0
0
mirror of https://github.com/python/cpython.git synced 2024-11-30 18:51:15 +01:00

gh-107178: Add the C API tests for the Abstract Objects Layer (GH-107179)

Cover all the Mapping Protocol, almost all the Sequence Protocol
(except PySequence_Fast) and a part of the Object Protocol.

Move existing tests to Lib/test/test_capi/test_abstract.py and
Modules/_testcapi/abstract.c.

Add also tests for PyDict C API.
This commit is contained in:
Serhiy Storchaka 2023-08-07 18:51:43 +03:00 committed by GitHub
parent 8579327879
commit 16c9415fba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 2174 additions and 297 deletions

View File

@ -1354,7 +1354,7 @@ class ByteArrayTest(BaseBytesTest, unittest.TestCase):
except ValueError:
pass
try:
setitem(b, 0, None)
setitem(b, 0, object())
self.fail("Didn't raise TypeError")
except TypeError:
pass

View File

@ -0,0 +1,722 @@
import unittest
import sys
from collections import OrderedDict
from test import support
from test.support import import_helper
import _testcapi
NULL = None
class TestObject:
@property
def evil(self):
raise RuntimeError('do not get evil')
@evil.setter
def evil(self, value):
raise RuntimeError('do not set evil')
@evil.deleter
def evil(self):
raise RuntimeError('do not del evil')
class ProxyGetItem:
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return self.obj[key]
class ProxySetItem:
def __init__(self, obj):
self.obj = obj
def __setitem__(self, key, value):
self.obj[key] = value
class ProxyDelItem:
def __init__(self, obj):
self.obj = obj
def __delitem__(self, key):
del self.obj[key]
def gen():
yield 'a'
yield 'b'
yield 'c'
class CAPITest(unittest.TestCase):
def test_object_getattr(self):
xgetattr = _testcapi.object_getattr
obj = TestObject()
obj.a = 11
setattr(obj, '\U0001f40d', 22)
self.assertEqual(xgetattr(obj, 'a'), 11)
self.assertRaises(AttributeError, xgetattr, obj, 'b')
self.assertEqual(xgetattr(obj, '\U0001f40d'), 22)
self.assertRaises(RuntimeError, xgetattr, obj, 'evil')
self.assertRaises(TypeError, xgetattr, obj, 1)
# CRASHES xgetattr(obj, NULL)
# CRASHES xgetattr(NULL, 'a')
def test_object_getattrstring(self):
getattrstring = _testcapi.object_getattrstring
obj = TestObject()
obj.a = 11
setattr(obj, '\U0001f40d', 22)
self.assertEqual(getattrstring(obj, b'a'), 11)
self.assertRaises(AttributeError, getattrstring, obj, b'b')
self.assertEqual(getattrstring(obj, '\U0001f40d'.encode()), 22)
self.assertRaises(RuntimeError, getattrstring, obj, b'evil')
self.assertRaises(UnicodeDecodeError, getattrstring, obj, b'\xff')
# CRASHES getattrstring(obj, NULL)
# CRASHES getattrstring(NULL, b'a')
def test_object_getoptionalattr(self):
getoptionalattr = _testcapi.object_getoptionalattr
obj = TestObject()
obj.a = 11
setattr(obj, '\U0001f40d', 22)
self.assertEqual(getoptionalattr(obj, 'a'), 11)
self.assertIs(getoptionalattr(obj, 'b'), AttributeError)
self.assertEqual(getoptionalattr(obj, '\U0001f40d'), 22)
self.assertRaises(RuntimeError, getoptionalattr, obj, 'evil')
self.assertRaises(TypeError, getoptionalattr, obj, 1)
# CRASHES getoptionalattr(obj, NULL)
# CRASHES getoptionalattr(NULL, 'a')
def test_object_getoptionalattrstring(self):
getoptionalattrstring = _testcapi.object_getoptionalattrstring
obj = TestObject()
obj.a = 11
setattr(obj, '\U0001f40d', 22)
self.assertEqual(getoptionalattrstring(obj, b'a'), 11)
self.assertIs(getoptionalattrstring(obj, b'b'), AttributeError)
self.assertEqual(getoptionalattrstring(obj, '\U0001f40d'.encode()), 22)
self.assertRaises(RuntimeError, getoptionalattrstring, obj, b'evil')
self.assertRaises(UnicodeDecodeError, getoptionalattrstring, obj, b'\xff')
# CRASHES getoptionalattrstring(obj, NULL)
# CRASHES getoptionalattrstring(NULL, b'a')
def test_object_hasattr(self):
xhasattr = _testcapi.object_hasattr
obj = TestObject()
obj.a = 1
setattr(obj, '\U0001f40d', 2)
self.assertTrue(xhasattr(obj, 'a'))
self.assertFalse(xhasattr(obj, 'b'))
self.assertTrue(xhasattr(obj, '\U0001f40d'))
self.assertFalse(xhasattr(obj, 'evil'))
self.assertFalse(xhasattr(obj, 1))
# CRASHES xhasattr(obj, NULL)
# CRASHES xhasattr(NULL, 'a')
def test_object_hasattrstring(self):
hasattrstring = _testcapi.object_hasattrstring
obj = TestObject()
obj.a = 1
setattr(obj, '\U0001f40d', 2)
self.assertTrue(hasattrstring(obj, b'a'))
self.assertFalse(hasattrstring(obj, b'b'))
self.assertTrue(hasattrstring(obj, '\U0001f40d'.encode()))
self.assertFalse(hasattrstring(obj, b'evil'))
self.assertFalse(hasattrstring(obj, b'\xff'))
# CRASHES hasattrstring(obj, NULL)
# CRASHES hasattrstring(NULL, b'a')
def test_object_setattr(self):
xsetattr = _testcapi.object_setattr
obj = TestObject()
xsetattr(obj, 'a', 5)
self.assertEqual(obj.a, 5)
xsetattr(obj, '\U0001f40d', 8)
self.assertEqual(getattr(obj, '\U0001f40d'), 8)
# PyObject_SetAttr(obj, attr_name, NULL) removes the attribute
xsetattr(obj, 'a', NULL)
self.assertFalse(hasattr(obj, 'a'))
self.assertRaises(AttributeError, xsetattr, obj, 'b', NULL)
self.assertRaises(RuntimeError, xsetattr, obj, 'evil', NULL)
self.assertRaises(RuntimeError, xsetattr, obj, 'evil', 'good')
self.assertRaises(AttributeError, xsetattr, 42, 'a', 5)
self.assertRaises(TypeError, xsetattr, obj, 1, 5)
# CRASHES xsetattr(obj, NULL, 5)
# CRASHES xsetattr(NULL, 'a', 5)
def test_object_setattrstring(self):
setattrstring = _testcapi.object_setattrstring
obj = TestObject()
setattrstring(obj, b'a', 5)
self.assertEqual(obj.a, 5)
setattrstring(obj, '\U0001f40d'.encode(), 8)
self.assertEqual(getattr(obj, '\U0001f40d'), 8)
# PyObject_SetAttrString(obj, attr_name, NULL) removes the attribute
setattrstring(obj, b'a', NULL)
self.assertFalse(hasattr(obj, 'a'))
self.assertRaises(AttributeError, setattrstring, obj, b'b', NULL)
self.assertRaises(RuntimeError, setattrstring, obj, b'evil', NULL)
self.assertRaises(RuntimeError, setattrstring, obj, b'evil', 'good')
self.assertRaises(AttributeError, setattrstring, 42, b'a', 5)
self.assertRaises(TypeError, setattrstring, obj, 1, 5)
self.assertRaises(UnicodeDecodeError, setattrstring, obj, b'\xff', 5)
# CRASHES setattrstring(obj, NULL, 5)
# CRASHES setattrstring(NULL, b'a', 5)
def test_object_delattr(self):
xdelattr = _testcapi.object_delattr
obj = TestObject()
obj.a = 1
setattr(obj, '\U0001f40d', 2)
xdelattr(obj, 'a')
self.assertFalse(hasattr(obj, 'a'))
self.assertRaises(AttributeError, xdelattr, obj, 'b')
xdelattr(obj, '\U0001f40d')
self.assertFalse(hasattr(obj, '\U0001f40d'))
self.assertRaises(AttributeError, xdelattr, 42, 'numerator')
self.assertRaises(RuntimeError, xdelattr, obj, 'evil')
self.assertRaises(TypeError, xdelattr, obj, 1)
# CRASHES xdelattr(obj, NULL)
# CRASHES xdelattr(NULL, 'a')
def test_object_delattrstring(self):
delattrstring = _testcapi.object_delattrstring
obj = TestObject()
obj.a = 1
setattr(obj, '\U0001f40d', 2)
delattrstring(obj, b'a')
self.assertFalse(hasattr(obj, 'a'))
self.assertRaises(AttributeError, delattrstring, obj, b'b')
delattrstring(obj, '\U0001f40d'.encode())
self.assertFalse(hasattr(obj, '\U0001f40d'))
self.assertRaises(AttributeError, delattrstring, 42, b'numerator')
self.assertRaises(RuntimeError, delattrstring, obj, b'evil')
self.assertRaises(UnicodeDecodeError, delattrstring, obj, b'\xff')
# CRASHES delattrstring(obj, NULL)
# CRASHES delattrstring(NULL, b'a')
def test_mapping_check(self):
check = _testcapi.mapping_check
self.assertTrue(check({1: 2}))
self.assertTrue(check([1, 2]))
self.assertTrue(check((1, 2)))
self.assertTrue(check('abc'))
self.assertTrue(check(b'abc'))
self.assertFalse(check(42))
self.assertFalse(check(object()))
self.assertFalse(check(NULL))
def test_mapping_size(self):
for size in _testcapi.mapping_size, _testcapi.mapping_length:
self.assertEqual(size({1: 2}), 1)
self.assertEqual(size([1, 2]), 2)
self.assertEqual(size((1, 2)), 2)
self.assertEqual(size('abc'), 3)
self.assertEqual(size(b'abc'), 3)
self.assertRaises(TypeError, size, 42)
self.assertRaises(TypeError, size, object())
self.assertRaises(SystemError, size, NULL)
def test_object_getitem(self):
getitem = _testcapi.object_getitem
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitem(dct, 'a'), 1)
self.assertRaises(KeyError, getitem, dct, 'b')
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
dct2 = ProxyGetItem(dct)
self.assertEqual(getitem(dct2, 'a'), 1)
self.assertRaises(KeyError, getitem, dct2, 'b')
self.assertEqual(getitem(['a', 'b', 'c'], 1), 'b')
self.assertRaises(TypeError, getitem, 42, 'a')
self.assertRaises(TypeError, getitem, {}, []) # unhashable
self.assertRaises(SystemError, getitem, {}, NULL)
self.assertRaises(IndexError, getitem, [], 1)
self.assertRaises(TypeError, getitem, [], 'a')
self.assertRaises(SystemError, getitem, NULL, 'a')
def test_mapping_getitemstring(self):
getitemstring = _testcapi.mapping_getitemstring
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitemstring(dct, b'a'), 1)
self.assertRaises(KeyError, getitemstring, dct, b'b')
self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
dct2 = ProxyGetItem(dct)
self.assertEqual(getitemstring(dct2, b'a'), 1)
self.assertRaises(KeyError, getitemstring, dct2, b'b')
self.assertRaises(TypeError, getitemstring, 42, b'a')
self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff')
self.assertRaises(SystemError, getitemstring, {}, NULL)
self.assertRaises(TypeError, getitemstring, [], b'a')
self.assertRaises(SystemError, getitemstring, NULL, b'a')
def test_mapping_haskey(self):
haskey = _testcapi.mapping_haskey
dct = {'a': 1, '\U0001f40d': 2}
self.assertTrue(haskey(dct, 'a'))
self.assertFalse(haskey(dct, 'b'))
self.assertTrue(haskey(dct, '\U0001f40d'))
dct2 = ProxyGetItem(dct)
self.assertTrue(haskey(dct2, 'a'))
self.assertFalse(haskey(dct2, 'b'))
self.assertTrue(haskey(['a', 'b', 'c'], 1))
self.assertFalse(haskey(42, 'a'))
self.assertFalse(haskey({}, [])) # unhashable
self.assertFalse(haskey({}, NULL))
self.assertFalse(haskey([], 1))
self.assertFalse(haskey([], 'a'))
self.assertFalse(haskey(NULL, 'a'))
def test_mapping_haskeystring(self):
haskeystring = _testcapi.mapping_haskeystring
dct = {'a': 1, '\U0001f40d': 2}
self.assertTrue(haskeystring(dct, b'a'))
self.assertFalse(haskeystring(dct, b'b'))
self.assertTrue(haskeystring(dct, '\U0001f40d'.encode()))
dct2 = ProxyGetItem(dct)
self.assertTrue(haskeystring(dct2, b'a'))
self.assertFalse(haskeystring(dct2, b'b'))
self.assertFalse(haskeystring(42, b'a'))
self.assertFalse(haskeystring({}, b'\xff'))
self.assertFalse(haskeystring({}, NULL))
self.assertFalse(haskeystring([], b'a'))
self.assertFalse(haskeystring(NULL, b'a'))
def test_object_setitem(self):
setitem = _testcapi.object_setitem
dct = {}
setitem(dct, 'a', 5)
self.assertEqual(dct, {'a': 5})
setitem(dct, '\U0001f40d', 8)
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
dct = {}
dct2 = ProxySetItem(dct)
setitem(dct2, 'a', 5)
self.assertEqual(dct, {'a': 5})
lst = ['a', 'b', 'c']
setitem(lst, 1, 'x')
self.assertEqual(lst, ['a', 'x', 'c'])
self.assertRaises(TypeError, setitem, 42, 'a', 5)
self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable
self.assertRaises(SystemError, setitem, {}, NULL, 5)
self.assertRaises(SystemError, setitem, {}, 'a', NULL)
self.assertRaises(IndexError, setitem, [], 1, 5)
self.assertRaises(TypeError, setitem, [], 'a', 5)
self.assertRaises(TypeError, setitem, (), 1, 5)
self.assertRaises(SystemError, setitem, NULL, 'a', 5)
def test_mapping_setitemstring(self):
setitemstring = _testcapi.mapping_setitemstring
dct = {}
setitemstring(dct, b'a', 5)
self.assertEqual(dct, {'a': 5})
setitemstring(dct, '\U0001f40d'.encode(), 8)
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
dct = {}
dct2 = ProxySetItem(dct)
setitemstring(dct2, b'a', 5)
self.assertEqual(dct, {'a': 5})
self.assertRaises(TypeError, setitemstring, 42, b'a', 5)
self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5)
self.assertRaises(SystemError, setitemstring, {}, NULL, 5)
self.assertRaises(SystemError, setitemstring, {}, b'a', NULL)
self.assertRaises(TypeError, setitemstring, [], b'a', 5)
self.assertRaises(SystemError, setitemstring, NULL, b'a', 5)
def test_object_delitem(self):
for delitem in _testcapi.object_delitem, _testcapi.mapping_delitem:
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
delitem(dct, 'a')
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
self.assertRaises(KeyError, delitem, dct, 'b')
delitem(dct, '\U0001f40d')
self.assertEqual(dct, {'c': 2})
dct = {'a': 1, 'c': 2}
dct2 = ProxyDelItem(dct)
delitem(dct2, 'a')
self.assertEqual(dct, {'c': 2})
self.assertRaises(KeyError, delitem, dct2, 'b')
lst = ['a', 'b', 'c']
delitem(lst, 1)
self.assertEqual(lst, ['a', 'c'])
self.assertRaises(TypeError, delitem, 42, 'a')
self.assertRaises(TypeError, delitem, {}, []) # unhashable
self.assertRaises(SystemError, delitem, {}, NULL)
self.assertRaises(IndexError, delitem, [], 1)
self.assertRaises(TypeError, delitem, [], 'a')
self.assertRaises(SystemError, delitem, NULL, 'a')
def test_mapping_delitemstring(self):
delitemstring = _testcapi.mapping_delitemstring
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
delitemstring(dct, b'a')
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
self.assertRaises(KeyError, delitemstring, dct, b'b')
delitemstring(dct, '\U0001f40d'.encode())
self.assertEqual(dct, {'c': 2})
dct = {'a': 1, 'c': 2}
dct2 = ProxyDelItem(dct)
delitemstring(dct2, b'a')
self.assertEqual(dct, {'c': 2})
self.assertRaises(KeyError, delitemstring, dct2, b'b')
self.assertRaises(TypeError, delitemstring, 42, b'a')
self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff')
self.assertRaises(SystemError, delitemstring, {}, NULL)
self.assertRaises(TypeError, delitemstring, [], b'a')
self.assertRaises(SystemError, delitemstring, NULL, b'a')
def test_mapping_keys_valuesitems(self):
class Mapping1(dict):
def keys(self):
return list(super().keys())
def values(self):
return list(super().values())
def items(self):
return list(super().items())
class Mapping2(dict):
def keys(self):
return tuple(super().keys())
def values(self):
return tuple(super().values())
def items(self):
return tuple(super().items())
dict_obj = {'foo': 1, 'bar': 2, 'spam': 3}
for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(),
dict_obj, OrderedDict(dict_obj),
Mapping1(dict_obj), Mapping2(dict_obj)]:
self.assertListEqual(_testcapi.mapping_keys(mapping),
list(mapping.keys()))
self.assertListEqual(_testcapi.mapping_values(mapping),
list(mapping.values()))
self.assertListEqual(_testcapi.mapping_items(mapping),
list(mapping.items()))
def test_mapping_keys_valuesitems_bad_arg(self):
self.assertRaises(AttributeError, _testcapi.mapping_keys, object())
self.assertRaises(AttributeError, _testcapi.mapping_values, object())
self.assertRaises(AttributeError, _testcapi.mapping_items, object())
self.assertRaises(AttributeError, _testcapi.mapping_keys, [])
self.assertRaises(AttributeError, _testcapi.mapping_values, [])
self.assertRaises(AttributeError, _testcapi.mapping_items, [])
self.assertRaises(SystemError, _testcapi.mapping_keys, NULL)
self.assertRaises(SystemError, _testcapi.mapping_values, NULL)
self.assertRaises(SystemError, _testcapi.mapping_items, NULL)
class BadMapping:
def keys(self):
return None
def values(self):
return None
def items(self):
return None
bad_mapping = BadMapping()
self.assertRaises(TypeError, _testcapi.mapping_keys, bad_mapping)
self.assertRaises(TypeError, _testcapi.mapping_values, bad_mapping)
self.assertRaises(TypeError, _testcapi.mapping_items, bad_mapping)
def test_sequence_check(self):
check = _testcapi.sequence_check
self.assertFalse(check({1: 2}))
self.assertTrue(check([1, 2]))
self.assertTrue(check((1, 2)))
self.assertTrue(check('abc'))
self.assertTrue(check(b'abc'))
self.assertFalse(check(42))
self.assertFalse(check(object()))
# CRASHES check(NULL)
def test_sequence_size(self):
for size in _testcapi.sequence_size, _testcapi.sequence_length:
self.assertEqual(size([1, 2]), 2)
self.assertEqual(size((1, 2)), 2)
self.assertEqual(size('abc'), 3)
self.assertEqual(size(b'abc'), 3)
self.assertRaises(TypeError, size, {})
self.assertRaises(TypeError, size, 42)
self.assertRaises(TypeError, size, object())
self.assertRaises(SystemError, size, NULL)
def test_sequence_getitem(self):
getitem = _testcapi.sequence_getitem
lst = ['a', 'b', 'c']
self.assertEqual(getitem(lst, 1), 'b')
self.assertEqual(getitem(lst, -1), 'c')
self.assertRaises(IndexError, getitem, lst, 3)
self.assertRaises(TypeError, getitem, 42, 1)
self.assertRaises(TypeError, getitem, {}, 1)
self.assertRaises(SystemError, getitem, NULL, 1)
def test_sequence_concat(self):
concat = _testcapi.sequence_concat
self.assertEqual(concat(['a', 'b'], [1, 2]), ['a', 'b', 1, 2])
self.assertEqual(concat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2))
self.assertRaises(TypeError, concat, [], ())
self.assertRaises(TypeError, concat, (), [])
self.assertRaises(TypeError, concat, [], 42)
self.assertRaises(TypeError, concat, 42, [])
self.assertRaises(TypeError, concat, 42, 43)
self.assertRaises(SystemError, concat, [], NULL)
self.assertRaises(SystemError, concat, NULL, [])
def test_sequence_repeat(self):
repeat = _testcapi.sequence_repeat
self.assertEqual(repeat(['a', 'b'], 2), ['a', 'b', 'a', 'b'])
self.assertEqual(repeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(repeat(['a', 'b'], 0), [])
self.assertEqual(repeat(['a', 'b'], -1), [])
self.assertRaises(TypeError, repeat, set(), 2)
self.assertRaises(TypeError, repeat, 42, 2)
self.assertRaises(SystemError, repeat, NULL, 2)
def test_sequence_inplaceconcat(self):
inplaceconcat = _testcapi.sequence_inplaceconcat
lst = ['a', 'b']
res = inplaceconcat(lst, [1, 2])
self.assertEqual(res, ['a', 'b', 1, 2])
self.assertIs(res, lst)
lst = ['a', 'b']
res = inplaceconcat(lst, (1, 2))
self.assertEqual(res, ['a', 'b', 1, 2])
self.assertIs(res, lst)
self.assertEqual(inplaceconcat(('a', 'b'), (1, 2)), ('a', 'b', 1, 2))
self.assertRaises(TypeError, inplaceconcat, (), [])
self.assertRaises(TypeError, inplaceconcat, [], 42)
self.assertRaises(TypeError, inplaceconcat, 42, [])
self.assertRaises(TypeError, inplaceconcat, 42, 43)
self.assertRaises(SystemError, inplaceconcat, [], NULL)
self.assertRaises(SystemError, inplaceconcat, NULL, [])
def test_sequence_inplacerepeat(self):
inplacerepeat = _testcapi.sequence_inplacerepeat
lst = ['a', 'b']
res = inplacerepeat(lst, 2)
self.assertEqual(res, ['a', 'b', 'a', 'b'])
self.assertIs(res, lst)
self.assertEqual(inplacerepeat(('a', 'b'), 2), ('a', 'b', 'a', 'b'))
self.assertEqual(inplacerepeat(['a', 'b'], 0), [])
self.assertEqual(inplacerepeat(['a', 'b'], -1), [])
self.assertRaises(TypeError, inplacerepeat, set(), 2)
self.assertRaises(TypeError, inplacerepeat, 42, 2)
self.assertRaises(SystemError, inplacerepeat, NULL, 2)
def test_sequence_setitem(self):
setitem = _testcapi.sequence_setitem
lst = ['a', 'b', 'c']
setitem(lst, 1, 'x')
self.assertEqual(lst, ['a', 'x', 'c'])
setitem(lst, -1, 'y')
self.assertEqual(lst, ['a', 'x', 'y'])
setitem(lst, 0, NULL)
self.assertEqual(lst, ['x', 'y'])
self.assertRaises(IndexError, setitem, lst, 3, 'x')
self.assertRaises(TypeError, setitem, 42, 1, 'x')
self.assertRaises(TypeError, setitem, {}, 1, 'x')
self.assertRaises(SystemError, setitem, NULL, 1, 'x')
def test_sequence_delitem(self):
delitem = _testcapi.sequence_delitem
lst = ['a', 'b', 'c']
delitem(lst, 1)
self.assertEqual(lst, ['a', 'c'])
delitem(lst, -1)
self.assertEqual(lst, ['a'])
self.assertRaises(IndexError, delitem, lst, 3)
self.assertRaises(TypeError, delitem, 42, 1)
self.assertRaises(TypeError, delitem, {}, 1)
self.assertRaises(SystemError, delitem, NULL, 1)
def test_sequence_setslice(self):
setslice = _testcapi.sequence_setslice
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
setslice(data, 1, 3, [8, 9])
data_copy[1:3] = [8, 9]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 8, 9, 4, 5])
# Custom class:
class Custom:
def __setitem__(self, index, value):
self.index = index
self.value = value
c = Custom()
setslice(c, 0, 5, 'abc')
self.assertEqual(c.index, slice(0, 5))
self.assertEqual(c.value, 'abc')
# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
self.assertRaises(TypeError, setslice, bad_seq1, 1, 3, (8, 9))
self.assertEqual(bad_seq1, (1, 2, 3, 4))
bad_seq2 = 'abcd'
self.assertRaises(TypeError, setslice, bad_seq2, 1, 3, 'xy')
self.assertEqual(bad_seq2, 'abcd')
# Not a sequence:
self.assertRaises(TypeError, setslice, object(), 1, 3, 'xy')
self.assertRaises(SystemError, setslice, NULL, 1, 3, 'xy')
data_copy = data.copy()
setslice(data_copy, 1, 3, NULL)
self.assertEqual(data_copy, [1, 4, 5])
def test_sequence_delslice(self):
delslice = _testcapi.sequence_delslice
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
delslice(data, 1, 3)
del data_copy[1:3]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 4, 5])
# Custom class:
class Custom:
def __delitem__(self, index):
self.index = index
c = Custom()
delslice(c, 0, 5)
self.assertEqual(c.index, slice(0, 5))
# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
self.assertRaises(TypeError, delslice, bad_seq1, 1, 3)
self.assertEqual(bad_seq1, (1, 2, 3, 4))
bad_seq2 = 'abcd'
self.assertRaises(TypeError, delslice, bad_seq2, 1, 3)
self.assertEqual(bad_seq2, 'abcd')
# Not a sequence:
self.assertRaises(TypeError, delslice, object(), 1, 3)
self.assertRaises(SystemError, delslice, NULL, 1, 3)
mapping = {1: 'a', 2: 'b', 3: 'c'}
self.assertRaises(KeyError, delslice, mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
def test_sequence_count(self):
count = _testcapi.sequence_count
lst = ['a', 'b', 'a']
self.assertEqual(count(lst, 'a'), 2)
self.assertEqual(count(lst, 'c'), 0)
self.assertEqual(count(iter(lst), 'a'), 2)
self.assertEqual(count(iter(lst), 'c'), 0)
self.assertEqual(count({'a': 2}, 'a'), 1)
self.assertRaises(TypeError, count, 42, 'a')
self.assertRaises(SystemError, count, [], NULL)
self.assertRaises(SystemError, count, [1], NULL)
self.assertRaises(SystemError, count, NULL, 'a')
def test_sequence_contains(self):
contains = _testcapi.sequence_contains
lst = ['a', 'b', 'a']
self.assertEqual(contains(lst, 'a'), 1)
self.assertEqual(contains(lst, 'c'), 0)
self.assertEqual(contains(iter(lst), 'a'), 1)
self.assertEqual(contains(iter(lst), 'c'), 0)
self.assertEqual(contains({'a': 2}, 'a'), 1)
# XXX Only for empty sequences. Should be SystemError?
self.assertEqual(contains([], NULL), 0)
self.assertRaises(TypeError, contains, 42, 'a')
self.assertRaises(SystemError, contains, [1], NULL)
# CRASHES contains({}, NULL)
# CRASHES contains(set(), NULL)
# CRASHES contains(NULL, 'a')
def test_sequence_index(self):
index = _testcapi.sequence_index
lst = ['a', 'b', 'a']
self.assertEqual(index(lst, 'a'), 0)
self.assertEqual(index(lst, 'b'), 1)
self.assertRaises(ValueError, index, lst, 'c')
self.assertEqual(index(iter(lst), 'a'), 0)
self.assertEqual(index(iter(lst), 'b'), 1)
self.assertRaises(ValueError, index, iter(lst), 'c')
dct = {'a': 2, 'b': 3}
self.assertEqual(index(dct, 'a'), 0)
self.assertEqual(index(dct, 'b'), 1)
self.assertRaises(ValueError, index, dct, 'c')
self.assertRaises(TypeError, index, 42, 'a')
self.assertRaises(SystemError, index, [], NULL)
self.assertRaises(SystemError, index, [1], NULL)
self.assertRaises(SystemError, index, NULL, 'a')
def test_sequence_list(self):
xlist = _testcapi.sequence_list
self.assertEqual(xlist(['a', 'b', 'c']), ['a', 'b', 'c'])
self.assertEqual(xlist(('a', 'b', 'c')), ['a', 'b', 'c'])
self.assertEqual(xlist(iter(['a', 'b', 'c'])), ['a', 'b', 'c'])
self.assertEqual(xlist(gen()), ['a', 'b', 'c'])
self.assertRaises(TypeError, xlist, 42)
self.assertRaises(SystemError, xlist, NULL)
def test_sequence_tuple(self):
xtuple = _testcapi.sequence_tuple
self.assertEqual(xtuple(['a', 'b', 'c']), ('a', 'b', 'c'))
self.assertEqual(xtuple(('a', 'b', 'c')), ('a', 'b', 'c'))
self.assertEqual(xtuple(iter(['a', 'b', 'c'])), ('a', 'b', 'c'))
self.assertEqual(xtuple(gen()), ('a', 'b', 'c'))
self.assertRaises(TypeError, xtuple, 42)
self.assertRaises(SystemError, xtuple, NULL)
if __name__ == "__main__":
unittest.main()

View File

@ -0,0 +1,413 @@
import unittest
import sys
from collections import OrderedDict, UserDict
from types import MappingProxyType
from test import support
from test.support import import_helper
import _testcapi
NULL = None
class DictSubclass(dict):
def __getitem__(self, key):
raise RuntimeError('do not get evil')
def __setitem__(self, key, value):
raise RuntimeError('do not set evil')
def __delitem__(self, key):
raise RuntimeError('do not del evil')
def gen():
yield 'a'
yield 'b'
yield 'c'
class CAPITest(unittest.TestCase):
def test_dict_check(self):
check = _testcapi.dict_check
self.assertTrue(check({1: 2}))
self.assertTrue(check(OrderedDict({1: 2})))
self.assertFalse(check(UserDict({1: 2})))
self.assertFalse(check([1, 2]))
self.assertFalse(check(object()))
#self.assertFalse(check(NULL))
def test_dict_checkexact(self):
check = _testcapi.dict_checkexact
self.assertTrue(check({1: 2}))
self.assertFalse(check(OrderedDict({1: 2})))
self.assertFalse(check(UserDict({1: 2})))
self.assertFalse(check([1, 2]))
self.assertFalse(check(object()))
#self.assertFalse(check(NULL))
def test_dict_new(self):
dict_new = _testcapi.dict_new
dct = dict_new()
self.assertEqual(dct, {})
self.assertIs(type(dct), dict)
dct2 = dict_new()
self.assertIsNot(dct2, dct)
def test_dictproxy_new(self):
dictproxy_new = _testcapi.dictproxy_new
for dct in {1: 2}, OrderedDict({1: 2}), UserDict({1: 2}):
proxy = dictproxy_new(dct)
self.assertIs(type(proxy), MappingProxyType)
self.assertEqual(proxy, dct)
with self.assertRaises(TypeError):
proxy[1] = 3
self.assertEqual(proxy[1], 2)
dct[1] = 4
self.assertEqual(proxy[1], 4)
self.assertRaises(TypeError, dictproxy_new, [])
self.assertRaises(TypeError, dictproxy_new, 42)
# CRASHES dictproxy_new(NULL)
def test_dict_copy(self):
copy = _testcapi.dict_copy
for dct in {1: 2}, OrderedDict({1: 2}):
dct_copy = copy(dct)
self.assertIs(type(dct_copy), dict)
self.assertEqual(dct_copy, dct)
self.assertRaises(SystemError, copy, UserDict())
self.assertRaises(SystemError, copy, [])
self.assertRaises(SystemError, copy, 42)
self.assertRaises(SystemError, copy, NULL)
def test_dict_clear(self):
clear = _testcapi.dict_clear
dct = {1: 2}
clear(dct)
self.assertEqual(dct, {})
# NOTE: It is not safe to call it with OrderedDict.
# Has no effect for non-dicts.
dct = UserDict({1: 2})
clear(dct)
self.assertEqual(dct, {1: 2})
lst = [1, 2]
clear(lst)
self.assertEqual(lst, [1, 2])
clear(object())
# CRASHES? clear(NULL)
def test_dict_size(self):
size = _testcapi.dict_size
self.assertEqual(size({1: 2}), 1)
self.assertEqual(size(OrderedDict({1: 2})), 1)
self.assertRaises(SystemError, size, UserDict())
self.assertRaises(SystemError, size, [])
self.assertRaises(SystemError, size, 42)
self.assertRaises(SystemError, size, object())
self.assertRaises(SystemError, size, NULL)
def test_dict_getitem(self):
getitem = _testcapi.dict_getitem
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitem(dct, 'a'), 1)
self.assertIs(getitem(dct, 'b'), KeyError)
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
dct2 = DictSubclass(dct)
self.assertEqual(getitem(dct2, 'a'), 1)
self.assertIs(getitem(dct2, 'b'), KeyError)
self.assertIs(getitem({}, []), KeyError) # unhashable
self.assertIs(getitem(42, 'a'), KeyError)
self.assertIs(getitem([1], 0), KeyError)
# CRASHES getitem({}, NULL)
# CRASHES getitem(NULL, 'a')
def test_dict_getitemstring(self):
getitemstring = _testcapi.dict_getitemstring
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitemstring(dct, b'a'), 1)
self.assertIs(getitemstring(dct, b'b'), KeyError)
self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
dct2 = DictSubclass(dct)
self.assertEqual(getitemstring(dct2, b'a'), 1)
self.assertIs(getitemstring(dct2, b'b'), KeyError)
self.assertIs(getitemstring({}, b'\xff'), KeyError)
self.assertIs(getitemstring(42, b'a'), KeyError)
self.assertIs(getitemstring([], b'a'), KeyError)
# CRASHES getitemstring({}, NULL)
# CRASHES getitemstring(NULL, b'a')
def test_dict_getitemref(self):
getitem = _testcapi.dict_getitemref
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitem(dct, 'a'), 1)
self.assertIs(getitem(dct, 'b'), KeyError)
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
dct2 = DictSubclass(dct)
self.assertEqual(getitem(dct2, 'a'), 1)
self.assertIs(getitem(dct2, 'b'), KeyError)
self.assertRaises(SystemError, getitem, 42, 'a')
self.assertRaises(TypeError, getitem, {}, []) # unhashable
self.assertRaises(SystemError, getitem, [], 1)
self.assertRaises(SystemError, getitem, [], 'a')
# CRASHES getitem({}, NULL)
# CRASHES getitem(NULL, 'a')
def test_dict_getitemstringref(self):
getitemstring = _testcapi.dict_getitemstringref
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitemstring(dct, b'a'), 1)
self.assertIs(getitemstring(dct, b'b'), KeyError)
self.assertEqual(getitemstring(dct, '\U0001f40d'.encode()), 2)
dct2 = DictSubclass(dct)
self.assertEqual(getitemstring(dct2, b'a'), 1)
self.assertIs(getitemstring(dct2, b'b'), KeyError)
self.assertRaises(SystemError, getitemstring, 42, b'a')
self.assertRaises(UnicodeDecodeError, getitemstring, {}, b'\xff')
self.assertRaises(SystemError, getitemstring, [], b'a')
# CRASHES getitemstring({}, NULL)
# CRASHES getitemstring(NULL, b'a')
def test_dict_getitemwitherror(self):
getitem = _testcapi.dict_getitemwitherror
dct = {'a': 1, '\U0001f40d': 2}
self.assertEqual(getitem(dct, 'a'), 1)
self.assertIs(getitem(dct, 'b'), KeyError)
self.assertEqual(getitem(dct, '\U0001f40d'), 2)
dct2 = DictSubclass(dct)
self.assertEqual(getitem(dct2, 'a'), 1)
self.assertIs(getitem(dct2, 'b'), KeyError)
self.assertRaises(SystemError, getitem, 42, 'a')
self.assertRaises(TypeError, getitem, {}, []) # unhashable
self.assertRaises(SystemError, getitem, [], 1)
self.assertRaises(SystemError, getitem, [], 'a')
# CRASHES getitem({}, NULL)
# CRASHES getitem(NULL, 'a')
def test_dict_contains(self):
contains = _testcapi.dict_contains
dct = {'a': 1, '\U0001f40d': 2}
self.assertTrue(contains(dct, 'a'))
self.assertFalse(contains(dct, 'b'))
self.assertTrue(contains(dct, '\U0001f40d'))
dct2 = DictSubclass(dct)
self.assertTrue(contains(dct2, 'a'))
self.assertFalse(contains(dct2, 'b'))
self.assertRaises(TypeError, contains, {}, []) # unhashable
# CRASHES contains({}, NULL)
# CRASHES contains(UserDict(), 'a')
# CRASHES contains(42, 'a')
# CRASHES contains(NULL, 'a')
def test_dict_setitem(self):
setitem = _testcapi.dict_setitem
dct = {}
setitem(dct, 'a', 5)
self.assertEqual(dct, {'a': 5})
setitem(dct, '\U0001f40d', 8)
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
dct2 = DictSubclass()
setitem(dct2, 'a', 5)
self.assertEqual(dct2, {'a': 5})
self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable
self.assertRaises(SystemError, setitem, UserDict(), 'a', 5)
self.assertRaises(SystemError, setitem, [1], 0, 5)
self.assertRaises(SystemError, setitem, 42, 'a', 5)
# CRASHES setitem({}, NULL, 5)
# CRASHES setitem({}, 'a', NULL)
# CRASHES setitem(NULL, 'a', 5)
def test_dict_setitemstring(self):
setitemstring = _testcapi.dict_setitemstring
dct = {}
setitemstring(dct, b'a', 5)
self.assertEqual(dct, {'a': 5})
setitemstring(dct, '\U0001f40d'.encode(), 8)
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
dct2 = DictSubclass()
setitemstring(dct2, b'a', 5)
self.assertEqual(dct2, {'a': 5})
self.assertRaises(UnicodeDecodeError, setitemstring, {}, b'\xff', 5)
self.assertRaises(SystemError, setitemstring, UserDict(), b'a', 5)
self.assertRaises(SystemError, setitemstring, 42, b'a', 5)
# CRASHES setitemstring({}, NULL, 5)
# CRASHES setitemstring({}, b'a', NULL)
# CRASHES setitemstring(NULL, b'a', 5)
def test_dict_delitem(self):
delitem = _testcapi.dict_delitem
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
delitem(dct, 'a')
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
self.assertRaises(KeyError, delitem, dct, 'b')
delitem(dct, '\U0001f40d')
self.assertEqual(dct, {'c': 2})
dct2 = DictSubclass({'a': 1, 'c': 2})
delitem(dct2, 'a')
self.assertEqual(dct2, {'c': 2})
self.assertRaises(KeyError, delitem, dct2, 'b')
self.assertRaises(TypeError, delitem, {}, []) # unhashable
self.assertRaises(SystemError, delitem, UserDict({'a': 1}), 'a')
self.assertRaises(SystemError, delitem, [1], 0)
self.assertRaises(SystemError, delitem, 42, 'a')
# CRASHES delitem({}, NULL)
# CRASHES delitem(NULL, 'a')
def test_dict_delitemstring(self):
delitemstring = _testcapi.dict_delitemstring
dct = {'a': 1, 'c': 2, '\U0001f40d': 3}
delitemstring(dct, b'a')
self.assertEqual(dct, {'c': 2, '\U0001f40d': 3})
self.assertRaises(KeyError, delitemstring, dct, b'b')
delitemstring(dct, '\U0001f40d'.encode())
self.assertEqual(dct, {'c': 2})
dct2 = DictSubclass({'a': 1, 'c': 2})
delitemstring(dct2, b'a')
self.assertEqual(dct2, {'c': 2})
self.assertRaises(KeyError, delitemstring, dct2, b'b')
self.assertRaises(UnicodeDecodeError, delitemstring, {}, b'\xff')
self.assertRaises(SystemError, delitemstring, UserDict({'a': 1}), b'a')
self.assertRaises(SystemError, delitemstring, 42, b'a')
# CRASHES delitemstring({}, NULL)
# CRASHES delitemstring(NULL, b'a')
def test_dict_setdefault(self):
setdefault = _testcapi.dict_setdefault
dct = {}
self.assertEqual(setdefault(dct, 'a', 5), 5)
self.assertEqual(dct, {'a': 5})
self.assertEqual(setdefault(dct, 'a', 8), 5)
self.assertEqual(dct, {'a': 5})
dct2 = DictSubclass()
self.assertEqual(setdefault(dct2, 'a', 5), 5)
self.assertEqual(dct2, {'a': 5})
self.assertEqual(setdefault(dct2, 'a', 8), 5)
self.assertEqual(dct2, {'a': 5})
self.assertRaises(TypeError, setdefault, {}, [], 5) # unhashable
self.assertRaises(SystemError, setdefault, UserDict(), 'a', 5)
self.assertRaises(SystemError, setdefault, [1], 0, 5)
self.assertRaises(SystemError, setdefault, 42, 'a', 5)
# CRASHES setdefault({}, NULL, 5)
# CRASHES setdefault({}, 'a', NULL)
# CRASHES setdefault(NULL, 'a', 5)
def test_mapping_keys_valuesitems(self):
class BadMapping(dict):
def keys(self):
return None
def values(self):
return None
def items(self):
return None
dict_obj = {'foo': 1, 'bar': 2, 'spam': 3}
for mapping in [dict_obj, DictSubclass(dict_obj), BadMapping(dict_obj)]:
self.assertListEqual(_testcapi.dict_keys(mapping),
list(dict_obj.keys()))
self.assertListEqual(_testcapi.dict_values(mapping),
list(dict_obj.values()))
self.assertListEqual(_testcapi.dict_items(mapping),
list(dict_obj.items()))
def test_dict_keys_valuesitems_bad_arg(self):
for mapping in UserDict(), [], object():
self.assertRaises(SystemError, _testcapi.dict_keys, mapping)
self.assertRaises(SystemError, _testcapi.dict_values, mapping)
self.assertRaises(SystemError, _testcapi.dict_items, mapping)
def test_dict_next(self):
dict_next = _testcapi.dict_next
self.assertIsNone(dict_next({}, 0))
dct = {'a': 1, 'b': 2, 'c': 3}
pos = 0
pairs = []
while True:
res = dict_next(dct, pos)
if res is None:
break
rc, pos, key, value = res
self.assertEqual(rc, 1)
pairs.append((key, value))
self.assertEqual(pairs, list(dct.items()))
# CRASHES dict_next(NULL, 0)
def test_dict_update(self):
update = _testcapi.dict_update
for cls1 in dict, DictSubclass:
for cls2 in dict, DictSubclass, UserDict:
dct = cls1({'a': 1, 'b': 2})
update(dct, cls2({'b': 3, 'c': 4}))
self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
self.assertRaises(AttributeError, update, {}, [])
self.assertRaises(AttributeError, update, {}, 42)
self.assertRaises(SystemError, update, UserDict(), {})
self.assertRaises(SystemError, update, 42, {})
self.assertRaises(SystemError, update, {}, NULL)
self.assertRaises(SystemError, update, NULL, {})
def test_dict_merge(self):
merge = _testcapi.dict_merge
for cls1 in dict, DictSubclass:
for cls2 in dict, DictSubclass, UserDict:
dct = cls1({'a': 1, 'b': 2})
merge(dct, cls2({'b': 3, 'c': 4}), 0)
self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4})
dct = cls1({'a': 1, 'b': 2})
merge(dct, cls2({'b': 3, 'c': 4}), 1)
self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
self.assertRaises(AttributeError, merge, {}, [], 0)
self.assertRaises(AttributeError, merge, {}, 42, 0)
self.assertRaises(SystemError, merge, UserDict(), {}, 0)
self.assertRaises(SystemError, merge, 42, {}, 0)
self.assertRaises(SystemError, merge, {}, NULL, 0)
self.assertRaises(SystemError, merge, NULL, {}, 0)
def test_dict_mergefromseq2(self):
mergefromseq2 = _testcapi.dict_mergefromseq2
for cls1 in dict, DictSubclass:
for cls2 in list, iter:
dct = cls1({'a': 1, 'b': 2})
mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 0)
self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4})
dct = cls1({'a': 1, 'b': 2})
mergefromseq2(dct, cls2([('b', 3), ('c', 4)]), 1)
self.assertEqual(dct, {'a': 1, 'b': 3, 'c': 4})
self.assertRaises(ValueError, mergefromseq2, {}, [(1,)], 0)
self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0)
self.assertRaises(TypeError, mergefromseq2, {}, [1], 0)
self.assertRaises(TypeError, mergefromseq2, {}, 42, 0)
# CRASHES mergefromseq2(UserDict(), [], 0)
# CRASHES mergefromseq2(42, [], 0)
# CRASHES mergefromseq2({}, NULL, 0)
# CRASHES mergefromseq2(NULL, {}, 0)
if __name__ == "__main__":
unittest.main()

