mirror of https://github.com/python/cpython.git
gh-93649: Add Modules/_testcapi/type.c file (#129516)
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()
This commit is contained in:
parent
881984b41a
commit
5424e3b034
|
@ -1111,147 +1111,6 @@ class Data(_testcapi.ObjExtraData):
|
|||
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()
|
||||
|
@ -2922,39 +2781,6 @@ def test_linked_lifecycle_link_incref_unlink_decref(self):
|
|||
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
|
||||
|
|
|
@ -4,7 +4,181 @@
|
|||
_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
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
@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
|
||||
|
|
|
@ -63,5 +63,6 @@ int _PyTestCapi_Init_Object(PyObject *module);
|
|||
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
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
#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);
|
||||
}
|
|
@ -530,136 +530,6 @@ test_buildvalue_N(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
}
|
||||
|
||||
|
||||
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))
|
||||
{
|
||||
|
@ -2380,68 +2250,6 @@ test_py_is_funcs(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] = {
|
||||
|
@ -3205,19 +3013,6 @@ finalize_thread_hang(PyObject *self, PyObject *callback)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
@ -3415,13 +3210,6 @@ static PyMethodDef TestMethods[] = {
|
|||
{"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},
|
||||
|
@ -3489,11 +3277,6 @@ static PyMethodDef TestMethods[] = {
|
|||
{"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},
|
||||
|
@ -3516,7 +3299,6 @@ static PyMethodDef TestMethods[] = {
|
|||
{"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},
|
||||
|
@ -4296,6 +4078,9 @@ PyInit__testcapi(void)
|
|||
if (_PyTestCapi_Init_Frame(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (_PyTestCapi_Init_Type(m) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyState_AddModule(m, &_testcapimodule);
|
||||
return m;
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
<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" />
|
||||
|
|
|
@ -120,6 +120,9 @@
|
|||
<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">
|
||||
|
|
Loading…
Reference in New Issue