mirror of
https://github.com/python/cpython.git
synced 2024-11-30 18:51:15 +01:00
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:
parent
8579327879
commit
16c9415fba
@ -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
|
||||
|
722
Lib/test/test_capi/test_abstract.py
Normal file
722
Lib/test/test_capi/test_abstract.py
Normal 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()
|
413
Lib/test/test_capi/test_dict.py
Normal file
413
Lib/test/test_capi/test_dict.py
Normal 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()
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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.
|
@ -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.
|
||||
|
640
Modules/_testcapi/abstract.c
Normal file
640
Modules/_testcapi/abstract.c
Normal 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
376
Modules/_testcapi/dict.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user