View File

@ -299,137 +299,6 @@ class CAPITest(unittest.TestCase):
def test_buildvalue_N(self):
_testcapi.test_buildvalue_N()
def test_mapping_keys_values_items(self):
class Mapping1(dict):
def keys(self):
return list(super().keys())
def values(self):
return list(super().values())
def items(self):
return list(super().items())
class Mapping2(dict):
def keys(self):
return tuple(super().keys())
def values(self):
return tuple(super().values())
def items(self):
return tuple(super().items())
dict_obj = {'foo': 1, 'bar': 2, 'spam': 3}
for mapping in [{}, OrderedDict(), Mapping1(), Mapping2(),
dict_obj, OrderedDict(dict_obj),
Mapping1(dict_obj), Mapping2(dict_obj)]:
self.assertListEqual(_testcapi.get_mapping_keys(mapping),
list(mapping.keys()))
self.assertListEqual(_testcapi.get_mapping_values(mapping),
list(mapping.values()))
self.assertListEqual(_testcapi.get_mapping_items(mapping),
list(mapping.items()))
def test_mapping_keys_values_items_bad_arg(self):
self.assertRaises(AttributeError, _testcapi.get_mapping_keys, None)
self.assertRaises(AttributeError, _testcapi.get_mapping_values, None)
self.assertRaises(AttributeError, _testcapi.get_mapping_items, None)
class BadMapping:
def keys(self):
return None
def values(self):
return None
def items(self):
return None
bad_mapping = BadMapping()
self.assertRaises(TypeError, _testcapi.get_mapping_keys, bad_mapping)
self.assertRaises(TypeError, _testcapi.get_mapping_values, bad_mapping)
self.assertRaises(TypeError, _testcapi.get_mapping_items, bad_mapping)
def test_mapping_has_key(self):
dct = {'a': 1}
self.assertTrue(_testcapi.mapping_has_key(dct, 'a'))
self.assertFalse(_testcapi.mapping_has_key(dct, 'b'))
class SubDict(dict):
pass
dct2 = SubDict({'a': 1})
self.assertTrue(_testcapi.mapping_has_key(dct2, 'a'))
self.assertFalse(_testcapi.mapping_has_key(dct2, 'b'))
def test_sequence_set_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
_testcapi.sequence_set_slice(data, 1, 3, [8, 9])
data_copy[1:3] = [8, 9]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 8, 9, 4, 5])
# Custom class:
class Custom:
def __setitem__(self, index, value):
self.index = index
self.value = value
c = Custom()
_testcapi.sequence_set_slice(c, 0, 5, 'abc')
self.assertEqual(c.index, slice(0, 5))
self.assertEqual(c.value, 'abc')
# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(bad_seq1, 1, 3, (8, 9))
self.assertEqual(bad_seq1, (1, 2, 3, 4))
bad_seq2 = 'abcd'
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(bad_seq2, 1, 3, 'xy')
self.assertEqual(bad_seq2, 'abcd')
# Not a sequence:
with self.assertRaises(TypeError):
_testcapi.sequence_set_slice(None, 1, 3, 'xy')
def test_sequence_del_slice(self):
# Correct case:
data = [1, 2, 3, 4, 5]
data_copy = data.copy()
_testcapi.sequence_del_slice(data, 1, 3)
del data_copy[1:3]
self.assertEqual(data, data_copy)
self.assertEqual(data, [1, 4, 5])
# Custom class:
class Custom:
def __delitem__(self, index):
self.index = index
c = Custom()
_testcapi.sequence_del_slice(c, 0, 5)
self.assertEqual(c.index, slice(0, 5))
# Immutable sequences must raise:
bad_seq1 = (1, 2, 3, 4)
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(bad_seq1, 1, 3)
self.assertEqual(bad_seq1, (1, 2, 3, 4))
bad_seq2 = 'abcd'
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(bad_seq2, 1, 3)
self.assertEqual(bad_seq2, 'abcd')
# Not a sequence:
with self.assertRaises(TypeError):
_testcapi.sequence_del_slice(None, 1, 3)
mapping = {1: 'a', 2: 'b', 3: 'c'}
with self.assertRaises(KeyError):
_testcapi.sequence_del_slice(mapping, 1, 3)
self.assertEqual(mapping, {1: 'a', 2: 'b', 3: 'c'})
@unittest.skipUnless(hasattr(_testcapi, 'negative_refcount'),
'need _testcapi.negative_refcount')
def test_negative_refcount(self):

