Skip to content

Commit b7f4811

Browse files
authored
gh-103091: Add PyUnstable_Type_AssignVersionTag (#103095)
1 parent dca27a6 commit b7f4811

File tree

6 files changed

+49
-0
lines changed

6 files changed

+49
-0
lines changed

Doc/c-api/type.rst

+9
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ Type Objects
232232
233233
.. versionadded:: 3.11
234234
235+
.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
236+
237+
Attempt to assign a version tag to the given type.
238+
239+
Returns 1 if the type already had a valid version tag or a new one was
240+
assigned, or 0 if a new tag could not be assigned.
241+
242+
.. versionadded:: 3.12
243+
235244
236245
Creating Heap-Allocated Types
237246
.............................

Include/cpython/object.h

+7
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,10 @@ PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback);
564564
PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id);
565565
PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type);
566566
PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type);
567+
568+
/* Attempt to assign a version tag to the given type.
569+
*
570+
* Returns 1 if the type already had a valid version tag or a new one was
571+
* assigned, or 0 if a new tag could not be assigned.
572+
*/
573+
PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type);

Lib/test/test_type_cache.py

+14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
# Skip this test if the _testcapi module isn't available.
1111
type_get_version = import_helper.import_module('_testcapi').type_get_version
12+
type_assign_version = import_helper.import_module('_testcapi').type_assign_version
1213

1314

1415
@support.cpython_only
@@ -42,6 +43,19 @@ def test_tp_version_tag_unique(self):
4243
self.assertEqual(len(set(all_version_tags)), 30,
4344
msg=f"{all_version_tags} contains non-unique versions")
4445

46+
def test_type_assign_version(self):
47+
class C:
48+
x = 5
49+
50+
self.assertEqual(type_assign_version(C), 1)
51+
c_ver = type_get_version(C)
52+
53+
C.x = 6
54+
self.assertEqual(type_get_version(C), 0)
55+
self.assertEqual(type_assign_version(C), 1)
56+
self.assertNotEqual(type_get_version(C), 0)
57+
self.assertNotEqual(type_get_version(C), c_ver)
58+
4559

4660
if __name__ == "__main__":
4761
support.run_unittest(TypeCacheTests)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a new C-API function to eagerly assign a version tag to a PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``.

Modules/_testcapimodule.c

+13
Original file line numberDiff line numberDiff line change
@@ -2733,6 +2733,18 @@ type_get_version(PyObject *self, PyObject *type)
27332733
}
27342734

27352735

2736+
static PyObject *
2737+
type_assign_version(PyObject *self, PyObject *type)
2738+
{
2739+
if (!PyType_Check(type)) {
2740+
PyErr_SetString(PyExc_TypeError, "argument must be a type");
2741+
return NULL;
2742+
}
2743+
int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type);
2744+
return PyLong_FromLong(res);
2745+
}
2746+
2747+
27362748
// Test PyThreadState C API
27372749
static PyObject *
27382750
test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args))
@@ -3530,6 +3542,7 @@ static PyMethodDef TestMethods[] = {
35303542
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
35313543
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
35323544
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
3545+
{"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")},
35333546
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
35343547
{"frame_getlocals", frame_getlocals, METH_O, NULL},
35353548
{"frame_getglobals", frame_getglobals, METH_O, NULL},

Objects/typeobject.c

+5
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ assign_version_tag(PyTypeObject *type)
592592
return 1;
593593
}
594594

595+
int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
596+
{
597+
return assign_version_tag(type);
598+
}
599+
595600

596601
static PyMemberDef type_members[] = {
597602
{"__basicsize__", T_PYSSIZET, offsetof(PyTypeObject,tp_basicsize),READONLY},

0 commit comments

Comments
 (0)