Skip to content

Commit

Permalink
gh-103091: Add PyUnstable_Type_AssignVersionTag (#103095)
Browse files Browse the repository at this point in the history
  • Loading branch information
swtaarrs authored Apr 24, 2023
1 parent dca27a6 commit b7f4811
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 0 deletions.
9 changes: 9 additions & 0 deletions Doc/c-api/type.rst
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ Type Objects
.. versionadded:: 3.11
.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
Attempt to assign a version tag to the given type.
Returns 1 if the type already had a valid version tag or a new one was
assigned, or 0 if a new tag could not be assigned.
.. versionadded:: 3.12
Creating Heap-Allocated Types
.............................
Expand Down
7 changes: 7 additions & 0 deletions Include/cpython/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,3 +564,10 @@ PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback);
PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id);
PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type);
PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type);

/* Attempt to assign a version tag to the given type.
*
* Returns 1 if the type already had a valid version tag or a new one was
* assigned, or 0 if a new tag could not be assigned.
*/
PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type);
14 changes: 14 additions & 0 deletions Lib/test/test_type_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

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


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

def test_type_assign_version(self):
class C:
x = 5

self.assertEqual(type_assign_version(C), 1)
c_ver = type_get_version(C)

C.x = 6
self.assertEqual(type_get_version(C), 0)
self.assertEqual(type_assign_version(C), 1)
self.assertNotEqual(type_get_version(C), 0)
self.assertNotEqual(type_get_version(C), c_ver)


if __name__ == "__main__":
support.run_unittest(TypeCacheTests)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a new C-API function to eagerly assign a version tag to a PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``.
13 changes: 13 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2733,6 +2733,18 @@ type_get_version(PyObject *self, PyObject *type)
}


static PyObject *
type_assign_version(PyObject *self, PyObject *type)
{
if (!PyType_Check(type)) {
PyErr_SetString(PyExc_TypeError, "argument must be a type");
return NULL;
}
int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type);
return PyLong_FromLong(res);
}


// Test PyThreadState C API
static PyObject *
test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args))
Expand Down Expand Up @@ -3530,6 +3542,7 @@ static PyMethodDef TestMethods[] = {
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
{"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"frame_getlocals", frame_getlocals, METH_O, NULL},
{"frame_getglobals", frame_getglobals, METH_O, NULL},
Expand Down
5 changes: 5 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,11 @@ assign_version_tag(PyTypeObject *type)
return 1;
}

int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
{
return assign_version_tag(type);
}


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

0 comments on commit b7f4811

Please sign in to comment.