View File

@ -455,8 +455,8 @@ class ClassTests(unittest.TestCase):
self.attr = 1
a = A()
self.assertEqual(_testcapi.hasattr_string(a, "attr"), True)
self.assertEqual(_testcapi.hasattr_string(a, "noattr"), False)
self.assertEqual(_testcapi.object_hasattrstring(a, b"attr"), 1)
self.assertEqual(_testcapi.object_hasattrstring(a, b"noattr"), 0)
self.assertIsNone(sys.exception())
def testDel(self):

View File

@ -0,0 +1,2 @@
Add the C API test for functions in the Mapping Protocol, the Sequence
Protocol and some functions in the Object Protocol.

View File

@ -159,7 +159,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/unicode.c _testcapi/dict.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyos.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
# Some testing modules MUST be built as shared libraries.

View File

@ -0,0 +1,640 @@
#include <stddef.h> // ptrdiff_t
#include "parts.h"
#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0);
#define RETURN_INT(value) do { \
int _ret = (value); \
if (_ret == -1) { \
return NULL; \
} \
return PyLong_FromLong(_ret); \
} while (0)
#define RETURN_SIZE(value) do { \
Py_ssize_t _ret = (value); \
if (_ret == -1) { \
return NULL; \
} \
return PyLong_FromSsize_t(_ret); \
} while (0)
static PyObject *
object_getattr(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
return PyObject_GetAttr(obj, attr_name);
}
static PyObject *
object_getattrstring(PyObject *self, PyObject *args)
{
PyObject *obj;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
return PyObject_GetAttrString(obj, attr_name);
}
static PyObject *
object_getoptionalattr(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name, *value;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
switch (PyObject_GetOptionalAttr(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_AttributeError);
case 1:
return value;
default:
Py_FatalError("PyObject_GetOptionalAttr() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
object_getoptionalattrstring(PyObject *self, PyObject *args)
{
PyObject *obj, *value;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
switch (PyObject_GetOptionalAttrString(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_AttributeError);
case 1:
return value;
default:
Py_FatalError("PyObject_GetOptionalAttrString() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
object_hasattr(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
return PyLong_FromLong(PyObject_HasAttr(obj, attr_name));
}
static PyObject *
object_hasattrstring(PyObject *self, PyObject *args)
{
PyObject *obj;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
return PyLong_FromLong(PyObject_HasAttrString(obj, attr_name));
}
static PyObject *
object_setattr(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name, *value;
if (!PyArg_ParseTuple(args, "OOO", &obj, &attr_name, &value)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
NULLABLE(value);
RETURN_INT(PyObject_SetAttr(obj, attr_name, value));
}
static PyObject *
object_setattrstring(PyObject *self, PyObject *args)
{
PyObject *obj, *value;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#O", &obj, &attr_name, &size, &value)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(value);
RETURN_INT(PyObject_SetAttrString(obj, attr_name, value));
}
static PyObject *
object_delattr(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
RETURN_INT(PyObject_DelAttr(obj, attr_name));
}
static PyObject *
object_delattrstring(PyObject *self, PyObject *args)
{
PyObject *obj;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
RETURN_INT(PyObject_DelAttrString(obj, attr_name));
}
static PyObject *
mapping_check(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyLong_FromLong(PyMapping_Check(obj));
}
static PyObject *
mapping_size(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
RETURN_SIZE(PyMapping_Size(obj));
}
static PyObject *
mapping_length(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
RETURN_SIZE(PyMapping_Length(obj));
}
static PyObject *
object_getitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
return PyObject_GetItem(mapping, key);
}
static PyObject *
mapping_getitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) {
return NULL;
}
NULLABLE(mapping);
return PyMapping_GetItemString(mapping, key);
}
static PyObject *
mapping_getoptionalitem(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name, *value;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
switch (PyMapping_GetOptionalItem(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_KeyError);
case 1:
return value;
default:
Py_FatalError("PyMapping_GetOptionalItem() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
mapping_getoptionalitemstring(PyObject *self, PyObject *args)
{
PyObject *obj, *value;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
switch (PyMapping_GetOptionalItemString(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_KeyError);
case 1:
return value;
default:
Py_FatalError("PyMapping_GetOptionalItemString() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
mapping_haskey(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
return PyLong_FromLong(PyMapping_HasKey(mapping, key));
}
static PyObject *
mapping_haskeystring(PyObject *self, PyObject *args)
{
PyObject *mapping;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) {
return NULL;
}
NULLABLE(mapping);
return PyLong_FromLong(PyMapping_HasKeyString(mapping, key));
}
static PyObject *
object_setitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key, *value;
if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &value)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
NULLABLE(value);
RETURN_INT(PyObject_SetItem(mapping, key, value));
}
static PyObject *
mapping_setitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping, *value;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#O", &mapping, &key, &size, &value)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(value);
RETURN_INT(PyMapping_SetItemString(mapping, key, value));
}
static PyObject *
object_delitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
RETURN_INT(PyObject_DelItem(mapping, key));
}
static PyObject *
mapping_delitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
RETURN_INT(PyMapping_DelItem(mapping, key));
}
static PyObject *
mapping_delitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) {
return NULL;
}
NULLABLE(mapping);
RETURN_INT(PyMapping_DelItemString(mapping, key));
}
static PyObject *
mapping_keys(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyMapping_Keys(obj);
}
static PyObject *
mapping_values(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyMapping_Values(obj);
}
static PyObject *
mapping_items(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyMapping_Items(obj);
}
static PyObject *
sequence_check(PyObject* self, PyObject *obj)
{
NULLABLE(obj);
return PyLong_FromLong(PySequence_Check(obj));
}
static PyObject *
sequence_size(PyObject* self, PyObject *obj)
{
NULLABLE(obj);
RETURN_SIZE(PySequence_Size(obj));
}
static PyObject *
sequence_length(PyObject* self, PyObject *obj)
{
NULLABLE(obj);
RETURN_SIZE(PySequence_Length(obj));
}
static PyObject *
sequence_concat(PyObject *self, PyObject *args)
{
PyObject *seq1, *seq2;
if (!PyArg_ParseTuple(args, "OO", &seq1, &seq2)) {
return NULL;
}
NULLABLE(seq1);
NULLABLE(seq2);
return PySequence_Concat(seq1, seq2);
}
static PyObject *
sequence_repeat(PyObject *self, PyObject *args)
{
PyObject *seq;
Py_ssize_t count;
if (!PyArg_ParseTuple(args, "On", &seq, &count)) {
return NULL;
}
NULLABLE(seq);
return PySequence_Repeat(seq, count);
}
static PyObject *
sequence_inplaceconcat(PyObject *self, PyObject *args)
{
PyObject *seq1, *seq2;
if (!PyArg_ParseTuple(args, "OO", &seq1, &seq2)) {
return NULL;
}
NULLABLE(seq1);
NULLABLE(seq2);
return PySequence_InPlaceConcat(seq1, seq2);
}
static PyObject *
sequence_inplacerepeat(PyObject *self, PyObject *args)
{
PyObject *seq;
Py_ssize_t count;
if (!PyArg_ParseTuple(args, "On", &seq, &count)) {
return NULL;
}
NULLABLE(seq);
return PySequence_InPlaceRepeat(seq, count);
}
static PyObject *
sequence_getitem(PyObject *self, PyObject *args)
{
PyObject *seq;
Py_ssize_t i;
if (!PyArg_ParseTuple(args, "On", &seq, &i)) {
return NULL;
}
NULLABLE(seq);
return PySequence_GetItem(seq, i);
}
static PyObject *
sequence_setitem(PyObject *self, PyObject *args)
{
Py_ssize_t i;
PyObject *seq, *val;
if (!PyArg_ParseTuple(args, "OnO", &seq, &i, &val)) {
return NULL;
}
NULLABLE(seq);
NULLABLE(val);
RETURN_INT(PySequence_SetItem(seq, i, val));
}
static PyObject *
sequence_delitem(PyObject *self, PyObject *args)
{
Py_ssize_t i;
PyObject *seq;
if (!PyArg_ParseTuple(args, "On", &seq, &i)) {
return NULL;
}
NULLABLE(seq);
RETURN_INT(PySequence_DelItem(seq, i));
}
static PyObject *
sequence_setslice(PyObject* self, PyObject *args)
{
PyObject *sequence, *obj;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) {
return NULL;
}
NULLABLE(sequence);
NULLABLE(obj);
RETURN_INT(PySequence_SetSlice(sequence, i1, i2, obj));
}
static PyObject *
sequence_delslice(PyObject *self, PyObject *args)
{
PyObject *sequence;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) {
return NULL;
}
NULLABLE(sequence);
RETURN_INT(PySequence_DelSlice(sequence, i1, i2));
}
static PyObject *
sequence_count(PyObject *self, PyObject *args)
{
PyObject *seq, *value;
if (!PyArg_ParseTuple(args, "OO", &seq, &value)) {
return NULL;
}
NULLABLE(seq);
NULLABLE(value);
RETURN_SIZE(PySequence_Count(seq, value));
}
static PyObject *
sequence_contains(PyObject *self, PyObject *args)
{
PyObject *seq, *value;
if (!PyArg_ParseTuple(args, "OO", &seq, &value)) {
return NULL;
}
NULLABLE(seq);
NULLABLE(value);
RETURN_INT(PySequence_Contains(seq, value));
}
static PyObject *
sequence_index(PyObject *self, PyObject *args)
{
PyObject *seq, *value;
if (!PyArg_ParseTuple(args, "OO", &seq, &value)) {
return NULL;
}
NULLABLE(seq);
NULLABLE(value);
RETURN_SIZE(PySequence_Index(seq, value));
}
static PyObject *
sequence_list(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PySequence_List(obj);
}
static PyObject *
sequence_tuple(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PySequence_Tuple(obj);
}
static PyMethodDef test_methods[] = {
{"object_getattr", object_getattr, METH_VARARGS},
{"object_getattrstring", object_getattrstring, METH_VARARGS},
{"object_getoptionalattr", object_getoptionalattr, METH_VARARGS},
{"object_getoptionalattrstring", object_getoptionalattrstring, METH_VARARGS},
{"object_hasattr", object_hasattr, METH_VARARGS},
{"object_hasattrstring", object_hasattrstring, METH_VARARGS},
{"object_setattr", object_setattr, METH_VARARGS},
{"object_setattrstring", object_setattrstring, METH_VARARGS},
{"object_delattr", object_delattr, METH_VARARGS},
{"object_delattrstring", object_delattrstring, METH_VARARGS},
{"mapping_check", mapping_check, METH_O},
{"mapping_size", mapping_size, METH_O},
{"mapping_length", mapping_length, METH_O},
{"object_getitem", object_getitem, METH_VARARGS},
{"mapping_getitemstring", mapping_getitemstring, METH_VARARGS},
{"mapping_getoptionalitem", mapping_getoptionalitem, METH_VARARGS},
{"mapping_getoptionalitemstring", mapping_getoptionalitemstring, METH_VARARGS},
{"mapping_haskey", mapping_haskey, METH_VARARGS},
{"mapping_haskeystring", mapping_haskeystring, METH_VARARGS},
{"object_setitem", object_setitem, METH_VARARGS},
{"mapping_setitemstring", mapping_setitemstring, METH_VARARGS},
{"object_delitem", object_delitem, METH_VARARGS},
{"mapping_delitem", mapping_delitem, METH_VARARGS},
{"mapping_delitemstring", mapping_delitemstring, METH_VARARGS},
{"mapping_keys", mapping_keys, METH_O},
{"mapping_values", mapping_values, METH_O},
{"mapping_items", mapping_items, METH_O},
{"sequence_check", sequence_check, METH_O},
{"sequence_size", sequence_size, METH_O},
{"sequence_length", sequence_length, METH_O},
{"sequence_concat", sequence_concat, METH_VARARGS},
{"sequence_repeat", sequence_repeat, METH_VARARGS},
{"sequence_inplaceconcat", sequence_inplaceconcat, METH_VARARGS},
{"sequence_inplacerepeat", sequence_inplacerepeat, METH_VARARGS},
{"sequence_getitem", sequence_getitem, METH_VARARGS},
{"sequence_setitem", sequence_setitem, METH_VARARGS},
{"sequence_delitem", sequence_delitem, METH_VARARGS},
{"sequence_setslice", sequence_setslice, METH_VARARGS},
{"sequence_delslice", sequence_delslice, METH_VARARGS},
{"sequence_count", sequence_count, METH_VARARGS},
{"sequence_contains", sequence_contains, METH_VARARGS},
{"sequence_index", sequence_index, METH_VARARGS},
{"sequence_list", sequence_list, METH_O},
{"sequence_tuple", sequence_tuple, METH_O},
{NULL},
};
int
_PyTestCapi_Init_Abstract(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}
return 0;
}

