Move PyType C API tests to a new file.
Move following tests from test_capi.test_misc to test_capi.test_type:
* BuiltinStaticTypesTests
* test_get_type_name()
* test_get_base_by_token()
del d.extra
self.assertIsNone(d.extra)
- def test_get_type_name(self):
- class MyType:
- pass
-
- from _testcapi import (
- get_type_name, get_type_qualname,
- get_type_fullyqualname, get_type_module_name)
-
- from collections import OrderedDict
- ht = _testcapi.get_heaptype_for_name()
- for cls, fullname, modname, qualname, name in (
- (int,
- 'int',
- 'builtins',
- 'int',
- 'int'),
- (OrderedDict,
- 'collections.OrderedDict',
- 'collections',
- 'OrderedDict',
- 'OrderedDict'),
- (ht,
- '_testcapi.HeapTypeNameType',
- '_testcapi',
- 'HeapTypeNameType',
- 'HeapTypeNameType'),
- (MyType,
- f'{__name__}.CAPITest.test_get_type_name.<locals>.MyType',
- __name__,
- 'CAPITest.test_get_type_name.<locals>.MyType',
- 'MyType'),
- ):
- with self.subTest(cls=repr(cls)):
- self.assertEqual(get_type_fullyqualname(cls), fullname)
- self.assertEqual(get_type_module_name(cls), modname)
- self.assertEqual(get_type_qualname(cls), qualname)
- self.assertEqual(get_type_name(cls), name)
-
- # override __module__
- ht.__module__ = 'test_module'
- self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType')
- self.assertEqual(get_type_module_name(ht), 'test_module')
- self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType')
- self.assertEqual(get_type_name(ht), 'HeapTypeNameType')
-
- # override __name__ and __qualname__
- MyType.__name__ = 'my_name'
- MyType.__qualname__ = 'my_qualname'
- self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname')
- self.assertEqual(get_type_module_name(MyType), __name__)
- self.assertEqual(get_type_qualname(MyType), 'my_qualname')
- self.assertEqual(get_type_name(MyType), 'my_name')
-
- # override also __module__
- MyType.__module__ = 'my_module'
- self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname')
- self.assertEqual(get_type_module_name(MyType), 'my_module')
- self.assertEqual(get_type_qualname(MyType), 'my_qualname')
- self.assertEqual(get_type_name(MyType), 'my_name')
-
- # PyType_GetFullyQualifiedName() ignores the module if it's "builtins"
- # or "__main__" of it is not a string
- MyType.__module__ = 'builtins'
- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
- MyType.__module__ = '__main__'
- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
- MyType.__module__ = 123
- self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
-
- def test_get_base_by_token(self):
- def get_base_by_token(src, key, comparable=True):
- def run(use_mro):
- find_first = _testcapi.pytype_getbasebytoken
- ret1, result = find_first(src, key, use_mro, True)
- ret2, no_result = find_first(src, key, use_mro, False)
- self.assertIn(ret1, (0, 1))
- self.assertEqual(ret1, result is not None)
- self.assertEqual(ret1, ret2)
- self.assertIsNone(no_result)
- return result
-
- found_in_mro = run(True)
- found_in_bases = run(False)
- if comparable:
- self.assertIs(found_in_mro, found_in_bases)
- return found_in_mro
- return found_in_mro, found_in_bases
-
- create_type = _testcapi.create_type_with_token
- get_token = _testcapi.get_tp_token
-
- Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC
- self.assertEqual(Py_TP_USE_SPEC, 0)
-
- A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC)
- self.assertTrue(get_token(A1) != Py_TP_USE_SPEC)
-
- B1 = create_type('_testcapi.B1', id(self))
- self.assertTrue(get_token(B1) == id(self))
-
- tokenA1 = get_token(A1)
- # find A1 from A1
- found = get_base_by_token(A1, tokenA1)
- self.assertIs(found, A1)
-
- # no token in static types
- STATIC = type(1)
- self.assertEqual(get_token(STATIC), 0)
- found = get_base_by_token(STATIC, tokenA1)
- self.assertIs(found, None)
-
- # no token in pure subtypes
- class A2(A1): pass
- self.assertEqual(get_token(A2), 0)
- # find A1
- class Z(STATIC, B1, A2): pass
- found = get_base_by_token(Z, tokenA1)
- self.assertIs(found, A1)
-
- # searching for NULL token is an error
- with self.assertRaises(SystemError):
- get_base_by_token(Z, 0)
- with self.assertRaises(SystemError):
- get_base_by_token(STATIC, 0)
-
- # share the token with A1
- C1 = create_type('_testcapi.C1', tokenA1)
- self.assertTrue(get_token(C1) == tokenA1)
-
- # find C1 first by shared token
- class Z(C1, A2): pass
- found = get_base_by_token(Z, tokenA1)
- self.assertIs(found, C1)
- # B1 not found
- found = get_base_by_token(Z, get_token(B1))
- self.assertIs(found, None)
-
- with self.assertRaises(TypeError):
- _testcapi.pytype_getbasebytoken(
- 'not a type', id(self), True, False)
-
def test_gen_get_code(self):
def genf(): yield
gen = genf()
0, get_refcount(interpid))
-class BuiltinStaticTypesTests(unittest.TestCase):
-
- TYPES = [
- object,
- type,
- int,
- str,
- dict,
- type(None),
- bool,
- BaseException,
- Exception,
- Warning,
- DeprecationWarning, # Warning subclass
- ]
-
- def test_tp_bases_is_set(self):
- # PyTypeObject.tp_bases is documented as public API.
- # See https://github.com/python/cpython/issues/105020.
- for typeobj in self.TYPES:
- with self.subTest(typeobj):
- bases = _testcapi.type_get_tp_bases(typeobj)
- self.assertIsNot(bases, None)
-
- def test_tp_mro_is_set(self):
- # PyTypeObject.tp_bases is documented as public API.
- # See https://github.com/python/cpython/issues/105020.
- for typeobj in self.TYPES:
- with self.subTest(typeobj):
- mro = _testcapi.type_get_tp_mro(typeobj)
- self.assertIsNot(mro, None)
-
-
class TestStaticTypes(unittest.TestCase):
_has_run = False
_testcapi = import_helper.import_module('_testcapi')
+class BuiltinStaticTypesTests(unittest.TestCase):
+
+ TYPES = [
+ object,
+ type,
+ int,
+ str,
+ dict,
+ type(None),
+ bool,
+ BaseException,
+ Exception,
+ Warning,
+ DeprecationWarning, # Warning subclass
+ ]
+
+ def test_tp_bases_is_set(self):
+ # PyTypeObject.tp_bases is documented as public API.
+ # See https://github.com/python/cpython/issues/105020.
+ for typeobj in self.TYPES:
+ with self.subTest(typeobj):
+ bases = _testcapi.type_get_tp_bases(typeobj)
+ self.assertIsNot(bases, None)
+
+ def test_tp_mro_is_set(self):
+ # PyTypeObject.tp_bases is documented as public API.
+ # See https://github.com/python/cpython/issues/105020.
+ for typeobj in self.TYPES:
+ with self.subTest(typeobj):
+ mro = _testcapi.type_get_tp_mro(typeobj)
+ self.assertIsNot(mro, None)
+
+
class TypeTests(unittest.TestCase):
+ def test_get_type_name(self):
+ class MyType:
+ pass
+
+ from _testcapi import (
+ get_type_name, get_type_qualname,
+ get_type_fullyqualname, get_type_module_name)
+
+ from collections import OrderedDict
+ ht = _testcapi.get_heaptype_for_name()
+ for cls, fullname, modname, qualname, name in (
+ (int,
+ 'int',
+ 'builtins',
+ 'int',
+ 'int'),
+ (OrderedDict,
+ 'collections.OrderedDict',
+ 'collections',
+ 'OrderedDict',
+ 'OrderedDict'),
+ (ht,
+ '_testcapi.HeapTypeNameType',
+ '_testcapi',
+ 'HeapTypeNameType',
+ 'HeapTypeNameType'),
+ (MyType,
+ f'{__name__}.TypeTests.test_get_type_name.<locals>.MyType',
+ __name__,
+ 'TypeTests.test_get_type_name.<locals>.MyType',
+ 'MyType'),
+ ):
+ with self.subTest(cls=repr(cls)):
+ self.assertEqual(get_type_fullyqualname(cls), fullname)
+ self.assertEqual(get_type_module_name(cls), modname)
+ self.assertEqual(get_type_qualname(cls), qualname)
+ self.assertEqual(get_type_name(cls), name)
+
+ # override __module__
+ ht.__module__ = 'test_module'
+ self.assertEqual(get_type_fullyqualname(ht), 'test_module.HeapTypeNameType')
+ self.assertEqual(get_type_module_name(ht), 'test_module')
+ self.assertEqual(get_type_qualname(ht), 'HeapTypeNameType')
+ self.assertEqual(get_type_name(ht), 'HeapTypeNameType')
+
+ # override __name__ and __qualname__
+ MyType.__name__ = 'my_name'
+ MyType.__qualname__ = 'my_qualname'
+ self.assertEqual(get_type_fullyqualname(MyType), f'{__name__}.my_qualname')
+ self.assertEqual(get_type_module_name(MyType), __name__)
+ self.assertEqual(get_type_qualname(MyType), 'my_qualname')
+ self.assertEqual(get_type_name(MyType), 'my_name')
+
+ # override also __module__
+ MyType.__module__ = 'my_module'
+ self.assertEqual(get_type_fullyqualname(MyType), 'my_module.my_qualname')
+ self.assertEqual(get_type_module_name(MyType), 'my_module')
+ self.assertEqual(get_type_qualname(MyType), 'my_qualname')
+ self.assertEqual(get_type_name(MyType), 'my_name')
+
+ # PyType_GetFullyQualifiedName() ignores the module if it's "builtins"
+ # or "__main__" of it is not a string
+ MyType.__module__ = 'builtins'
+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
+ MyType.__module__ = '__main__'
+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
+ MyType.__module__ = 123
+ self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')
+
+ def test_get_base_by_token(self):
+ def get_base_by_token(src, key, comparable=True):
+ def run(use_mro):
+ find_first = _testcapi.pytype_getbasebytoken
+ ret1, result = find_first(src, key, use_mro, True)
+ ret2, no_result = find_first(src, key, use_mro, False)
+ self.assertIn(ret1, (0, 1))
+ self.assertEqual(ret1, result is not None)
+ self.assertEqual(ret1, ret2)
+ self.assertIsNone(no_result)
+ return result
+
+ found_in_mro = run(True)
+ found_in_bases = run(False)
+ if comparable:
+ self.assertIs(found_in_mro, found_in_bases)
+ return found_in_mro
+ return found_in_mro, found_in_bases
+
+ create_type = _testcapi.create_type_with_token
+ get_token = _testcapi.get_tp_token
+
+ Py_TP_USE_SPEC = _testcapi.Py_TP_USE_SPEC
+ self.assertEqual(Py_TP_USE_SPEC, 0)
+
+ A1 = create_type('_testcapi.A1', Py_TP_USE_SPEC)
+ self.assertTrue(get_token(A1) != Py_TP_USE_SPEC)
+
+ B1 = create_type('_testcapi.B1', id(self))
+ self.assertTrue(get_token(B1) == id(self))
+
+ tokenA1 = get_token(A1)
+ # find A1 from A1
+ found = get_base_by_token(A1, tokenA1)
+ self.assertIs(found, A1)
+
+ # no token in static types
+ STATIC = type(1)
+ self.assertEqual(get_token(STATIC), 0)
+ found = get_base_by_token(STATIC, tokenA1)
+ self.assertIs(found, None)
+
+ # no token in pure subtypes
+ class A2(A1): pass
+ self.assertEqual(get_token(A2), 0)
+ # find A1
+ class Z(STATIC, B1, A2): pass
+ found = get_base_by_token(Z, tokenA1)
+ self.assertIs(found, A1)
+
+ # searching for NULL token is an error
+ with self.assertRaises(SystemError):
+ get_base_by_token(Z, 0)
+ with self.assertRaises(SystemError):
+ get_base_by_token(STATIC, 0)
+
+ # share the token with A1
+ C1 = create_type('_testcapi.C1', tokenA1)
+ self.assertTrue(get_token(C1) == tokenA1)
+
+ # find C1 first by shared token
+ class Z(C1, A2): pass
+ found = get_base_by_token(Z, tokenA1)
+ self.assertIs(found, C1)
+ # B1 not found
+ found = get_base_by_token(Z, get_token(B1))
+ self.assertIs(found, None)
+
+ with self.assertRaises(TypeError):
+ _testcapi.pytype_getbasebytoken(
+ 'not a type', id(self), True, False)
+
def test_freeze(self):
# test PyType_Freeze()
type_freeze = _testcapi.type_freeze
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
-@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c
+@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/run.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/gc.c _testcapi/hash.c _testcapi/time.c _testcapi/bytes.c _testcapi/object.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/codec.c _testlimitedcapi/complex.c _testlimitedcapi/dict.c _testlimitedcapi/eval.c _testlimitedcapi/float.c _testlimitedcapi/heaptype_relative.c _testlimitedcapi/import.c _testlimitedcapi/list.c _testlimitedcapi/long.c _testlimitedcapi/object.c _testlimitedcapi/pyos.c _testlimitedcapi/set.c _testlimitedcapi/sys.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c
int _PyTestCapi_Init_Config(PyObject *mod);
int _PyTestCapi_Init_Import(PyObject *mod);
int _PyTestCapi_Init_Frame(PyObject *mod);
+int _PyTestCapi_Init_Type(PyObject *mod);
#endif // Py_TESTCAPI_PARTS_H
--- /dev/null
+#include "parts.h"
+#include "util.h"
+
+
+static PyType_Slot HeapTypeNameType_slots[] = {
+ {0},
+};
+
+static PyType_Spec HeapTypeNameType_Spec = {
+ .name = "_testcapi.HeapTypeNameType",
+ .basicsize = sizeof(PyObject),
+ .flags = Py_TPFLAGS_DEFAULT,
+ .slots = HeapTypeNameType_slots,
+};
+
+static PyObject *
+get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ return PyType_FromSpec(&HeapTypeNameType_Spec);
+}
+
+
+static PyObject *
+get_type_name(PyObject *self, PyObject *type)
+{
+ assert(PyType_Check(type));
+ return PyType_GetName((PyTypeObject *)type);
+}
+
+
+static PyObject *
+get_type_qualname(PyObject *self, PyObject *type)
+{
+ assert(PyType_Check(type));
+ return PyType_GetQualName((PyTypeObject *)type);
+}
+
+
+static PyObject *
+get_type_fullyqualname(PyObject *self, PyObject *type)
+{
+ assert(PyType_Check(type));
+ return PyType_GetFullyQualifiedName((PyTypeObject *)type);
+}
+
+
+static PyObject *
+get_type_module_name(PyObject *self, PyObject *type)
+{
+ assert(PyType_Check(type));
+ return PyType_GetModuleName((PyTypeObject *)type);
+}
+
+
+static PyObject *
+test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ /* Test for PyType_GetDict */
+
+ // Assert ints have a `to_bytes` method
+ PyObject *long_dict = PyType_GetDict(&PyLong_Type);
+ assert(long_dict);
+ assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref
+ Py_DECREF(long_dict);
+
+ // Make a new type, add an attribute to it and assert it's there
+ PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec);
+ assert(HeapTypeNameType);
+ assert(PyObject_SetAttrString(
+ HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0);
+ PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType);
+ assert(type_dict);
+ assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref
+ Py_DECREF(HeapTypeNameType);
+ Py_DECREF(type_dict);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *
+test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new);
+ if (PyLong_Type.tp_new != tp_new) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long");
+ return NULL;
+ }
+
+ reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr);
+ if (PyLong_Type.tp_repr != tp_repr) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long");
+ return NULL;
+ }
+
+ ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call);
+ if (tp_call != NULL) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long");
+ return NULL;
+ }
+
+ binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add);
+ if (PyLong_Type.tp_as_number->nb_add != nb_add) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long");
+ return NULL;
+ }
+
+ lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length);
+ if (mp_length != NULL) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long");
+ return NULL;
+ }
+
+ void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1);
+ if (over_value != NULL) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long");
+ return NULL;
+ }
+
+ tp_new = PyType_GetSlot(&PyLong_Type, 0);
+ if (tp_new != NULL) {
+ PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long");
+ return NULL;
+ }
+ if (PyErr_ExceptionMatches(PyExc_SystemError)) {
+ // This is the right exception
+ PyErr_Clear();
+ }
+ else {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+// Get type->tp_version_tag
+static PyObject *
+type_get_version(PyObject *self, PyObject *type)
+{
+ if (!PyType_Check(type)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyObject *res = PyLong_FromUnsignedLong(
+ ((PyTypeObject *)type)->tp_version_tag);
+ if (res == NULL) {
+ assert(PyErr_Occurred());
+ return NULL;
+ }
+ return res;
+}
+
+static PyObject *
+type_modified(PyObject *self, PyObject *arg)
+{
+ if (!PyType_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyTypeObject *type = (PyTypeObject*)arg;
+
+ PyType_Modified(type);
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *
+type_assign_version(PyObject *self, PyObject *arg)
+{
+ if (!PyType_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyTypeObject *type = (PyTypeObject*)arg;
+
+ int res = PyUnstable_Type_AssignVersionTag(type);
+ return PyLong_FromLong(res);
+}
+
+
+static PyObject *
+type_get_tp_bases(PyObject *self, PyObject *arg)
+{
+ if (!PyType_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyTypeObject *type = (PyTypeObject*)arg;
+
+ PyObject *bases = type->tp_bases;
+ if (bases == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(bases);
+}
+
+static PyObject *
+type_get_tp_mro(PyObject *self, PyObject *arg)
+{
+ if (!PyType_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyTypeObject *type = (PyTypeObject*)arg;
+
+ PyObject *mro = ((PyTypeObject *)type)->tp_mro;
+ if (mro == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(mro);
+}
+
+
+static PyObject *
+type_freeze(PyObject *module, PyObject *arg)
+{
+ if (!PyType_Check(arg)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ PyTypeObject *type = (PyTypeObject*)arg;
+
+ if (PyType_Freeze(type) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef test_methods[] = {
+ {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS},
+ {"get_type_name", get_type_name, METH_O},
+ {"get_type_qualname", get_type_qualname, METH_O},
+ {"get_type_fullyqualname", get_type_fullyqualname, METH_O},
+ {"get_type_module_name", get_type_module_name, METH_O},
+ {"test_get_type_dict", test_get_type_dict, METH_NOARGS},
+ {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS},
+ {"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
+ {"type_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")},
+ {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")},
+ {"type_get_tp_bases", type_get_tp_bases, METH_O},
+ {"type_get_tp_mro", type_get_tp_mro, METH_O},
+ {"type_freeze", type_freeze, METH_O},
+ {NULL},
+};
+
+int
+_PyTestCapi_Init_Type(PyObject *m)
+{
+ return PyModule_AddFunctions(m, test_methods);
+}
}
-static PyObject *
-test_get_statictype_slots(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
- newfunc tp_new = PyType_GetSlot(&PyLong_Type, Py_tp_new);
- if (PyLong_Type.tp_new != tp_new) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_new of long");
- return NULL;
- }
-
- reprfunc tp_repr = PyType_GetSlot(&PyLong_Type, Py_tp_repr);
- if (PyLong_Type.tp_repr != tp_repr) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_repr of long");
- return NULL;
- }
-
- ternaryfunc tp_call = PyType_GetSlot(&PyLong_Type, Py_tp_call);
- if (tp_call != NULL) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: tp_call of long");
- return NULL;
- }
-
- binaryfunc nb_add = PyType_GetSlot(&PyLong_Type, Py_nb_add);
- if (PyLong_Type.tp_as_number->nb_add != nb_add) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: nb_add of long");
- return NULL;
- }
-
- lenfunc mp_length = PyType_GetSlot(&PyLong_Type, Py_mp_length);
- if (mp_length != NULL) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: mp_length of long");
- return NULL;
- }
-
- void *over_value = PyType_GetSlot(&PyLong_Type, Py_bf_releasebuffer + 1);
- if (over_value != NULL) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: max+1 of long");
- return NULL;
- }
-
- tp_new = PyType_GetSlot(&PyLong_Type, 0);
- if (tp_new != NULL) {
- PyErr_SetString(PyExc_AssertionError, "mismatch: slot 0 of long");
- return NULL;
- }
- if (PyErr_ExceptionMatches(PyExc_SystemError)) {
- // This is the right exception
- PyErr_Clear();
- }
- else {
- return NULL;
- }
-
- Py_RETURN_NONE;
-}
-
-
-static PyType_Slot HeapTypeNameType_slots[] = {
- {0},
-};
-
-static PyType_Spec HeapTypeNameType_Spec = {
- .name = "_testcapi.HeapTypeNameType",
- .basicsize = sizeof(PyObject),
- .flags = Py_TPFLAGS_DEFAULT,
- .slots = HeapTypeNameType_slots,
-};
-
-static PyObject *
-get_heaptype_for_name(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
- return PyType_FromSpec(&HeapTypeNameType_Spec);
-}
-
-
-static PyObject *
-get_type_name(PyObject *self, PyObject *type)
-{
- assert(PyType_Check(type));
- return PyType_GetName((PyTypeObject *)type);
-}
-
-
-static PyObject *
-get_type_qualname(PyObject *self, PyObject *type)
-{
- assert(PyType_Check(type));
- return PyType_GetQualName((PyTypeObject *)type);
-}
-
-
-static PyObject *
-get_type_fullyqualname(PyObject *self, PyObject *type)
-{
- assert(PyType_Check(type));
- return PyType_GetFullyQualifiedName((PyTypeObject *)type);
-}
-
-
-static PyObject *
-get_type_module_name(PyObject *self, PyObject *type)
-{
- assert(PyType_Check(type));
- return PyType_GetModuleName((PyTypeObject *)type);
-}
-
-
-static PyObject *
-test_get_type_dict(PyObject *self, PyObject *Py_UNUSED(ignored))
-{
- /* Test for PyType_GetDict */
-
- // Assert ints have a `to_bytes` method
- PyObject *long_dict = PyType_GetDict(&PyLong_Type);
- assert(long_dict);
- assert(PyDict_GetItemString(long_dict, "to_bytes")); // borrowed ref
- Py_DECREF(long_dict);
-
- // Make a new type, add an attribute to it and assert it's there
- PyObject *HeapTypeNameType = PyType_FromSpec(&HeapTypeNameType_Spec);
- assert(HeapTypeNameType);
- assert(PyObject_SetAttrString(
- HeapTypeNameType, "new_attr", Py_NewRef(Py_None)) >= 0);
- PyObject *type_dict = PyType_GetDict((PyTypeObject*)HeapTypeNameType);
- assert(type_dict);
- assert(PyDict_GetItemString(type_dict, "new_attr")); // borrowed ref
- Py_DECREF(HeapTypeNameType);
- Py_DECREF(type_dict);
- Py_RETURN_NONE;
-}
-
static PyObject *
pyobject_repr_from_null(PyObject *self, PyObject *Py_UNUSED(ignored))
{
}
-// type->tp_version_tag
-static PyObject *
-type_get_version(PyObject *self, PyObject *type)
-{
- if (!PyType_Check(type)) {
- PyErr_SetString(PyExc_TypeError, "argument must be a type");
- return NULL;
- }
- PyObject *res = PyLong_FromUnsignedLong(
- ((PyTypeObject *)type)->tp_version_tag);
- if (res == NULL) {
- assert(PyErr_Occurred());
- return NULL;
- }
- return res;
-}
-
-static PyObject *
-type_modified(PyObject *self, PyObject *type)
-{
- if (!PyType_Check(type)) {
- PyErr_SetString(PyExc_TypeError, "argument must be a type");
- return NULL;
- }
- PyType_Modified((PyTypeObject *)type);
- Py_RETURN_NONE;
-}
-
-
-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);
-}
-
-
-static PyObject *
-type_get_tp_bases(PyObject *self, PyObject *type)
-{
- PyObject *bases = ((PyTypeObject *)type)->tp_bases;
- if (bases == NULL) {
- Py_RETURN_NONE;
- }
- return Py_NewRef(bases);
-}
-
-static PyObject *
-type_get_tp_mro(PyObject *self, PyObject *type)
-{
- PyObject *mro = ((PyTypeObject *)type)->tp_mro;
- if (mro == NULL) {
- Py_RETURN_NONE;
- }
- return Py_NewRef(mro);
-}
-
-
/* We only use 2 in test_capi/test_misc.py. */
#define NUM_BASIC_STATIC_TYPES 2
static PyTypeObject BasicStaticTypes[NUM_BASIC_STATIC_TYPES] = {
}
-static PyObject *
-type_freeze(PyObject *module, PyObject *args)
-{
- PyTypeObject *type;
- if (!PyArg_ParseTuple(args, "O!", &PyType_Type, &type)) {
- return NULL;
- }
- if (PyType_Freeze(type) < 0) {
- return NULL;
- }
- Py_RETURN_NONE;
-}
-
struct atexit_data {
int called;
PyThreadState *tstate;
{"py_buildvalue", py_buildvalue, METH_VARARGS},
{"py_buildvalue_ints", py_buildvalue_ints, METH_VARARGS},
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
- {"test_get_statictype_slots", test_get_statictype_slots, METH_NOARGS},
- {"get_heaptype_for_name", get_heaptype_for_name, METH_NOARGS},
- {"get_type_name", get_type_name, METH_O},
- {"get_type_qualname", get_type_qualname, METH_O},
- {"get_type_fullyqualname", get_type_fullyqualname, METH_O},
- {"get_type_module_name", get_type_module_name, METH_O},
- {"test_get_type_dict", test_get_type_dict, METH_NOARGS},
{"test_reftracer", test_reftracer, METH_NOARGS},
{"_test_thread_state", test_thread_state, METH_VARARGS},
{"gilstate_ensure_release", gilstate_ensure_release, METH_NOARGS},
{"test_refcount_funcs", test_refcount_funcs, METH_NOARGS},
{"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_modified", type_modified, METH_O, PyDoc_STR("PyType_Modified")},
- {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")},
- {"type_get_tp_bases", type_get_tp_bases, METH_O},
- {"type_get_tp_mro", type_get_tp_mro, METH_O},
{"get_basic_static_type", get_basic_static_type, METH_VARARGS, NULL},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"gen_get_code", gen_get_code, METH_O, NULL},
{"function_set_warning", function_set_warning, METH_NOARGS},
{"test_critical_sections", test_critical_sections, METH_NOARGS},
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
- {"type_freeze", type_freeze, METH_VARARGS},
{"test_atexit", test_atexit, METH_NOARGS},
{"code_offset_to_line", _PyCFunction_CAST(code_offset_to_line), METH_FASTCALL},
{"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS},
if (_PyTestCapi_Init_Frame(m) < 0) {
return NULL;
}
+ if (_PyTestCapi_Init_Type(m) < 0) {
+ return NULL;
+ }
PyState_AddModule(m, &_testcapimodule);
return m;
<ClCompile Include="..\Modules\_testcapi\config.c" />
<ClCompile Include="..\Modules\_testcapi\import.c" />
<ClCompile Include="..\Modules\_testcapi\frame.c" />
+ <ClCompile Include="..\Modules\_testcapi\type.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc" />
<ClCompile Include="..\Modules\_testcapi\frame.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\Modules\_testcapi\type.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\PC\python_nt.rc">