From de0d9763682b414c028b3443aeab60fe2daec645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?tonghuaroot=20=28=E7=AB=A5=E8=AF=9D=29?= Date: Mon, 21 Sep 2026 05:04:01 +0800 Subject: [PATCH 1/2] gh-153319: Read turtledemo scripts with the source file's own encoding (#153321) The demo viewer read each script with open() and no encoding argument, i.e. the locale default encoding. That emits an EncodingWarning under -X warn_default_encoding and can mis-decode a script on a non-UTF-8 locale. Read the source with tokenize.open() instead, which decodes using the encoding detected from the file (its coding cookie, else UTF-8), matching how Python read the module when it was imported just above. * gh-153319: Read turtledemo scripts as UTF-8 Per review, open the demo scripts with encoding='utf-8' instead of tokenize.open(); the scripts are UTF-8. --------- Co-authored-by: Serhiy Storchaka Co-authored-by: Terry Jan Reedy --- Lib/turtledemo/__main__.py | 2 +- .../next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst diff --git a/Lib/turtledemo/__main__.py b/Lib/turtledemo/__main__.py index 7c2d753f4c3111..cffc08f59b99d2 100644 --- a/Lib/turtledemo/__main__.py +++ b/Lib/turtledemo/__main__.py @@ -333,7 +333,7 @@ def loadfile(self, filename): modname = 'turtledemo.' + filename __import__(modname) self.module = sys.modules[modname] - with open(self.module.__file__, 'r') as f: + with open(self.module.__file__, encoding='utf-8') as f: chars = f.read() self.text.delete("1.0", "end") self.text.insert("1.0", chars) diff --git a/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst b/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst new file mode 100644 index 00000000000000..95f8e2fb7f4f8b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-08-19-40-00.gh-issue-153319.Qk7bE2.rst @@ -0,0 +1,2 @@ +The :mod:`turtledemo` viewer now reads each demo script as UTF-8 instead of +the locale encoding. From 41d09220bda74cda6897a4e807d7af0edaff1fd8 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 20 Sep 2026 18:08:23 -0400 Subject: [PATCH 2/2] gh-157840: Special-case member descriptors when using `hasattr` (GH-157866) --- .../2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst | 2 ++ Objects/object.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst new file mode 100644 index 00000000000000..c2212267ce6fa4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-20-12-11-01.gh-issue-157840.EAo1Kp.rst @@ -0,0 +1,2 @@ +Speed up calls to :func:`hasattr` and three-argument :func:`getattr` for +unassigned attributes in an object's :attr:`~object.__slots__` by roughly 6x. diff --git a/Objects/object.c b/Objects/object.c index 971ac1b7a68669..c7aeba0cee22c6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1924,6 +1924,19 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, if (descr != NULL) { f = Py_TYPE(descr)->tp_descr_get; if (f != NULL && PyDescr_IsData(descr)) { + // gh-157840: We special-case member descriptors here to avoid + // allocating an extra AttributeError + if (suppress && Py_IS_TYPE(descr, &PyMemberDescr_Type)) { + PyMemberDef *member = ((PyMemberDescrObject *)descr)->d_member; + if (member->type == Py_T_OBJECT_EX + && !(member->flags & Py_AUDIT_READ) + && PyObject_TypeCheck(obj, PyDescr_TYPE(descr))) { + PyObject **addr = _PyMember_GetOffset(obj, member); + if (FT_ATOMIC_LOAD_PTR(*addr) == NULL) { + goto done; + } + } + } res = f(descr, obj, (PyObject *)Py_TYPE(obj)); if (res == NULL && suppress && PyErr_ExceptionMatches(PyExc_AttributeError)) {