Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ given type object has a specified feature.
#define Py_TPFLAGS_SEQUENCE (1 << 5)
/* Set if instances of the type object are treated as mappings for pattern matching */
#define Py_TPFLAGS_MAPPING (1 << 6)
#endif
#endif // Py_LIMITED_API

/* Disallow creating instances of the type: set tp_new to NULL and don't create
* the "__new__" key in the type dictionary. */
Expand Down
204 changes: 200 additions & 4 deletions Lib/test/test_capi/test_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import unittest

_testcapi = import_helper.import_module('_testcapi')
_testlimitedcapi = import_helper.import_module('_testlimitedcapi')

NULL = None


class BuiltinStaticTypesTests(unittest.TestCase):
Expand Down Expand Up @@ -39,15 +42,18 @@ def test_tp_mro_is_set(self):

class TypeTests(unittest.TestCase):
def test_get_type_name(self):
# Test PyType_GetName(), PyType_GetQualName(),
# PyType_GetFullyQualifiedName() and PyType_GetModuleName().

class MyType:
pass

from _testcapi import (
from _testlimitedcapi import (
get_type_name, get_type_qualname,
get_type_fullyqualname, get_type_module_name)

from collections import OrderedDict
ht = _testcapi.get_heaptype_for_name()
ht = _testlimitedcapi.get_heaptype_for_name()
for cls, fullname, modname, qualname, name in (
(int,
'int',
Expand Down Expand Up @@ -107,6 +113,15 @@ class MyType:
MyType.__module__ = 123
self.assertEqual(get_type_fullyqualname(MyType), 'my_qualname')

# CRASHES get_type_name(NULL)
# CRASHES get_type_qualname(NULL)
# CRASHES get_type_fullyqualname(NULL)
# CRASHES get_type_module_name(NULL)
# CRASHES get_type_name(object()): argument must be a type
# CRASHES get_type_qualname(object()): argument must be a type
# CRASHES get_type_fullyqualname(object()): argument must be a type
# CRASHES get_type_module_name(object()): argument must be a type

def test_get_base_by_token(self):
def get_base_by_token(src, key, comparable=True):
def run(use_mro):
Expand Down Expand Up @@ -215,7 +230,7 @@ class H2(int): pass

def test_freeze(self):
# test PyType_Freeze()
type_freeze = _testcapi.type_freeze
type_freeze = _testlimitedcapi.type_freeze

# simple case, no inherante
class MyType:
Expand Down Expand Up @@ -245,12 +260,15 @@ class D(A, C): pass
# as well
type_freeze(D)

# CRASHES type_freeze(NULL)
# CRASHES type_freeze(object()): argument must be a type

@unittest.skipIf(
Py_GIL_DISABLED and refleak_helper.hunting_for_refleaks(),
"Specialization failure triggers gh-127773")
def test_freeze_meta(self):
"""test PyType_Freeze() with overridden MRO"""
type_freeze = _testcapi.type_freeze
type_freeze = _testlimitedcapi.type_freeze

class Base:
value = 1
Expand Down Expand Up @@ -299,3 +317,181 @@ def test_extension_managed_weakref_nogc_type(self):
"flag but not Py_TPFLAGS_HAVE_GC flag")
with self.assertRaisesRegex(SystemError, msg):
_testcapi.create_managed_weakref_nogc_type()

def test_type_ready(self):
# Test PyType_Ready(): calling it on initialized types
# must not raise an exception.
type_ready = _testlimitedcapi.type_ready

class HeapType:
pass

type_ready(int)
type_ready(dict)
type_ready(HeapType)

# CRASHES type_ready(NULL)
# CRASHES type_ready(123): argument must be a type

def test_type_clearcache(self):
# Test PyType_ClearCache()
type_clearcache = _testlimitedcapi.type_clearcache
version_tag = type_clearcache()
self.assertEqual(type(version_tag), int)
self.assertGreaterEqual(version_tag, 0)

def test_type_getflags(self):
# Test PyType_GetFlags()
type_getflags = _testlimitedcapi.type_getflags

from _testlimitedcapi import (
Py_TPFLAGS_HEAPTYPE,
Py_TPFLAGS_HAVE_GC,
Py_TPFLAGS_HAVE_FINALIZE,
Py_TPFLAGS_HAVE_VERSION_TAG,
Py_TPFLAGS_VALID_VERSION_TAG,
Py_TPFLAGS_HAVE_VECTORCALL,
Py_TPFLAGS_DISALLOW_INSTANTIATION,
Py_TPFLAGS_IMMUTABLETYPE,
Py_TPFLAGS_READY,
Py_TPFLAGS_READYING,
Py_TPFLAGS_LONG_SUBCLASS,
Py_TPFLAGS_LIST_SUBCLASS,
Py_TPFLAGS_TUPLE_SUBCLASS,
Py_TPFLAGS_BYTES_SUBCLASS,
Py_TPFLAGS_UNICODE_SUBCLASS,
Py_TPFLAGS_DICT_SUBCLASS,
Py_TPFLAGS_BASE_EXC_SUBCLASS,
Py_TPFLAGS_TYPE_SUBCLASS,
Py_TPFLAGS_IS_ABSTRACT,
Py_TPFLAGS_BASETYPE,
_Py_TPFLAGS_MATCH_SELF,
Py_TPFLAGS_ITEMS_AT_END,
Py_TPFLAGS_METHOD_DESCRIPTOR,
)
from _testcapi import (
_Py_TPFLAGS_STATIC_BUILTIN,
Py_TPFLAGS_SEQUENCE,
Py_TPFLAGS_MAPPING,
Py_TPFLAGS_INLINE_VALUES,
Py_TPFLAGS_MANAGED_WEAKREF,
Py_TPFLAGS_MANAGED_DICT,
)

def check_flag(flags, flag, expected):
self.assertEqual(bool(flags & flag), expected)

def check_subclasses(test_type, flags):
for flag, base_type in (
(Py_TPFLAGS_LONG_SUBCLASS, int),
(Py_TPFLAGS_LIST_SUBCLASS, list),
(Py_TPFLAGS_TUPLE_SUBCLASS, tuple),
(Py_TPFLAGS_BYTES_SUBCLASS, bytes),
(Py_TPFLAGS_UNICODE_SUBCLASS, str),
(Py_TPFLAGS_DICT_SUBCLASS, dict),
(Py_TPFLAGS_BASE_EXC_SUBCLASS, BaseException),
(Py_TPFLAGS_TYPE_SUBCLASS, type),
):
with self.subTest(test_type=test_type, flag=flag, base_type=base_type):
check_flag(flags, flag, issubclass(test_type, base_type))

def check_type(test_type, static_type, have_gc=False, have_vectorcall=False,
is_base_type=True, sequence=False, mapping=False,
match_self=True, items_at_end=False):
heap_type = not static_type

flags = type_getflags(test_type)
check_flag(flags, _Py_TPFLAGS_STATIC_BUILTIN, static_type)
check_flag(flags, Py_TPFLAGS_HEAPTYPE, heap_type)
check_flag(flags, Py_TPFLAGS_HAVE_GC, have_gc)
check_subclasses(test_type, flags)
check_flag(flags, Py_TPFLAGS_HAVE_VECTORCALL, have_vectorcall)
check_flag(flags, Py_TPFLAGS_DISALLOW_INSTANTIATION, False)
check_flag(flags, Py_TPFLAGS_IMMUTABLETYPE, static_type)
check_flag(flags, Py_TPFLAGS_READY, True)
check_flag(flags, Py_TPFLAGS_READYING, False)
check_flag(flags, Py_TPFLAGS_IS_ABSTRACT, False)
check_flag(flags, Py_TPFLAGS_BASETYPE, is_base_type)
check_flag(flags, Py_TPFLAGS_SEQUENCE, sequence)
check_flag(flags, Py_TPFLAGS_MAPPING, mapping)

check_flag(flags, Py_TPFLAGS_INLINE_VALUES, heap_type)
check_flag(flags, Py_TPFLAGS_MANAGED_WEAKREF, heap_type)
check_flag(flags, Py_TPFLAGS_MANAGED_DICT, heap_type)
check_flag(flags, Py_TPFLAGS_ITEMS_AT_END, items_at_end)
check_flag(flags, Py_TPFLAGS_METHOD_DESCRIPTOR, False)

check_flag(flags, _Py_TPFLAGS_MATCH_SELF, match_self)

# Flags kept for backward compatibility
check_flag(flags, Py_TPFLAGS_HAVE_FINALIZE, False)
check_flag(flags, Py_TPFLAGS_HAVE_VERSION_TAG, False)
check_flag(flags, Py_TPFLAGS_VALID_VERSION_TAG, False)

# Scalar types
check_type(int, static_type=True)
check_type(bool, static_type=True,
is_base_type=False)
check_type(float, static_type=True)
check_type(complex, static_type=True,
match_self=False)
check_type(bytes, static_type=True)
check_type(bytearray, static_type=True)
check_type(str, static_type=True)

# Collection types
check_type(tuple, static_type=True, have_gc=True,
sequence=True)
check_type(list, static_type=True, have_gc=True,
sequence=True)
check_type(dict, static_type=True, have_gc=True,
mapping=True)
check_type(frozendict, static_type=True, have_gc=True,
mapping=True)
check_type(set, static_type=True, have_gc=True)
check_type(frozenset, static_type=True, have_gc=True)

# Other types
check_type(BaseException, static_type=True, have_gc=True,
match_self=False)
check_type(type, static_type=True, have_gc=True,
have_vectorcall=True,
match_self=False,
items_at_end=True)

# Heap type
class HeapType:
pass
check_type(HeapType, static_type=False, have_gc=True, match_self=False)

# CRASHES type_getflags(NULL)

def test_type_issubtype(self):
# Test PyType_IsSubtype()
_type_issubtype = _testlimitedcapi.type_issubtype

def type_issubtype(type1, type2):
res = _type_issubtype(type1, type2)
self.assertIn(res, (0, 1))
return bool(res)

class MyList(list):
pass

self.assertTrue(type_issubtype(bool, int))
self.assertTrue(type_issubtype(MyList, list))

self.assertFalse(type_issubtype(int, type))
self.assertFalse(type_issubtype(frozendict, dict))
self.assertFalse(type_issubtype(MyList, tuple))

def test_type_modified(self):
# Test PyType_Modified()
type_modified = _testlimitedcapi.type_modified

class MyType:
pass
type_modified(MyType)

# CRASHES type_modified(NULL)
# CRASHES type_modified({}): argument must be a type
6 changes: 4 additions & 2 deletions Lib/test/test_type_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
except ImportError:
_clear_type_cache = None

# Skip this test if the _testcapi module isn't available.
# Skip this test if the _testcapi modules are not available.
_testcapi = import_helper.import_module("_testcapi")
_testlimitedcapi = import_helper.import_module("_testlimitedcapi")
_testinternalcapi = import_helper.import_module("_testinternalcapi")

type_get_version = _testcapi.type_get_version
type_assign_specific_version_unsafe = _testinternalcapi.type_assign_specific_version_unsafe
type_assign_version = _testcapi.type_assign_version
type_modified = _testcapi.type_modified
type_modified = _testlimitedcapi.type_modified

def clear_type_cache():
with warnings.catch_warnings():
Expand Down
2 changes: 1 addition & 1 deletion Modules/Setup.stdlib.in
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
@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 _testinternalcapi/complex.c _testinternalcapi/interpreter.c _testinternalcapi/tuple.c _testinternalcapi/typecache.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/modsupport.c _testcapi/monitoring.c _testcapi/config.c _testcapi/import.c _testcapi/frame.c _testcapi/type.c _testcapi/function.c _testcapi/module.c _testcapi/weakref.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/capsule.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/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c
@MODULE__TESTLIMITEDCAPI_TRUE@_testlimitedcapi _testlimitedcapi.c _testlimitedcapi/abstract.c _testlimitedcapi/bytearray.c _testlimitedcapi/bytes.c _testlimitedcapi/capsule.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/slots.c _testlimitedcapi/sys.c _testlimitedcapi/threadstate.c _testlimitedcapi/tuple.c _testlimitedcapi/unicode.c _testlimitedcapi/vectorcall_limited.c _testlimitedcapi/version.c _testlimitedcapi/file.c _testlimitedcapi/weakref.c _testlimitedcapi/run.c _testlimitedcapi/type.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

Expand Down
Loading
Loading