376
Modules/_testcapi/dict.c Normal file
View File

@ -0,0 +1,376 @@
#include <stddef.h> // ptrdiff_t
#include "parts.h"
#define NULLABLE(x) do { if (x == Py_None) x = NULL; } while (0);
#define RETURN_INT(value) do { \
int _ret = (value); \
if (_ret == -1) { \
return NULL; \
} \
return PyLong_FromLong(_ret); \
} while (0)
#define RETURN_SIZE(value) do { \
Py_ssize_t _ret = (value); \
if (_ret == -1) { \
return NULL; \
} \
return PyLong_FromSsize_t(_ret); \
} while (0)
static PyObject *
dict_check(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyLong_FromLong(PyDict_Check(obj));
}
static PyObject *
dict_checkexact(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyLong_FromLong(PyDict_CheckExact(obj));
}
static PyObject *
dict_new(PyObject *self, PyObject *Py_UNUSED(ignored))
{
return PyDict_New();
}
static PyObject *
dictproxy_new(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyDictProxy_New(obj);
}
static PyObject *
dict_clear(PyObject *self, PyObject *obj)
{
PyDict_Clear(obj);
Py_RETURN_NONE;
}
static PyObject *
dict_copy(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyDict_Copy(obj);
}
static PyObject *
dict_contains(PyObject *self, PyObject *args)
{
PyObject *obj, *key;
if (!PyArg_ParseTuple(args, "OO", &obj, &key)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(key);
RETURN_INT(PyDict_Contains(obj, key));
}
static PyObject *
dict_size(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
RETURN_SIZE(PyDict_Size(obj));
}
static PyObject *
dict_getitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
PyObject *value = PyDict_GetItem(mapping, key);
if (value == NULL) {
if (PyErr_Occurred()) {
return NULL;
}
return Py_NewRef(PyExc_KeyError);
}
return Py_NewRef(value);
}
static PyObject *
dict_getitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) {
return NULL;
}
NULLABLE(mapping);
PyObject *value = PyDict_GetItemString(mapping, key);
if (value == NULL) {
if (PyErr_Occurred()) {
return NULL;
}
return Py_NewRef(PyExc_KeyError);
}
return Py_NewRef(value);
}
static PyObject *
dict_getitemwitherror(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
PyObject *value = PyDict_GetItemWithError(mapping, key);
if (value == NULL) {
if (PyErr_Occurred()) {
return NULL;
}
return Py_NewRef(PyExc_KeyError);
}
return Py_NewRef(value);
}
static PyObject *
dict_getitemref(PyObject *self, PyObject *args)
{
PyObject *obj, *attr_name, *value;
if (!PyArg_ParseTuple(args, "OO", &obj, &attr_name)) {
return NULL;
}
NULLABLE(obj);
NULLABLE(attr_name);
switch (PyDict_GetItemRef(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_KeyError);
case 1:
return value;
default:
Py_FatalError("PyMapping_GetItemRef() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
dict_getitemstringref(PyObject *self, PyObject *args)
{
PyObject *obj, *value;
const char *attr_name;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &obj, &attr_name, &size)) {
return NULL;
}
NULLABLE(obj);
switch (PyDict_GetItemStringRef(obj, attr_name, &value)) {
case -1:
assert(value == NULL);
return NULL;
case 0:
assert(value == NULL);
return Py_NewRef(PyExc_KeyError);
case 1:
return value;
default:
Py_FatalError("PyDict_GetItemStringRef() returned invalid code");
Py_UNREACHABLE();
}
}
static PyObject *
dict_setitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key, *value;
if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &value)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
NULLABLE(value);
RETURN_INT(PyDict_SetItem(mapping, key, value));
}
static PyObject *
dict_setitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping, *value;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#O", &mapping, &key, &size, &value)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(value);
RETURN_INT(PyDict_SetItemString(mapping, key, value));
}
static PyObject *
dict_setdefault(PyObject *self, PyObject *args)
{
PyObject *mapping, *key, *defaultobj;
if (!PyArg_ParseTuple(args, "OOO", &mapping, &key, &defaultobj)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
NULLABLE(defaultobj);
return PyDict_SetDefault(mapping, key, defaultobj);
}
static PyObject *
dict_delitem(PyObject *self, PyObject *args)
{
PyObject *mapping, *key;
if (!PyArg_ParseTuple(args, "OO", &mapping, &key)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(key);
RETURN_INT(PyDict_DelItem(mapping, key));
}
static PyObject *
dict_delitemstring(PyObject *self, PyObject *args)
{
PyObject *mapping;
const char *key;
Py_ssize_t size;
if (!PyArg_ParseTuple(args, "Oz#", &mapping, &key, &size)) {
return NULL;
}
NULLABLE(mapping);
RETURN_INT(PyDict_DelItemString(mapping, key));
}
static PyObject *
dict_keys(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyDict_Keys(obj);
}
static PyObject *
dict_values(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyDict_Values(obj);
}
static PyObject *
dict_items(PyObject *self, PyObject *obj)
{
NULLABLE(obj);
return PyDict_Items(obj);
}
static PyObject *
dict_next(PyObject *self, PyObject *args)
{
PyObject *mapping, *key, *value;
Py_ssize_t pos;
if (!PyArg_ParseTuple(args, "On", &mapping, &pos)) {
return NULL;
}
NULLABLE(mapping);
int rc = PyDict_Next(mapping, &pos, &key, &value);
if (rc != 0) {
return Py_BuildValue("inOO", rc, pos, key, value);
}
if (PyErr_Occurred()) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
dict_merge(PyObject *self, PyObject *args)
{
PyObject *mapping, *mapping2;
int override;
if (!PyArg_ParseTuple(args, "OOi", &mapping, &mapping2, &override)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(mapping2);
RETURN_INT(PyDict_Merge(mapping, mapping2, override));
}
static PyObject *
dict_update(PyObject *self, PyObject *args)
{
PyObject *mapping, *mapping2;
if (!PyArg_ParseTuple(args, "OO", &mapping, &mapping2)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(mapping2);
RETURN_INT(PyDict_Update(mapping, mapping2));
}
static PyObject *
dict_mergefromseq2(PyObject *self, PyObject *args)
{
PyObject *mapping, *seq;
int override;
if (!PyArg_ParseTuple(args, "OOi", &mapping, &seq, &override)) {
return NULL;
}
NULLABLE(mapping);
NULLABLE(seq);
RETURN_INT(PyDict_MergeFromSeq2(mapping, seq, override));
}
static PyMethodDef test_methods[] = {
{"dict_check", dict_check, METH_O},
{"dict_checkexact", dict_checkexact, METH_O},
{"dict_new", dict_new, METH_NOARGS},
{"dictproxy_new", dictproxy_new, METH_O},
{"dict_clear", dict_clear, METH_O},
{"dict_copy", dict_copy, METH_O},
{"dict_size", dict_size, METH_O},
{"dict_getitem", dict_getitem, METH_VARARGS},
{"dict_getitemwitherror", dict_getitemwitherror, METH_VARARGS},
{"dict_getitemstring", dict_getitemstring, METH_VARARGS},
{"dict_getitemref", dict_getitemref, METH_VARARGS},
{"dict_getitemstringref", dict_getitemstringref, METH_VARARGS},
{"dict_contains", dict_contains, METH_VARARGS},
{"dict_setitem", dict_setitem, METH_VARARGS},
{"dict_setitemstring", dict_setitemstring, METH_VARARGS},
{"dict_delitem", dict_delitem, METH_VARARGS},
{"dict_delitemstring", dict_delitemstring, METH_VARARGS},
{"dict_setdefault", dict_setdefault, METH_VARARGS},
{"dict_keys", dict_keys, METH_O},
{"dict_values", dict_values, METH_O},
{"dict_items", dict_items, METH_O},
{"dict_next", dict_next, METH_VARARGS},
{"dict_merge", dict_merge, METH_VARARGS},
{"dict_update", dict_update, METH_VARARGS},
{"dict_mergefromseq2", dict_mergefromseq2, METH_VARARGS},
{NULL},
};
int
_PyTestCapi_Init_Dict(PyObject *m)
{
if (PyModule_AddFunctions(m, test_methods) < 0) {
return -1;
}
return 0;
}

View File

@ -26,6 +26,7 @@
int _PyTestCapi_Init_Vectorcall(PyObject *module);
int _PyTestCapi_Init_Heaptype(PyObject *module);
int _PyTestCapi_Init_Abstract(PyObject *module);
int _PyTestCapi_Init_Unicode(PyObject *module);
int _PyTestCapi_Init_GetArgs(PyObject *module);
int _PyTestCapi_Init_DateTime(PyObject *module);
@ -34,6 +35,7 @@ int _PyTestCapi_Init_Mem(PyObject *module);
int _PyTestCapi_Init_Watchers(PyObject *module);
int _PyTestCapi_Init_Long(PyObject *module);
int _PyTestCapi_Init_Float(PyObject *module);
int _PyTestCapi_Init_Dict(PyObject *module);
int _PyTestCapi_Init_Structmember(PyObject *module);
int _PyTestCapi_Init_Exceptions(PyObject *module);
int _PyTestCapi_Init_Code(PyObject *module);

View File

@ -1983,7 +1983,7 @@ return_result_with_error(PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
static PyObject*
static PyObject *
getitem_with_error(PyObject *self, PyObject *args)
{
PyObject *map, *key;
@ -2060,90 +2060,6 @@ py_w_stopcode(PyObject *self, PyObject *args)
#endif
static PyObject *
get_mapping_keys(PyObject* self, PyObject *obj)
{
return PyMapping_Keys(obj);
}
static PyObject *
get_mapping_values(PyObject* self, PyObject *obj)
{
return PyMapping_Values(obj);
}
static PyObject *
get_mapping_items(PyObject* self, PyObject *obj)
{
return PyMapping_Items(obj);
}
static PyObject *
test_mapping_has_key_string(PyObject *self, PyObject *Py_UNUSED(args))
{
PyObject *context = PyDict_New();
PyObject *val = PyLong_FromLong(1);
// Since this uses `const char*` it is easier to test this in C:
PyDict_SetItemString(context, "a", val);
if (!PyMapping_HasKeyString(context, "a")) {
PyErr_SetString(PyExc_RuntimeError,
"Existing mapping key does not exist");
return NULL;
}
if (PyMapping_HasKeyString(context, "b")) {
PyErr_SetString(PyExc_RuntimeError,
"Missing mapping key exists");
return NULL;
}
Py_DECREF(val);
Py_DECREF(context);
Py_RETURN_NONE;
}
static PyObject *
mapping_has_key(PyObject* self, PyObject *args)
{
PyObject *context, *key;
if (!PyArg_ParseTuple(args, "OO", &context, &key)) {
return NULL;
}
return PyLong_FromLong(PyMapping_HasKey(context, key));
}
static PyObject *
sequence_set_slice(PyObject* self, PyObject *args)
{
PyObject *sequence, *obj;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "OnnO", &sequence, &i1, &i2, &obj)) {
return NULL;
}
int res = PySequence_SetSlice(sequence, i1, i2, obj);
if (res == -1) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
sequence_del_slice(PyObject* self, PyObject *args)
{
PyObject *sequence;
Py_ssize_t i1, i2;
if (!PyArg_ParseTuple(args, "Onn", &sequence, &i1, &i2)) {
return NULL;
}
int res = PySequence_DelSlice(sequence, i1, i2);
if (res == -1) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
test_pythread_tss_key_state(PyObject *self, PyObject *args)
{
@ -2247,72 +2163,6 @@ negative_refcount(PyObject *self, PyObject *Py_UNUSED(args))
#endif
static PyObject *
sequence_getitem(PyObject *self, PyObject *args)
{
PyObject *seq;
Py_ssize_t i;
if (!PyArg_ParseTuple(args, "On", &seq, &i)) {
return NULL;
}
return PySequence_GetItem(seq, i);
}
static PyObject *
sequence_setitem(PyObject *self, PyObject *args)
{
Py_ssize_t i;
PyObject *seq, *val;
if (!PyArg_ParseTuple(args, "OnO", &seq, &i, &val)) {
return NULL;
}
if (PySequence_SetItem(seq, i, val)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
sequence_delitem(PyObject *self, PyObject *args)
{
Py_ssize_t i;
PyObject *seq;
if (!PyArg_ParseTuple(args, "On", &seq, &i)) {
return NULL;
}
if (PySequence_DelItem(seq, i)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
hasattr_string(PyObject *self, PyObject* args)
{
PyObject* obj;
PyObject* attr_name;
if (!PyArg_UnpackTuple(args, "hasattr_string", 2, 2, &obj, &attr_name)) {
return NULL;
}
if (!PyUnicode_Check(attr_name)) {
PyErr_SetString(PyExc_TypeError, "attribute name must a be string");
return PyErr_Occurred();
}
const char *name_str = PyUnicode_AsUTF8(attr_name);
if (PyObject_HasAttrString(obj, name_str)) {
Py_RETURN_TRUE;
}
else {
Py_RETURN_FALSE;
}
}
/* Functions for testing C calling conventions (METH_*) are named meth_*,
* e.g. "meth_varargs" for METH_VARARGS.
*
@ -3736,23 +3586,12 @@ static PyMethodDef TestMethods[] = {
#ifdef W_STOPCODE
{"W_STOPCODE", py_w_stopcode, METH_VARARGS},
#endif
{"get_mapping_keys", get_mapping_keys, METH_O},
{"get_mapping_values", get_mapping_values, METH_O},
{"get_mapping_items", get_mapping_items, METH_O},
{"test_mapping_has_key_string", test_mapping_has_key_string, METH_NOARGS},
{"mapping_has_key", mapping_has_key, METH_VARARGS},
{"sequence_set_slice", sequence_set_slice, METH_VARARGS},
{"sequence_del_slice", sequence_del_slice, METH_VARARGS},
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
{"hamt", new_hamt, METH_NOARGS},
{"bad_get", _PyCFunction_CAST(bad_get), METH_FASTCALL},
#ifdef Py_REF_DEBUG
{"negative_refcount", negative_refcount, METH_NOARGS},
#endif
{"sequence_getitem", sequence_getitem, METH_VARARGS},
{"sequence_setitem", sequence_setitem, METH_VARARGS},
{"sequence_delitem", sequence_delitem, METH_VARARGS},
{"hasattr_string", hasattr_string, METH_VARARGS},
{"meth_varargs", meth_varargs, METH_VARARGS},
{"meth_varargs_keywords", _PyCFunction_CAST(meth_varargs_keywords), METH_VARARGS|METH_KEYWORDS},
{"meth_o", meth_o, METH_O},
@ -4394,6 +4233,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_Heaptype(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Abstract(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Unicode(m) < 0) {
return NULL;
}
@ -4418,6 +4260,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_Float(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Dict(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Structmember(m) < 0) {
return NULL;
}

View File

@ -99,7 +99,9 @@
<ClCompile Include="..\Modules\_testcapi\vectorcall_limited.c" />
<ClCompile Include="..\Modules\_testcapi\heaptype.c" />
<ClCompile Include="..\Modules\_testcapi\heaptype_relative.c" />
<ClCompile Include="..\Modules\_testcapi\abstract.c" />
<ClCompile Include="..\Modules\_testcapi\unicode.c" />
<ClCompile Include="..\Modules\_testcapi\dict.c" />
<ClCompile Include="..\Modules\_testcapi\datetime.c" />
<ClCompile Include="..\Modules\_testcapi\docstring.c" />
<ClCompile Include="..\Modules\_testcapi\mem.c" />

View File

@ -27,9 +27,15 @@
<ClCompile Include="..\Modules\_testcapi\heaptype_relative.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\abstract.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\unicode.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\dict.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\datetime.c">
<Filter>Source Files</Filter>
</ClCompile>