Skip to content

Commit 2cc543c

Browse files
committed
gh-134819: Add sys.set_object_tags and sys.get_object_tags
1 parent ec12559 commit 2cc543c

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

Lib/test/test_sys.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -753,23 +753,25 @@ def test_43581(self):
753753
self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding)
754754

755755
def test_intern(self):
756-
has_is_interned = (test.support.check_impl_detail(cpython=True)
757-
or hasattr(sys, '_is_interned'))
758756
self.assertRaises(TypeError, sys.intern)
759757
self.assertRaises(TypeError, sys.intern, b'abc')
758+
has_is_interned = (test.support.check_impl_detail(cpython=True)
759+
or hasattr(sys, '_is_interned'))
760760
if has_is_interned:
761761
self.assertRaises(TypeError, sys._is_interned)
762762
self.assertRaises(TypeError, sys._is_interned, b'abc')
763+
764+
def _is_interned(obj):
765+
tags = sys.get_object_tags(obj)
766+
return tags.get("interned", False)
767+
763768
s = "never interned before" + str(random.randrange(0, 10**9))
764769
self.assertTrue(sys.intern(s) is s)
765-
if has_is_interned:
766-
self.assertIs(sys._is_interned(s), True)
770+
self.assertIs(_is_interned(s), True)
767771
s2 = s.swapcase().swapcase()
768-
if has_is_interned:
769-
self.assertIs(sys._is_interned(s2), False)
772+
self.assertIs(_is_interned(s2), False)
770773
self.assertTrue(sys.intern(s2) is s)
771-
if has_is_interned:
772-
self.assertIs(sys._is_interned(s2), False)
774+
self.assertIs(_is_interned(s2), False)
773775

774776
# Subclasses of string can't be interned, because they
775777
# provide too much opportunity for insane things to happen.
@@ -781,8 +783,7 @@ def __hash__(self):
781783
return 123
782784

783785
self.assertRaises(TypeError, sys.intern, S("abc"))
784-
if has_is_interned:
785-
self.assertIs(sys._is_interned(S("abc")), False)
786+
self.assertIs(_is_interned(S("abc")), False)
786787

787788
@support.cpython_only
788789
@requires_subinterpreters
@@ -847,7 +848,8 @@ def test_subinterp_intern_singleton(self):
847848
assert id(s) == {id(s)}
848849
t = sys.intern(s)
849850
'''))
850-
self.assertTrue(sys._is_interned(s))
851+
tags = sys.get_object_tags(s)
852+
self.assertTrue(tags.get("interned", False))
851853

852854
def test_sys_flags(self):
853855
self.assertTrue(sys.flags)

Python/clinic/sysmodule.c.h

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/sysmodule.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,65 @@ sys__is_immortal_impl(PyObject *module, PyObject *op)
10521052
return PyUnstable_IsImmortal(op);
10531053
}
10541054

1055+
1056+
/*[clinic input]
1057+
sys.get_object_tags -> object
1058+
1059+
op: object
1060+
/
1061+
Return the tags of the given object.
1062+
[clinic start generated code]*/
1063+
1064+
static PyObject *
1065+
sys_get_object_tags(PyObject *module, PyObject *op)
1066+
/*[clinic end generated code: output=a68da7f1805c9216 input=75993fb67096e2ff]*/
1067+
{
1068+
assert(op != NULL);
1069+
PyObject *dict = PyDict_New();
1070+
if (dict == NULL) {
1071+
return NULL;
1072+
}
1073+
if (PyUnstable_IsImmortal(op)) {
1074+
if (PyDict_SetItemString(dict, "immortal", Py_True) < 0) {
1075+
Py_DECREF(dict);
1076+
return NULL;
1077+
}
1078+
}
1079+
else {
1080+
if (PyDict_SetItemString(dict, "immortal", Py_False) < 0) {
1081+
Py_DECREF(dict);
1082+
return NULL;
1083+
}
1084+
}
1085+
1086+
if (PyUnicode_CHECK_INTERNED(op)) {
1087+
if (PyDict_SetItemString(dict, "interned", Py_True) < 0) {
1088+
Py_DECREF(dict);
1089+
return NULL;
1090+
}
1091+
}
1092+
else {
1093+
if (PyDict_SetItemString(dict, "interned", Py_False) < 0) {
1094+
Py_DECREF(dict);
1095+
return NULL;
1096+
}
1097+
}
1098+
1099+
if (PyUnstable_Object_EnableDeferredRefcount(op)) {
1100+
if (PyDict_SetItemString(dict, "deferred_refcount", Py_True) < 0) {
1101+
Py_DECREF(dict);
1102+
return NULL;
1103+
}
1104+
}
1105+
else {
1106+
if (PyDict_SetItemString(dict, "deferred_refcount", Py_False) < 0) {
1107+
Py_DECREF(dict);
1108+
return NULL;
1109+
}
1110+
}
1111+
return dict;
1112+
}
1113+
10551114
/*
10561115
* Cached interned string objects used for calling the profile and
10571116
* trace functions.
@@ -2796,6 +2855,7 @@ static PyMethodDef sys_methods[] = {
27962855
SYS__IS_IMMORTAL_METHODDEF
27972856
SYS_INTERN_METHODDEF
27982857
SYS__IS_INTERNED_METHODDEF
2858+
SYS_GET_OBJECT_TAGS_METHODDEF
27992859
SYS_IS_FINALIZING_METHODDEF
28002860
SYS_MDEBUG_METHODDEF
28012861
SYS_SETSWITCHINTERVAL_METHODDEF

0 commit comments

Comments
 (0)