Skip to content

Commit 5aade39

Browse files
committed
pythongh-103091: Add PyType_AssignVersionTag
1 parent ba65a06 commit 5aade39

File tree

6 files changed

+50
-1
lines changed

6 files changed

+50
-1
lines changed

Doc/c-api/type.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,15 @@ Type Objects
232232
233233
.. versionadded:: 3.11
234234
235+
.. c:function:: int PyType_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/object.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,15 @@ static inline int PyType_CheckExact(PyObject *op) {
861861
# define PyType_CheckExact(op) PyType_CheckExact(_PyObject_CAST(op))
862862
#endif
863863

864+
#if !defined(Py_LIMITED_API)
865+
/* Attempt to assign a version tag to the given type.
866+
*
867+
* Returns 1 if the type already had a valid version tag or a new one was
868+
* assigned, or 0 if a new tag could not be assigned.
869+
*/
870+
PyAPI_FUNC(int) PyType_AssignVersionTag(PyTypeObject *type);
871+
#endif
872+
864873
#ifdef __cplusplus
865874
}
866875
#endif

Lib/test/test_type_cache.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +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-
12+
type_assign_version = import_helper.import_module('_testcapi').type_assign_version
1313

1414
@support.cpython_only
1515
@unittest.skipIf(_clear_type_cache is None, "requires sys._clear_type_cache")
@@ -42,6 +42,19 @@ def test_tp_version_tag_unique(self):
4242
self.assertEqual(len(set(all_version_tags)), 30,
4343
msg=f"{all_version_tags} contains non-unique versions")
4444

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

4659
if __name__ == "__main__":
4760
support.run_unittest(TypeCacheTests)
Lines changed: 1 addition & 0 deletions
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.

Modules/_testcapimodule.c

Lines changed: 13 additions & 0 deletions
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 = PyType_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))
@@ -3499,6 +3511,7 @@ static PyMethodDef TestMethods[] = {
34993511
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
35003512
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
35013513
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
3514+
{"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyType_AssignVersionTag")},
35023515
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
35033516
{"frame_getlocals", frame_getlocals, METH_O, NULL},
35043517
{"frame_getglobals", frame_getglobals, METH_O, NULL},

Objects/typeobject.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,10 @@ assign_version_tag(PyTypeObject *type)
598598
return 1;
599599
}
600600

601+
int PyType_AssignVersionTag(PyTypeObject *type)
602+
{
603+
return assign_version_tag(type);
604+
}
601605

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

0 commit comments

Comments
 (0)