From 2cc543c352322e870bbf74a6de20456dc1f7541a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:17:29 +0900 Subject: [PATCH 01/13] gh-134819: Add sys.set_object_tags and sys.get_object_tags --- Lib/test/test_sys.py | 24 ++++++++------- Python/clinic/sysmodule.c.h | 11 ++++++- Python/sysmodule.c | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 83745f3d0ba46e..8360b98ece8e5d 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -753,23 +753,25 @@ def test_43581(self): self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) def test_intern(self): - has_is_interned = (test.support.check_impl_detail(cpython=True) - or hasattr(sys, '_is_interned')) self.assertRaises(TypeError, sys.intern) self.assertRaises(TypeError, sys.intern, b'abc') + has_is_interned = (test.support.check_impl_detail(cpython=True) + or hasattr(sys, '_is_interned')) if has_is_interned: self.assertRaises(TypeError, sys._is_interned) self.assertRaises(TypeError, sys._is_interned, b'abc') + + def _is_interned(obj): + tags = sys.get_object_tags(obj) + return tags.get("interned", False) + s = "never interned before" + str(random.randrange(0, 10**9)) self.assertTrue(sys.intern(s) is s) - if has_is_interned: - self.assertIs(sys._is_interned(s), True) + self.assertIs(_is_interned(s), True) s2 = s.swapcase().swapcase() - if has_is_interned: - self.assertIs(sys._is_interned(s2), False) + self.assertIs(_is_interned(s2), False) self.assertTrue(sys.intern(s2) is s) - if has_is_interned: - self.assertIs(sys._is_interned(s2), False) + self.assertIs(_is_interned(s2), False) # Subclasses of string can't be interned, because they # provide too much opportunity for insane things to happen. @@ -781,8 +783,7 @@ def __hash__(self): return 123 self.assertRaises(TypeError, sys.intern, S("abc")) - if has_is_interned: - self.assertIs(sys._is_interned(S("abc")), False) + self.assertIs(_is_interned(S("abc")), False) @support.cpython_only @requires_subinterpreters @@ -847,7 +848,8 @@ def test_subinterp_intern_singleton(self): assert id(s) == {id(s)} t = sys.intern(s) ''')) - self.assertTrue(sys._is_interned(s)) + tags = sys.get_object_tags(s) + self.assertTrue(tags.get("interned", False)) def test_sys_flags(self): self.assertTrue(sys.flags) diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index a47e4d11b54441..1604554d6c94d0 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -405,6 +405,15 @@ sys__is_immortal(PyObject *module, PyObject *op) return return_value; } +PyDoc_STRVAR(sys_get_object_tags__doc__, +"get_object_tags($module, op, /)\n" +"--\n" +"\n" +"Return the tags of the given object."); + +#define SYS_GET_OBJECT_TAGS_METHODDEF \ + {"get_object_tags", (PyCFunction)sys_get_object_tags, METH_O, sys_get_object_tags__doc__}, + PyDoc_STRVAR(sys_settrace__doc__, "settrace($module, function, /)\n" "--\n" @@ -1948,4 +1957,4 @@ _jit_is_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=449d16326e69dcf6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9654d356bd94f235 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index e5ae841d195d4f..669ef9af359c96 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1052,6 +1052,65 @@ sys__is_immortal_impl(PyObject *module, PyObject *op) return PyUnstable_IsImmortal(op); } + +/*[clinic input] +sys.get_object_tags -> object + + op: object + / +Return the tags of the given object. +[clinic start generated code]*/ + +static PyObject * +sys_get_object_tags(PyObject *module, PyObject *op) +/*[clinic end generated code: output=a68da7f1805c9216 input=75993fb67096e2ff]*/ +{ + assert(op != NULL); + PyObject *dict = PyDict_New(); + if (dict == NULL) { + return NULL; + } + if (PyUnstable_IsImmortal(op)) { + if (PyDict_SetItemString(dict, "immortal", Py_True) < 0) { + Py_DECREF(dict); + return NULL; + } + } + else { + if (PyDict_SetItemString(dict, "immortal", Py_False) < 0) { + Py_DECREF(dict); + return NULL; + } + } + + if (PyUnicode_CHECK_INTERNED(op)) { + if (PyDict_SetItemString(dict, "interned", Py_True) < 0) { + Py_DECREF(dict); + return NULL; + } + } + else { + if (PyDict_SetItemString(dict, "interned", Py_False) < 0) { + Py_DECREF(dict); + return NULL; + } + } + + if (PyUnstable_Object_EnableDeferredRefcount(op)) { + if (PyDict_SetItemString(dict, "deferred_refcount", Py_True) < 0) { + Py_DECREF(dict); + return NULL; + } + } + else { + if (PyDict_SetItemString(dict, "deferred_refcount", Py_False) < 0) { + Py_DECREF(dict); + return NULL; + } + } + return dict; +} + /* * Cached interned string objects used for calling the profile and * trace functions. @@ -2796,6 +2855,7 @@ static PyMethodDef sys_methods[] = { SYS__IS_IMMORTAL_METHODDEF SYS_INTERN_METHODDEF SYS__IS_INTERNED_METHODDEF + SYS_GET_OBJECT_TAGS_METHODDEF SYS_IS_FINALIZING_METHODDEF SYS_MDEBUG_METHODDEF SYS_SETSWITCHINTERVAL_METHODDEF From 17ccccfd1f474622b2563bff7e1edd3a362148e3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:21:42 +0900 Subject: [PATCH 02/13] Add test --- Lib/test/test_sys.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 8360b98ece8e5d..6c4a26e43c31e6 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -785,6 +785,15 @@ def __hash__(self): self.assertRaises(TypeError, sys.intern, S("abc")) self.assertIs(_is_interned(S("abc")), False) + @support.cpython_only + def test_get_object_tags(self): + keys = ("immortal", "interned", "deferred_refcount") + s = "foobar" + tags = sys.get_object_tags(s) + self.assertEqual(len(tags), len(keys)) + for k in keys: + self.assertIn(k, tags) + @support.cpython_only @requires_subinterpreters def test_subinterp_intern_dynamically_allocated(self): From fb997ab1ce4653dd0a927ec3946b69cae1040fdd Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:51:50 +0900 Subject: [PATCH 03/13] Add set_object_tag --- Lib/test/test_sys.py | 14 +++++++ Python/clinic/sysmodule.c.h | 82 ++++++++++++++++++++++++++++++++++++- Python/sysmodule.c | 29 ++++++++++++- 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 6c4a26e43c31e6..b0f997521f9a38 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -794,6 +794,20 @@ def test_get_object_tags(self): for k in keys: self.assertIn(k, tags) + @support.cpython_only + def test_set_object_tags(self): + keys = ("immortal", "interned") + s = "should never interned before" + str(random.randrange(0, 10**9)) + origin_tags = sys.get_object_tags(s) + for k in keys: + sys.set_object_tag(s, k) + sys.set_object_tag(s, "unknown") + after_tags = sys.get_object_tags(s) + self.assertEqual(len(origin_tags), len(after_tags)) + for k in keys: + self.assertIn(k, after_tags) + self.assertTrue(after_tags[k]) + @support.cpython_only @requires_subinterpreters def test_subinterp_intern_dynamically_allocated(self): diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 1604554d6c94d0..c184e6be34caad 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -414,6 +414,86 @@ PyDoc_STRVAR(sys_get_object_tags__doc__, #define SYS_GET_OBJECT_TAGS_METHODDEF \ {"get_object_tags", (PyCFunction)sys_get_object_tags, METH_O, sys_get_object_tags__doc__}, +PyDoc_STRVAR(sys_set_object_tag__doc__, +"set_object_tag($module, /, object, tag, *, options=None)\n" +"--\n" +"\n" +"Set the tags of the given object."); + +#define SYS_SET_OBJECT_TAG_METHODDEF \ + {"set_object_tag", _PyCFunction_CAST(sys_set_object_tag), METH_FASTCALL|METH_KEYWORDS, sys_set_object_tag__doc__}, + +static PyObject * +sys_set_object_tag_impl(PyObject *module, PyObject *object, const char *tag, + PyObject *options); + +static PyObject * +sys_set_object_tag(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 + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(object), &_Py_ID(tag), &_Py_ID(options), }, + }; + #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", "tag", "options", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "set_object_tag", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; + PyObject *object; + const char *tag; + PyObject *options = Py_None; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + object = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("set_object_tag", "argument 'tag'", "str", args[1]); + goto exit; + } + Py_ssize_t tag_length; + tag = PyUnicode_AsUTF8AndSize(args[1], &tag_length); + if (tag == NULL) { + goto exit; + } + if (strlen(tag) != (size_t)tag_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!noptargs) { + goto skip_optional_kwonly; + } + options = args[2]; +skip_optional_kwonly: + return_value = sys_set_object_tag_impl(module, object, tag, options); + +exit: + return return_value; +} + PyDoc_STRVAR(sys_settrace__doc__, "settrace($module, function, /)\n" "--\n" @@ -1957,4 +2037,4 @@ _jit_is_active(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=9654d356bd94f235 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cf56a851495bb951 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 669ef9af359c96..e2be8c49c83659 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1083,7 +1083,7 @@ sys_get_object_tags(PyObject *module, PyObject *op) } } - if (PyUnicode_CHECK_INTERNED(op)) { + if (PyUnicode_Check(op) && PyUnicode_CHECK_INTERNED(op)) { if (PyDict_SetItemString(dict, "interned", Py_True) < 0) { Py_DECREF(dict); return NULL; @@ -1111,6 +1111,32 @@ sys_get_object_tags(PyObject *module, PyObject *op) return dict; } +/*[clinic input] +sys.set_object_tag -> object + + object: object + tag: str + * + options: object = None + +Set the tags of the given object. +[clinic start generated code]*/ + +static PyObject * +sys_set_object_tag_impl(PyObject *module, PyObject *object, const char *tag, + PyObject *options) +/*[clinic end generated code: output=b0fb5e9931feb4aa input=b64c9bd958c75f11]*/ +{ + assert(object != NULL); + if (strcmp(tag, "immortal") == 0) { + _Py_SetImmortal(object); + } + else if (strcmp(tag, "interned") == 0) { + _PyUnicode_InternMortal(_PyInterpreterState_GET(), &object); + } + Py_RETURN_NONE; +} + /* * Cached interned string objects used for calling the profile and * trace functions. @@ -2856,6 +2882,7 @@ static PyMethodDef sys_methods[] = { SYS_INTERN_METHODDEF SYS__IS_INTERNED_METHODDEF SYS_GET_OBJECT_TAGS_METHODDEF + SYS_SET_OBJECT_TAG_METHODDEF SYS_IS_FINALIZING_METHODDEF SYS_MDEBUG_METHODDEF SYS_SETSWITCHINTERVAL_METHODDEF From 5027d35300b72ae08725bdff89eed5394c1fa828 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:55:06 +0900 Subject: [PATCH 04/13] Add NEWS.d --- .../2025-06-03-21-55-03.gh-issue-134819.M9PZZc.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-55-03.gh-issue-134819.M9PZZc.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-55-03.gh-issue-134819.M9PZZc.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-55-03.gh-issue-134819.M9PZZc.rst new file mode 100644 index 00000000000000..89b2531a5110df --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-03-21-55-03.gh-issue-134819.M9PZZc.rst @@ -0,0 +1,2 @@ +Add :func:`sys.get_object_tags` and :func:`sys.set_object_tags` for handling +CPython object implementation detail. Patch By Donghee Na. From ba2c974b0e34cc5896d16f387fb2794c93f77cb4 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:56:23 +0900 Subject: [PATCH 05/13] nit --- Lib/test/test_sys.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index b0f997521f9a38..bb8eec53f127f3 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -800,6 +800,7 @@ def test_set_object_tags(self): s = "should never interned before" + str(random.randrange(0, 10**9)) origin_tags = sys.get_object_tags(s) for k in keys: + self.assertFalse(origin_tags[k]) sys.set_object_tag(s, k) sys.set_object_tag(s, "unknown") after_tags = sys.get_object_tags(s) From 658e7317e7b4a6dff9f989aea48d6b5a695589fd Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 21:59:56 +0900 Subject: [PATCH 06/13] nit --- Lib/test/test_sys.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index bb8eec53f127f3..6cb28514ed5b99 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -763,7 +763,7 @@ def test_intern(self): def _is_interned(obj): tags = sys.get_object_tags(obj) - return tags.get("interned", False) + return tags["interned"] s = "never interned before" + str(random.randrange(0, 10**9)) self.assertTrue(sys.intern(s) is s) @@ -873,7 +873,7 @@ def test_subinterp_intern_singleton(self): t = sys.intern(s) ''')) tags = sys.get_object_tags(s) - self.assertTrue(tags.get("interned", False)) + self.assertTrue(tags["interned"]) def test_sys_flags(self): self.assertTrue(sys.flags) From e725c7f182b95f6dc4747a67e4a5e4aa5192300a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:01:19 +0900 Subject: [PATCH 07/13] fix --- Lib/test/test_sys.py | 2 +- Python/sysmodule.c | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 6cb28514ed5b99..adb480b58493a1 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -787,7 +787,7 @@ def __hash__(self): @support.cpython_only def test_get_object_tags(self): - keys = ("immortal", "interned", "deferred_refcount") + keys = ("immortal", "interned") s = "foobar" tags = sys.get_object_tags(s) self.assertEqual(len(tags), len(keys)) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index e2be8c49c83659..fe36c0912150d2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1095,19 +1095,6 @@ sys_get_object_tags(PyObject *module, PyObject *op) return NULL; } } - - if (PyUnstable_Object_EnableDeferredRefcount(op)) { - if (PyDict_SetItemString(dict, "deferred_refcount", Py_True) < 0) { - Py_DECREF(dict); - return NULL; - } - } - else { - if (PyDict_SetItemString(dict, "deferred_refcount", Py_False) < 0) { - Py_DECREF(dict); - return NULL; - } - } return dict; } From 1cdc798b44f1ce072b67f90bada4acef7bd256b1 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:08:35 +0900 Subject: [PATCH 08/13] Update --- Lib/test/test_sys.py | 4 ++-- Python/sysmodule.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index adb480b58493a1..d6df6c3ced14a5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -787,7 +787,7 @@ def __hash__(self): @support.cpython_only def test_get_object_tags(self): - keys = ("immortal", "interned") + keys = ("immortal", "interned", "deferred_refcount") s = "foobar" tags = sys.get_object_tags(s) self.assertEqual(len(tags), len(keys)) @@ -796,7 +796,7 @@ def test_get_object_tags(self): @support.cpython_only def test_set_object_tags(self): - keys = ("immortal", "interned") + keys = ("immortal", "interned", "deferred_refcount") s = "should never interned before" + str(random.randrange(0, 10**9)) origin_tags = sys.get_object_tags(s) for k in keys: diff --git a/Python/sysmodule.c b/Python/sysmodule.c index fe36c0912150d2..38f997a0f00401 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -18,6 +18,7 @@ Data members: #include "pycore_audit.h" // _Py_AuditHookEntry #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer() +#include "pycore_object_deferred.h" // _PyObject_HasDeferredRefcount #include "pycore_frame.h" // _PyInterpreterFrame #include "pycore_import.h" // _PyImport_SetDLOpenFlags() #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() @@ -1095,6 +1096,19 @@ sys_get_object_tags(PyObject *module, PyObject *op) return NULL; } } + + if (_PyObject_HasDeferredRefcount(op)) { + if (PyDict_SetItemString(dict, "deferred_refcount", Py_True) < 0) { + Py_DECREF(dict); + return NULL; + } + } + else { + if (PyDict_SetItemString(dict, "deferred_refcount", Py_False) < 0) { + Py_DECREF(dict); + return NULL; + } + } return dict; } @@ -1121,6 +1135,9 @@ sys_set_object_tag_impl(PyObject *module, PyObject *object, const char *tag, else if (strcmp(tag, "interned") == 0) { _PyUnicode_InternMortal(_PyInterpreterState_GET(), &object); } + else if(strcmp(tag, "deferred_refcount") == 0) { + PyUnstable_Object_EnableDeferredRefcount(object); + } Py_RETURN_NONE; } From dbc30b77ed718e50e3446f7ff4576a42b70d0a8a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:13:25 +0900 Subject: [PATCH 09/13] Address code review --- Python/sysmodule.c | 45 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 38f997a0f00401..3608b3d2fbbcbc 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1071,44 +1071,23 @@ sys_get_object_tags(PyObject *module, PyObject *op) if (dict == NULL) { return NULL; } - if (PyUnstable_IsImmortal(op)) { - if (PyDict_SetItemString(dict, "immortal", Py_True) < 0) { - Py_DECREF(dict); - return NULL; - } - } - else { - if (PyDict_SetItemString(dict, "immortal", Py_False) < 0) { - Py_DECREF(dict); - return NULL; - } - } - if (PyUnicode_Check(op) && PyUnicode_CHECK_INTERNED(op)) { - if (PyDict_SetItemString(dict, "interned", Py_True) < 0) { - Py_DECREF(dict); - return NULL; - } - } - else { - if (PyDict_SetItemString(dict, "interned", Py_False) < 0) { - Py_DECREF(dict); - return NULL; - } + if (PyDict_SetItemString(dict, "immortal", PyBool_FromLong(PyUnstable_IsImmortal(op))) < 0) { + Py_DECREF(dict); + return NULL; } - if (_PyObject_HasDeferredRefcount(op)) { - if (PyDict_SetItemString(dict, "deferred_refcount", Py_True) < 0) { - Py_DECREF(dict); - return NULL; - } + + if (PyDict_SetItemString(dict, "interned", PyBool_FromLong((PyUnicode_Check(op) && PyUnicode_CHECK_INTERNED(op)))) < 0) { + Py_DECREF(dict); + return NULL; } - else { - if (PyDict_SetItemString(dict, "deferred_refcount", Py_False) < 0) { - Py_DECREF(dict); - return NULL; - } + + if (PyDict_SetItemString(dict, "deferred_refcount", PyBool_FromLong(_PyObject_HasDeferredRefcount(op))) < 0) { + Py_DECREF(dict); + return NULL; } + return dict; } From e7d06b6725c8856faec66cb580a29a04e71f7137 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:14:38 +0900 Subject: [PATCH 10/13] nit --- Python/sysmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 3608b3d2fbbcbc..afcd2939ed709d 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1077,7 +1077,6 @@ sys_get_object_tags(PyObject *module, PyObject *op) return NULL; } - if (PyDict_SetItemString(dict, "interned", PyBool_FromLong((PyUnicode_Check(op) && PyUnicode_CHECK_INTERNED(op)))) < 0) { Py_DECREF(dict); return NULL; From ff34816b5d47056a79276232529c8f1c1600527a Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:27:57 +0900 Subject: [PATCH 11/13] Address code review --- Python/sysmodule.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index afcd2939ed709d..5eacf5c89c9fca 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1107,10 +1107,7 @@ sys_set_object_tag_impl(PyObject *module, PyObject *object, const char *tag, /*[clinic end generated code: output=b0fb5e9931feb4aa input=b64c9bd958c75f11]*/ { assert(object != NULL); - if (strcmp(tag, "immortal") == 0) { - _Py_SetImmortal(object); - } - else if (strcmp(tag, "interned") == 0) { + if (strcmp(tag, "interned") == 0) { _PyUnicode_InternMortal(_PyInterpreterState_GET(), &object); } else if(strcmp(tag, "deferred_refcount") == 0) { From 4e1946ffcd93eed70d6ac635bdfaf30d71b2f761 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:30:03 +0900 Subject: [PATCH 12/13] nit --- Python/sysmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 5eacf5c89c9fca..f5933ea1bdac73 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1108,6 +1108,7 @@ sys_set_object_tag_impl(PyObject *module, PyObject *object, const char *tag, { assert(object != NULL); if (strcmp(tag, "interned") == 0) { + Py_INCREF(object); _PyUnicode_InternMortal(_PyInterpreterState_GET(), &object); } else if(strcmp(tag, "deferred_refcount") == 0) { From 2a0eb8e32605b7c50d571415c3dda2c8133e6101 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 3 Jun 2025 22:44:27 +0900 Subject: [PATCH 13/13] Update --- Lib/test/test_sys.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index d6df6c3ced14a5..b932c860b9f25e 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -805,9 +805,6 @@ def test_set_object_tags(self): sys.set_object_tag(s, "unknown") after_tags = sys.get_object_tags(s) self.assertEqual(len(origin_tags), len(after_tags)) - for k in keys: - self.assertIn(k, after_tags) - self.assertTrue(after_tags[k]) @support.cpython_only @requires_subinterpreters