Compare commits
5 Commits
11276cd9c4
...
607501abb4
Author | SHA1 | Date |
---|---|---|
Serhiy Storchaka | 607501abb4 | |
Serhiy Storchaka | a25011be8c | |
Erlend Egeberg Aasland | 75bf107c62 | |
Ken Jin | 49cd68fb1e | |
Kurochan | d9142831ba |
|
@ -174,7 +174,7 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384):
|
||||||
The file is read and scanned in chunks of chunksize bytes.
|
The file is read and scanned in chunks of chunksize bytes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if executable is None:
|
if not executable:
|
||||||
try:
|
try:
|
||||||
ver = os.confstr('CS_GNU_LIBC_VERSION')
|
ver = os.confstr('CS_GNU_LIBC_VERSION')
|
||||||
# parse 'glibc 2.28' as ('glibc', '2.28')
|
# parse 'glibc 2.28' as ('glibc', '2.28')
|
||||||
|
|
|
@ -69,6 +69,10 @@ def count_opcode(code, pickle):
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def identity(x):
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
class UnseekableIO(io.BytesIO):
|
class UnseekableIO(io.BytesIO):
|
||||||
def peek(self, *args):
|
def peek(self, *args):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -138,11 +142,12 @@ class E(C):
|
||||||
def __getinitargs__(self):
|
def __getinitargs__(self):
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
class H(object):
|
# Simple mutable object.
|
||||||
|
class Object:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Hashable mutable key
|
# Hashable immutable key object containing unheshable mutable data.
|
||||||
class K(object):
|
class K:
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
@ -157,10 +162,6 @@ __main__.D = D
|
||||||
D.__module__ = "__main__"
|
D.__module__ = "__main__"
|
||||||
__main__.E = E
|
__main__.E = E
|
||||||
E.__module__ = "__main__"
|
E.__module__ = "__main__"
|
||||||
__main__.H = H
|
|
||||||
H.__module__ = "__main__"
|
|
||||||
__main__.K = K
|
|
||||||
K.__module__ = "__main__"
|
|
||||||
|
|
||||||
class myint(int):
|
class myint(int):
|
||||||
def __init__(self, x):
|
def __init__(self, x):
|
||||||
|
@ -1496,54 +1497,182 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
got = filelike.getvalue()
|
got = filelike.getvalue()
|
||||||
self.assertEqual(expected, got)
|
self.assertEqual(expected, got)
|
||||||
|
|
||||||
def test_recursive_list(self):
|
def _test_recursive_list(self, cls, aslist=identity, minprotocol=0):
|
||||||
l = []
|
# List containing itself.
|
||||||
|
l = cls()
|
||||||
l.append(l)
|
l.append(l)
|
||||||
for proto in protocols:
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(l, proto)
|
s = self.dumps(l, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, list)
|
self.assertIsInstance(x, cls)
|
||||||
self.assertEqual(len(x), 1)
|
y = aslist(x)
|
||||||
self.assertIs(x[0], x)
|
self.assertEqual(len(y), 1)
|
||||||
|
self.assertIs(y[0], x)
|
||||||
|
|
||||||
def test_recursive_tuple_and_list(self):
|
def test_recursive_list(self):
|
||||||
t = ([],)
|
self._test_recursive_list(list)
|
||||||
|
|
||||||
|
def test_recursive_list_subclass(self):
|
||||||
|
self._test_recursive_list(MyList, minprotocol=2)
|
||||||
|
|
||||||
|
def test_recursive_list_like(self):
|
||||||
|
self._test_recursive_list(REX_six, aslist=lambda x: x.items)
|
||||||
|
|
||||||
|
def _test_recursive_tuple_and_list(self, cls, aslist=identity, minprotocol=0):
|
||||||
|
# Tuple containing a list containing the original tuple.
|
||||||
|
t = (cls(),)
|
||||||
t[0].append(t)
|
t[0].append(t)
|
||||||
for proto in protocols:
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(t, proto)
|
s = self.dumps(t, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, tuple)
|
self.assertIsInstance(x, tuple)
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertIsInstance(x[0], list)
|
self.assertIsInstance(x[0], cls)
|
||||||
self.assertEqual(len(x[0]), 1)
|
y = aslist(x[0])
|
||||||
self.assertIs(x[0][0], x)
|
self.assertEqual(len(y), 1)
|
||||||
|
self.assertIs(y[0], x)
|
||||||
|
|
||||||
|
# List containing a tuple containing the original list.
|
||||||
|
t, = t
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, cls)
|
||||||
|
y = aslist(x)
|
||||||
|
self.assertEqual(len(y), 1)
|
||||||
|
self.assertIsInstance(y[0], tuple)
|
||||||
|
self.assertEqual(len(y[0]), 1)
|
||||||
|
self.assertIs(y[0][0], x)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_list(self):
|
||||||
|
self._test_recursive_tuple_and_list(list)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_list_subclass(self):
|
||||||
|
self._test_recursive_tuple_and_list(MyList, minprotocol=2)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_list_like(self):
|
||||||
|
self._test_recursive_tuple_and_list(REX_six, aslist=lambda x: x.items)
|
||||||
|
|
||||||
|
def _test_recursive_dict(self, cls, asdict=identity, minprotocol=0):
|
||||||
|
# Dict containing itself.
|
||||||
|
d = cls()
|
||||||
|
d[1] = d
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(d, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, cls)
|
||||||
|
y = asdict(x)
|
||||||
|
self.assertEqual(list(y.keys()), [1])
|
||||||
|
self.assertIs(y[1], x)
|
||||||
|
|
||||||
def test_recursive_dict(self):
|
def test_recursive_dict(self):
|
||||||
d = {}
|
self._test_recursive_dict(dict)
|
||||||
d[1] = d
|
|
||||||
for proto in protocols:
|
def test_recursive_dict_subclass(self):
|
||||||
|
self._test_recursive_dict(MyDict, minprotocol=2)
|
||||||
|
|
||||||
|
def test_recursive_dict_like(self):
|
||||||
|
self._test_recursive_dict(REX_seven, asdict=lambda x: x.table)
|
||||||
|
|
||||||
|
def _test_recursive_tuple_and_dict(self, cls, asdict=identity, minprotocol=0):
|
||||||
|
# Tuple containing a dict containing the original tuple.
|
||||||
|
t = (cls(),)
|
||||||
|
t[0][1] = t
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, tuple)
|
||||||
|
self.assertEqual(len(x), 1)
|
||||||
|
self.assertIsInstance(x[0], cls)
|
||||||
|
y = asdict(x[0])
|
||||||
|
self.assertEqual(list(y), [1])
|
||||||
|
self.assertIs(y[1], x)
|
||||||
|
|
||||||
|
# Dict containing a tuple containing the original dict.
|
||||||
|
t, = t
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, cls)
|
||||||
|
y = asdict(x)
|
||||||
|
self.assertEqual(list(y), [1])
|
||||||
|
self.assertIsInstance(y[1], tuple)
|
||||||
|
self.assertEqual(len(y[1]), 1)
|
||||||
|
self.assertIs(y[1][0], x)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict(self):
|
||||||
|
self._test_recursive_tuple_and_dict(dict)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict_subclass(self):
|
||||||
|
self._test_recursive_tuple_and_dict(MyDict, minprotocol=2)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict_like(self):
|
||||||
|
self._test_recursive_tuple_and_dict(REX_seven, asdict=lambda x: x.table)
|
||||||
|
|
||||||
|
def _test_recursive_dict_key(self, cls, asdict=identity, minprotocol=0):
|
||||||
|
# Dict containing an immutable object (as key) containing the original
|
||||||
|
# dict.
|
||||||
|
d = cls()
|
||||||
|
d[K(d)] = 1
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(d, proto)
|
s = self.dumps(d, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, dict)
|
self.assertIsInstance(x, cls)
|
||||||
self.assertEqual(list(x.keys()), [1])
|
y = asdict(x)
|
||||||
self.assertIs(x[1], x)
|
self.assertEqual(len(y.keys()), 1)
|
||||||
|
self.assertIsInstance(list(y.keys())[0], K)
|
||||||
|
self.assertIs(list(y.keys())[0].value, x)
|
||||||
|
|
||||||
def test_recursive_dict_key(self):
|
def test_recursive_dict_key(self):
|
||||||
d = {}
|
self._test_recursive_dict_key(dict)
|
||||||
k = K(d)
|
|
||||||
d[k] = 1
|
def test_recursive_dict_subclass_key(self):
|
||||||
for proto in protocols:
|
self._test_recursive_dict_key(MyDict, minprotocol=2)
|
||||||
s = self.dumps(d, proto)
|
|
||||||
|
def test_recursive_dict_like_key(self):
|
||||||
|
self._test_recursive_dict_key(REX_seven, asdict=lambda x: x.table)
|
||||||
|
|
||||||
|
def _test_recursive_tuple_and_dict_key(self, cls, asdict=identity, minprotocol=0):
|
||||||
|
# Tuple containing a dict containing an immutable object (as key)
|
||||||
|
# containing the original tuple.
|
||||||
|
t = (cls(),)
|
||||||
|
t[0][K(t)] = 1
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(t, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, dict)
|
self.assertIsInstance(x, tuple)
|
||||||
self.assertEqual(len(x.keys()), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertIsInstance(list(x.keys())[0], K)
|
self.assertIsInstance(x[0], cls)
|
||||||
self.assertIs(list(x.keys())[0].value, x)
|
y = asdict(x[0])
|
||||||
|
self.assertEqual(len(y), 1)
|
||||||
|
self.assertIsInstance(list(y.keys())[0], K)
|
||||||
|
self.assertIs(list(y.keys())[0].value, x)
|
||||||
|
|
||||||
|
# Dict containing an immutable object (as key) containing a tuple
|
||||||
|
# containing the original dict.
|
||||||
|
t, = t
|
||||||
|
for proto in range(minprotocol, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, cls)
|
||||||
|
y = asdict(x)
|
||||||
|
self.assertEqual(len(y), 1)
|
||||||
|
self.assertIsInstance(list(y.keys())[0], K)
|
||||||
|
self.assertIs(list(y.keys())[0].value[0], x)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict_key(self):
|
||||||
|
self._test_recursive_tuple_and_dict_key(dict)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict_subclass_key(self):
|
||||||
|
self._test_recursive_tuple_and_dict_key(MyDict, minprotocol=2)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_dict_like_key(self):
|
||||||
|
self._test_recursive_tuple_and_dict_key(REX_seven, asdict=lambda x: x.table)
|
||||||
|
|
||||||
def test_recursive_set(self):
|
def test_recursive_set(self):
|
||||||
|
# Set containing an immutable object containing the original set.
|
||||||
y = set()
|
y = set()
|
||||||
k = K(y)
|
y.add(K(y))
|
||||||
y.add(k)
|
|
||||||
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(y, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
|
@ -1552,52 +1681,31 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
self.assertIsInstance(list(x)[0], K)
|
self.assertIsInstance(list(x)[0], K)
|
||||||
self.assertIs(list(x)[0].value, x)
|
self.assertIs(list(x)[0].value, x)
|
||||||
|
|
||||||
def test_recursive_list_subclass(self):
|
# Immutable object containing a set containing the original object.
|
||||||
y = MyList()
|
y, = y
|
||||||
y.append(y)
|
for proto in range(4, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(y, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, MyList)
|
self.assertIsInstance(x, K)
|
||||||
self.assertEqual(len(x), 1)
|
self.assertIsInstance(x.value, set)
|
||||||
self.assertIs(x[0], x)
|
self.assertEqual(len(x.value), 1)
|
||||||
|
self.assertIs(list(x.value)[0], x)
|
||||||
def test_recursive_dict_subclass(self):
|
|
||||||
d = MyDict()
|
|
||||||
d[1] = d
|
|
||||||
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(d, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, MyDict)
|
|
||||||
self.assertEqual(list(x.keys()), [1])
|
|
||||||
self.assertIs(x[1], x)
|
|
||||||
|
|
||||||
def test_recursive_dict_subclass_key(self):
|
|
||||||
d = MyDict()
|
|
||||||
k = K(d)
|
|
||||||
d[k] = 1
|
|
||||||
for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
|
|
||||||
s = self.dumps(d, proto)
|
|
||||||
x = self.loads(s)
|
|
||||||
self.assertIsInstance(x, MyDict)
|
|
||||||
self.assertEqual(len(list(x.keys())), 1)
|
|
||||||
self.assertIsInstance(list(x.keys())[0], K)
|
|
||||||
self.assertIs(list(x.keys())[0].value, x)
|
|
||||||
|
|
||||||
def test_recursive_inst(self):
|
def test_recursive_inst(self):
|
||||||
i = C()
|
# Mutable object containing itself.
|
||||||
|
i = Object()
|
||||||
i.attr = i
|
i.attr = i
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
s = self.dumps(i, proto)
|
s = self.dumps(i, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, C)
|
self.assertIsInstance(x, Object)
|
||||||
self.assertEqual(dir(x), dir(i))
|
self.assertEqual(dir(x), dir(i))
|
||||||
self.assertIs(x.attr, x)
|
self.assertIs(x.attr, x)
|
||||||
|
|
||||||
def test_recursive_multi(self):
|
def test_recursive_multi(self):
|
||||||
l = []
|
l = []
|
||||||
d = {1:l}
|
d = {1:l}
|
||||||
i = C()
|
i = Object()
|
||||||
i.attr = d
|
i.attr = d
|
||||||
l.append(i)
|
l.append(i)
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
|
@ -1607,49 +1715,94 @@ class AbstractPickleTests(unittest.TestCase):
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertEqual(dir(x[0]), dir(i))
|
self.assertEqual(dir(x[0]), dir(i))
|
||||||
self.assertEqual(list(x[0].attr.keys()), [1])
|
self.assertEqual(list(x[0].attr.keys()), [1])
|
||||||
self.assertTrue(x[0].attr[1] is x)
|
self.assertIs(x[0].attr[1], x)
|
||||||
|
|
||||||
def check_recursive_collection_and_inst(self, factory):
|
def _test_recursive_collection_and_inst(self, factory):
|
||||||
h = H()
|
# Mutable object containing a collection containing the original
|
||||||
y = factory([h])
|
# object.
|
||||||
h.attr = y
|
o = Object()
|
||||||
|
o.attr = factory([o])
|
||||||
|
t = type(o.attr)
|
||||||
for proto in protocols:
|
for proto in protocols:
|
||||||
s = self.dumps(y, proto)
|
s = self.dumps(o, proto)
|
||||||
x = self.loads(s)
|
x = self.loads(s)
|
||||||
self.assertIsInstance(x, type(y))
|
self.assertIsInstance(x.attr, t)
|
||||||
|
self.assertEqual(len(x.attr), 1)
|
||||||
|
self.assertIsInstance(list(x.attr)[0], Object)
|
||||||
|
self.assertIs(list(x.attr)[0], x)
|
||||||
|
|
||||||
|
# Collection containing a mutable object containing the original
|
||||||
|
# collection.
|
||||||
|
o = o.attr
|
||||||
|
for proto in protocols:
|
||||||
|
s = self.dumps(o, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, t)
|
||||||
self.assertEqual(len(x), 1)
|
self.assertEqual(len(x), 1)
|
||||||
self.assertIsInstance(list(x)[0], H)
|
self.assertIsInstance(list(x)[0], Object)
|
||||||
self.assertIs(list(x)[0].attr, x)
|
self.assertIs(list(x)[0].attr, x)
|
||||||
|
|
||||||
def test_recursive_list_and_inst(self):
|
def test_recursive_list_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(list)
|
self._test_recursive_collection_and_inst(list)
|
||||||
|
|
||||||
def test_recursive_tuple_and_inst(self):
|
def test_recursive_tuple_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(tuple)
|
self._test_recursive_collection_and_inst(tuple)
|
||||||
|
|
||||||
def test_recursive_dict_and_inst(self):
|
def test_recursive_dict_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(dict.fromkeys)
|
self._test_recursive_collection_and_inst(dict.fromkeys)
|
||||||
|
|
||||||
def test_recursive_set_and_inst(self):
|
def test_recursive_set_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(set)
|
self._test_recursive_collection_and_inst(set)
|
||||||
|
|
||||||
def test_recursive_frozenset_and_inst(self):
|
def test_recursive_frozenset_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(frozenset)
|
self._test_recursive_collection_and_inst(frozenset)
|
||||||
|
|
||||||
def test_recursive_list_subclass_and_inst(self):
|
def test_recursive_list_subclass_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(MyList)
|
self._test_recursive_collection_and_inst(MyList)
|
||||||
|
|
||||||
def test_recursive_tuple_subclass_and_inst(self):
|
def test_recursive_tuple_subclass_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(MyTuple)
|
self._test_recursive_collection_and_inst(MyTuple)
|
||||||
|
|
||||||
def test_recursive_dict_subclass_and_inst(self):
|
def test_recursive_dict_subclass_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(MyDict.fromkeys)
|
self._test_recursive_collection_and_inst(MyDict.fromkeys)
|
||||||
|
|
||||||
def test_recursive_set_subclass_and_inst(self):
|
def test_recursive_set_subclass_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(MySet)
|
self._test_recursive_collection_and_inst(MySet)
|
||||||
|
|
||||||
def test_recursive_frozenset_subclass_and_inst(self):
|
def test_recursive_frozenset_subclass_and_inst(self):
|
||||||
self.check_recursive_collection_and_inst(MyFrozenSet)
|
self._test_recursive_collection_and_inst(MyFrozenSet)
|
||||||
|
|
||||||
|
def test_recursive_inst_state(self):
|
||||||
|
# Mutable object containing itself.
|
||||||
|
y = REX_state()
|
||||||
|
y.state = y
|
||||||
|
for proto in protocols:
|
||||||
|
s = self.dumps(y, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, REX_state)
|
||||||
|
self.assertIs(x.state, x)
|
||||||
|
|
||||||
|
def test_recursive_tuple_and_inst_state(self):
|
||||||
|
# Tuple containing a mutable object containing the original tuple.
|
||||||
|
t = (REX_state(),)
|
||||||
|
t[0].state = t
|
||||||
|
for proto in protocols:
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, tuple)
|
||||||
|
self.assertEqual(len(x), 1)
|
||||||
|
self.assertIsInstance(x[0], REX_state)
|
||||||
|
self.assertIs(x[0].state, x)
|
||||||
|
|
||||||
|
# Mutable object containing a tuple containing the object.
|
||||||
|
t, = t
|
||||||
|
for proto in protocols:
|
||||||
|
s = self.dumps(t, proto)
|
||||||
|
x = self.loads(s)
|
||||||
|
self.assertIsInstance(x, REX_state)
|
||||||
|
self.assertIsInstance(x.state, tuple)
|
||||||
|
self.assertEqual(len(x.state), 1)
|
||||||
|
self.assertIs(x.state[0], x)
|
||||||
|
|
||||||
def test_unicode(self):
|
def test_unicode(self):
|
||||||
endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
|
endcases = ['', '<\\u>', '<\\\u1234>', '<\n>',
|
||||||
|
@ -3062,6 +3215,19 @@ class REX_seven(object):
|
||||||
def __reduce__(self):
|
def __reduce__(self):
|
||||||
return type(self), (), None, None, iter(self.table.items())
|
return type(self), (), None, None, iter(self.table.items())
|
||||||
|
|
||||||
|
class REX_state(object):
|
||||||
|
"""This class is used to check the 3th argument (state) of
|
||||||
|
the reduce protocol.
|
||||||
|
"""
|
||||||
|
def __init__(self, state=None):
|
||||||
|
self.state = state
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) is type(other) and self.state == other.state
|
||||||
|
def __setstate__(self, state):
|
||||||
|
self.state = state
|
||||||
|
def __reduce__(self):
|
||||||
|
return type(self), (), self.state
|
||||||
|
|
||||||
|
|
||||||
# Test classes for newobj
|
# Test classes for newobj
|
||||||
|
|
||||||
|
|
|
@ -48,37 +48,57 @@ class TestCurses(unittest.TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
if not sys.__stdout__.isatty():
|
|
||||||
# Temporary skip tests on non-tty
|
|
||||||
raise unittest.SkipTest('sys.__stdout__ is not a tty')
|
|
||||||
cls.tmp = tempfile.TemporaryFile()
|
|
||||||
fd = cls.tmp.fileno()
|
|
||||||
else:
|
|
||||||
cls.tmp = None
|
|
||||||
fd = sys.__stdout__.fileno()
|
|
||||||
# testing setupterm() inside initscr/endwin
|
# testing setupterm() inside initscr/endwin
|
||||||
# causes terminal breakage
|
# causes terminal breakage
|
||||||
curses.setupterm(fd=fd)
|
stdout_fd = sys.__stdout__.fileno()
|
||||||
|
curses.setupterm(fd=stdout_fd)
|
||||||
@classmethod
|
|
||||||
def tearDownClass(cls):
|
|
||||||
if cls.tmp:
|
|
||||||
cls.tmp.close()
|
|
||||||
del cls.tmp
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.isatty = True
|
||||||
|
self.output = sys.__stdout__
|
||||||
|
stdout_fd = sys.__stdout__.fileno()
|
||||||
|
if not sys.__stdout__.isatty():
|
||||||
|
# initstr() unconditionally uses C stdout.
|
||||||
|
# If it is redirected to file or pipe, try to attach it
|
||||||
|
# to terminal.
|
||||||
|
# First, save a copy of the file descriptor of stdout, so it
|
||||||
|
# can be restored after finishing the test.
|
||||||
|
dup_fd = os.dup(stdout_fd)
|
||||||
|
self.addCleanup(os.close, dup_fd)
|
||||||
|
self.addCleanup(os.dup2, dup_fd, stdout_fd)
|
||||||
|
|
||||||
|
if sys.__stderr__.isatty():
|
||||||
|
# If stderr is connected to terminal, use it.
|
||||||
|
tmp = sys.__stderr__
|
||||||
|
self.output = sys.__stderr__
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# Try to open the terminal device.
|
||||||
|
tmp = open('/xdev/tty', 'wb', buffering=0)
|
||||||
|
except OSError:
|
||||||
|
# As a fallback, use regular file to write control codes.
|
||||||
|
# Some functions (like savetty) will not work, but at
|
||||||
|
# least the garbage control sequences will not be mixed
|
||||||
|
# with the testing report.
|
||||||
|
tmp = tempfile.TemporaryFile(mode='wb', buffering=0)
|
||||||
|
self.isatty = False
|
||||||
|
self.addCleanup(tmp.close)
|
||||||
|
self.output = None
|
||||||
|
os.dup2(tmp.fileno(), stdout_fd)
|
||||||
|
|
||||||
self.save_signals = SaveSignals()
|
self.save_signals = SaveSignals()
|
||||||
self.save_signals.save()
|
self.save_signals.save()
|
||||||
if verbose:
|
self.addCleanup(self.save_signals.restore)
|
||||||
|
if verbose and self.output is not None:
|
||||||
# just to make the test output a little more readable
|
# just to make the test output a little more readable
|
||||||
print()
|
sys.stderr.flush()
|
||||||
|
sys.stdout.flush()
|
||||||
|
print(file=self.output, flush=True)
|
||||||
self.stdscr = curses.initscr()
|
self.stdscr = curses.initscr()
|
||||||
curses.savetty()
|
if self.isatty:
|
||||||
|
curses.savetty()
|
||||||
def tearDown(self):
|
self.addCleanup(curses.endwin)
|
||||||
curses.resetty()
|
self.addCleanup(curses.resetty)
|
||||||
curses.endwin()
|
|
||||||
self.save_signals.restore()
|
|
||||||
|
|
||||||
def test_window_funcs(self):
|
def test_window_funcs(self):
|
||||||
"Test the methods of windows"
|
"Test the methods of windows"
|
||||||
|
@ -96,7 +116,7 @@ class TestCurses(unittest.TestCase):
|
||||||
for meth in [stdscr.clear, stdscr.clrtobot,
|
for meth in [stdscr.clear, stdscr.clrtobot,
|
||||||
stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
|
stdscr.clrtoeol, stdscr.cursyncup, stdscr.delch,
|
||||||
stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
|
stdscr.deleteln, stdscr.erase, stdscr.getbegyx,
|
||||||
stdscr.getbkgd, stdscr.getkey, stdscr.getmaxyx,
|
stdscr.getbkgd, stdscr.getmaxyx,
|
||||||
stdscr.getparyx, stdscr.getyx, stdscr.inch,
|
stdscr.getparyx, stdscr.getyx, stdscr.inch,
|
||||||
stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
|
stdscr.insertln, stdscr.instr, stdscr.is_wintouched,
|
||||||
win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
|
win.noutrefresh, stdscr.redrawwin, stdscr.refresh,
|
||||||
|
@ -207,6 +227,11 @@ class TestCurses(unittest.TestCase):
|
||||||
if hasattr(stdscr, 'enclose'):
|
if hasattr(stdscr, 'enclose'):
|
||||||
stdscr.enclose(10, 10)
|
stdscr.enclose(10, 10)
|
||||||
|
|
||||||
|
with tempfile.TemporaryFile() as f:
|
||||||
|
self.stdscr.putwin(f)
|
||||||
|
f.seek(0)
|
||||||
|
curses.getwin(f)
|
||||||
|
|
||||||
self.assertRaises(ValueError, stdscr.getstr, -400)
|
self.assertRaises(ValueError, stdscr.getstr, -400)
|
||||||
self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
|
self.assertRaises(ValueError, stdscr.getstr, 2, 3, -400)
|
||||||
self.assertRaises(ValueError, stdscr.instr, -2)
|
self.assertRaises(ValueError, stdscr.instr, -2)
|
||||||
|
@ -225,17 +250,20 @@ class TestCurses(unittest.TestCase):
|
||||||
def test_module_funcs(self):
|
def test_module_funcs(self):
|
||||||
"Test module-level functions"
|
"Test module-level functions"
|
||||||
for func in [curses.baudrate, curses.beep, curses.can_change_color,
|
for func in [curses.baudrate, curses.beep, curses.can_change_color,
|
||||||
curses.cbreak, curses.def_prog_mode, curses.doupdate,
|
curses.doupdate, curses.flash, curses.flushinp,
|
||||||
curses.flash, curses.flushinp,
|
|
||||||
curses.has_colors, curses.has_ic, curses.has_il,
|
curses.has_colors, curses.has_ic, curses.has_il,
|
||||||
curses.isendwin, curses.killchar, curses.longname,
|
curses.isendwin, curses.killchar, curses.longname,
|
||||||
curses.nocbreak, curses.noecho, curses.nonl,
|
curses.noecho, curses.nonl, curses.noqiflush,
|
||||||
curses.noqiflush, curses.noraw,
|
curses.termattrs, curses.termname, curses.erasechar,
|
||||||
curses.reset_prog_mode, curses.termattrs,
|
|
||||||
curses.termname, curses.erasechar,
|
|
||||||
curses.has_extended_color_support]:
|
curses.has_extended_color_support]:
|
||||||
with self.subTest(func=func.__qualname__):
|
with self.subTest(func=func.__qualname__):
|
||||||
func()
|
func()
|
||||||
|
if self.isatty:
|
||||||
|
for func in [curses.cbreak, curses.def_prog_mode,
|
||||||
|
curses.nocbreak, curses.noraw,
|
||||||
|
curses.reset_prog_mode]:
|
||||||
|
with self.subTest(func=func.__qualname__):
|
||||||
|
func()
|
||||||
if hasattr(curses, 'filter'):
|
if hasattr(curses, 'filter'):
|
||||||
curses.filter()
|
curses.filter()
|
||||||
if hasattr(curses, 'getsyx'):
|
if hasattr(curses, 'getsyx'):
|
||||||
|
@ -247,13 +275,9 @@ class TestCurses(unittest.TestCase):
|
||||||
curses.delay_output(1)
|
curses.delay_output(1)
|
||||||
curses.echo() ; curses.echo(1)
|
curses.echo() ; curses.echo(1)
|
||||||
|
|
||||||
with tempfile.TemporaryFile() as f:
|
|
||||||
self.stdscr.putwin(f)
|
|
||||||
f.seek(0)
|
|
||||||
curses.getwin(f)
|
|
||||||
|
|
||||||
curses.halfdelay(1)
|
curses.halfdelay(1)
|
||||||
curses.intrflush(1)
|
if self.isatty:
|
||||||
|
curses.intrflush(1)
|
||||||
curses.meta(1)
|
curses.meta(1)
|
||||||
curses.napms(100)
|
curses.napms(100)
|
||||||
curses.newpad(50,50)
|
curses.newpad(50,50)
|
||||||
|
@ -262,7 +286,8 @@ class TestCurses(unittest.TestCase):
|
||||||
curses.nl() ; curses.nl(1)
|
curses.nl() ; curses.nl(1)
|
||||||
curses.putp(b'abc')
|
curses.putp(b'abc')
|
||||||
curses.qiflush()
|
curses.qiflush()
|
||||||
curses.raw() ; curses.raw(1)
|
if self.isatty:
|
||||||
|
curses.raw() ; curses.raw(1)
|
||||||
curses.set_escdelay(25)
|
curses.set_escdelay(25)
|
||||||
self.assertEqual(curses.get_escdelay(), 25)
|
self.assertEqual(curses.get_escdelay(), 25)
|
||||||
curses.set_tabsize(4)
|
curses.set_tabsize(4)
|
||||||
|
@ -373,7 +398,6 @@ class TestCurses(unittest.TestCase):
|
||||||
|
|
||||||
@requires_curses_func('resizeterm')
|
@requires_curses_func('resizeterm')
|
||||||
def test_resizeterm(self):
|
def test_resizeterm(self):
|
||||||
stdscr = self.stdscr
|
|
||||||
lines, cols = curses.LINES, curses.COLS
|
lines, cols = curses.LINES, curses.COLS
|
||||||
new_lines = lines - 1
|
new_lines = lines - 1
|
||||||
new_cols = cols + 1
|
new_cols = cols + 1
|
||||||
|
|
|
@ -737,6 +737,16 @@ class TypesTests(unittest.TestCase):
|
||||||
with self.assertRaises(ZeroDivisionError):
|
with self.assertRaises(ZeroDivisionError):
|
||||||
list[int] | list[bt]
|
list[int] | list[bt]
|
||||||
|
|
||||||
|
union_ga = (int | list[str], int | collections.abc.Callable[..., str],
|
||||||
|
int | d)
|
||||||
|
# Raise error when isinstance(type, type | genericalias)
|
||||||
|
for type_ in union_ga:
|
||||||
|
with self.subTest(f"check isinstance/issubclass is invalid for {type_}"):
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
isinstance(list, type_)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
issubclass(list, type_)
|
||||||
|
|
||||||
def test_ellipsis_type(self):
|
def test_ellipsis_type(self):
|
||||||
self.assertIsInstance(Ellipsis, types.EllipsisType)
|
self.assertIsInstance(Ellipsis, types.EllipsisType)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Convert :mod:`array` to use heap types, and establish module state for these.
|
|
@ -0,0 +1 @@
|
||||||
|
Handle empty string in variable executable in platform.libc_ver()
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "structmember.h" // PyMemberDef
|
||||||
#include <stddef.h> // offsetof()
|
#include <stddef.h> // offsetof()
|
||||||
|
|
||||||
#ifdef STDC_HEADERS
|
#ifdef STDC_HEADERS
|
||||||
|
@ -21,6 +22,7 @@ module array
|
||||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7d1b8d7f5958fd83]*/
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7d1b8d7f5958fd83]*/
|
||||||
|
|
||||||
struct arrayobject; /* Forward */
|
struct arrayobject; /* Forward */
|
||||||
|
static struct PyModuleDef arraymodule;
|
||||||
|
|
||||||
/* All possible arraydescr values are defined in the vector "descriptors"
|
/* All possible arraydescr values are defined in the vector "descriptors"
|
||||||
* below. That's defined later because the appropriate get and set
|
* below. That's defined later because the appropriate get and set
|
||||||
|
@ -46,8 +48,6 @@ typedef struct arrayobject {
|
||||||
Py_ssize_t ob_exports; /* Number of exported buffers */
|
Py_ssize_t ob_exports; /* Number of exported buffers */
|
||||||
} arrayobject;
|
} arrayobject;
|
||||||
|
|
||||||
static PyTypeObject Arraytype;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
Py_ssize_t index;
|
Py_ssize_t index;
|
||||||
|
@ -55,9 +55,21 @@ typedef struct {
|
||||||
PyObject* (*getitem)(struct arrayobject *, Py_ssize_t);
|
PyObject* (*getitem)(struct arrayobject *, Py_ssize_t);
|
||||||
} arrayiterobject;
|
} arrayiterobject;
|
||||||
|
|
||||||
static PyTypeObject PyArrayIter_Type;
|
typedef struct {
|
||||||
|
PyTypeObject *ArrayType;
|
||||||
|
PyTypeObject *ArrayIterType;
|
||||||
|
} array_state;
|
||||||
|
|
||||||
#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type)
|
static array_state *
|
||||||
|
get_array_state(PyObject *module)
|
||||||
|
{
|
||||||
|
return (array_state *)PyModule_GetState(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define find_array_state_by_type(tp) \
|
||||||
|
(get_array_state(_PyType_GetModuleByDef(tp, &arraymodule)))
|
||||||
|
#define get_array_state_by_class(cls) \
|
||||||
|
(get_array_state(PyType_GetModule(cls)))
|
||||||
|
|
||||||
enum machine_format_code {
|
enum machine_format_code {
|
||||||
UNKNOWN_FORMAT = -1,
|
UNKNOWN_FORMAT = -1,
|
||||||
|
@ -105,8 +117,7 @@ enum machine_format_code {
|
||||||
*/
|
*/
|
||||||
#include "clinic/arraymodule.c.h"
|
#include "clinic/arraymodule.c.h"
|
||||||
|
|
||||||
#define array_Check(op) PyObject_TypeCheck(op, &Arraytype)
|
#define array_Check(op, state) PyObject_TypeCheck(op, state->ArrayType)
|
||||||
#define array_CheckExact(op) Py_IS_TYPE(op, &Arraytype)
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
array_resize(arrayobject *self, Py_ssize_t newsize)
|
array_resize(arrayobject *self, Py_ssize_t newsize)
|
||||||
|
@ -562,9 +573,9 @@ static const struct arraydescr descriptors[] = {
|
||||||
Implementations of array object methods.
|
Implementations of array object methods.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
class array.array "arrayobject *" "&Arraytype"
|
class array.array "arrayobject *" "ArrayType"
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ad43d37e942a8854]*/
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
|
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
|
||||||
|
@ -607,8 +618,11 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
|
||||||
static PyObject *
|
static PyObject *
|
||||||
getarrayitem(PyObject *op, Py_ssize_t i)
|
getarrayitem(PyObject *op, Py_ssize_t i)
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(op));
|
||||||
|
assert(array_Check(op, state));
|
||||||
|
#endif
|
||||||
arrayobject *ap;
|
arrayobject *ap;
|
||||||
assert(array_Check(op));
|
|
||||||
ap = (arrayobject *)op;
|
ap = (arrayobject *)op;
|
||||||
assert(i>=0 && i<Py_SIZE(ap));
|
assert(i>=0 && i<Py_SIZE(ap));
|
||||||
return (*ap->ob_descr->getitem)(ap, i);
|
return (*ap->ob_descr->getitem)(ap, i);
|
||||||
|
@ -649,23 +663,27 @@ ins1(arrayobject *self, Py_ssize_t where, PyObject *v)
|
||||||
static void
|
static void
|
||||||
array_dealloc(arrayobject *op)
|
array_dealloc(arrayobject *op)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = Py_TYPE(op);
|
||||||
|
|
||||||
if (op->weakreflist != NULL)
|
if (op->weakreflist != NULL)
|
||||||
PyObject_ClearWeakRefs((PyObject *) op);
|
PyObject_ClearWeakRefs((PyObject *) op);
|
||||||
if (op->ob_item != NULL)
|
if (op->ob_item != NULL)
|
||||||
PyMem_Free(op->ob_item);
|
PyMem_Free(op->ob_item);
|
||||||
Py_TYPE(op)->tp_free((PyObject *)op);
|
tp->tp_free(op);
|
||||||
|
Py_DECREF(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_richcompare(PyObject *v, PyObject *w, int op)
|
array_richcompare(PyObject *v, PyObject *w, int op)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(v));
|
||||||
arrayobject *va, *wa;
|
arrayobject *va, *wa;
|
||||||
PyObject *vi = NULL;
|
PyObject *vi = NULL;
|
||||||
PyObject *wi = NULL;
|
PyObject *wi = NULL;
|
||||||
Py_ssize_t i, k;
|
Py_ssize_t i, k;
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
|
||||||
if (!array_Check(v) || !array_Check(w))
|
if (!array_Check(v, state) || !array_Check(w, state))
|
||||||
Py_RETURN_NOTIMPLEMENTED;
|
Py_RETURN_NOTIMPLEMENTED;
|
||||||
|
|
||||||
va = (arrayobject *)v;
|
va = (arrayobject *)v;
|
||||||
|
@ -787,7 +805,9 @@ array_item(arrayobject *a, Py_ssize_t i)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
|
array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(a));
|
||||||
arrayobject *np;
|
arrayobject *np;
|
||||||
|
|
||||||
if (ilow < 0)
|
if (ilow < 0)
|
||||||
ilow = 0;
|
ilow = 0;
|
||||||
else if (ilow > Py_SIZE(a))
|
else if (ilow > Py_SIZE(a))
|
||||||
|
@ -798,7 +818,7 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
|
||||||
ihigh = ilow;
|
ihigh = ilow;
|
||||||
else if (ihigh > Py_SIZE(a))
|
else if (ihigh > Py_SIZE(a))
|
||||||
ihigh = Py_SIZE(a);
|
ihigh = Py_SIZE(a);
|
||||||
np = (arrayobject *) newarrayobject(&Arraytype, ihigh - ilow, a->ob_descr);
|
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
|
||||||
if (np == NULL)
|
if (np == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (ihigh > ilow) {
|
if (ihigh > ilow) {
|
||||||
|
@ -841,9 +861,10 @@ array_array___deepcopy__(arrayobject *self, PyObject *unused)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_concat(arrayobject *a, PyObject *bb)
|
array_concat(arrayobject *a, PyObject *bb)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(a));
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
arrayobject *np;
|
arrayobject *np;
|
||||||
if (!array_Check(bb)) {
|
if (!array_Check(bb, state)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"can only append array (not \"%.200s\") to array",
|
"can only append array (not \"%.200s\") to array",
|
||||||
Py_TYPE(bb)->tp_name);
|
Py_TYPE(bb)->tp_name);
|
||||||
|
@ -858,7 +879,7 @@ array_concat(arrayobject *a, PyObject *bb)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
}
|
}
|
||||||
size = Py_SIZE(a) + Py_SIZE(b);
|
size = Py_SIZE(a) + Py_SIZE(b);
|
||||||
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
|
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -876,6 +897,7 @@ array_concat(arrayobject *a, PyObject *bb)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_repeat(arrayobject *a, Py_ssize_t n)
|
array_repeat(arrayobject *a, Py_ssize_t n)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(a));
|
||||||
Py_ssize_t size;
|
Py_ssize_t size;
|
||||||
arrayobject *np;
|
arrayobject *np;
|
||||||
Py_ssize_t oldbytes, newbytes;
|
Py_ssize_t oldbytes, newbytes;
|
||||||
|
@ -885,7 +907,7 @@ array_repeat(arrayobject *a, Py_ssize_t n)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
}
|
}
|
||||||
size = Py_SIZE(a) * n;
|
size = Py_SIZE(a) * n;
|
||||||
np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr);
|
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
|
||||||
if (np == NULL)
|
if (np == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
|
@ -958,7 +980,10 @@ array_ass_item(arrayobject *a, Py_ssize_t i, PyObject *v)
|
||||||
static int
|
static int
|
||||||
setarrayitem(PyObject *a, Py_ssize_t i, PyObject *v)
|
setarrayitem(PyObject *a, Py_ssize_t i, PyObject *v)
|
||||||
{
|
{
|
||||||
assert(array_Check(a));
|
#ifndef NDEBUG
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(a));
|
||||||
|
assert(array_Check(a, state));
|
||||||
|
#endif
|
||||||
return array_ass_item((arrayobject *)a, i, v);
|
return array_ass_item((arrayobject *)a, i, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,11 +1011,11 @@ array_iter_extend(arrayobject *self, PyObject *bb)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
array_do_extend(arrayobject *self, PyObject *bb)
|
array_do_extend(array_state *state, arrayobject *self, PyObject *bb)
|
||||||
{
|
{
|
||||||
Py_ssize_t size, oldsize, bbsize;
|
Py_ssize_t size, oldsize, bbsize;
|
||||||
|
|
||||||
if (!array_Check(bb))
|
if (!array_Check(bb, state))
|
||||||
return array_iter_extend(self, bb);
|
return array_iter_extend(self, bb);
|
||||||
#define b ((arrayobject *)bb)
|
#define b ((arrayobject *)bb)
|
||||||
if (self->ob_descr != b->ob_descr) {
|
if (self->ob_descr != b->ob_descr) {
|
||||||
|
@ -1021,13 +1046,15 @@ array_do_extend(arrayobject *self, PyObject *bb)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_inplace_concat(arrayobject *self, PyObject *bb)
|
array_inplace_concat(arrayobject *self, PyObject *bb)
|
||||||
{
|
{
|
||||||
if (!array_Check(bb)) {
|
array_state *state = find_array_state_by_type(Py_TYPE(self));
|
||||||
|
|
||||||
|
if (!array_Check(bb, state)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"can only extend array with array (not \"%.200s\")",
|
"can only extend array with array (not \"%.200s\")",
|
||||||
Py_TYPE(bb)->tp_name);
|
Py_TYPE(bb)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (array_do_extend(self, bb) == -1)
|
if (array_do_extend(state, self, bb) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_INCREF(self);
|
Py_INCREF(self);
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
|
@ -1232,6 +1259,7 @@ array_array_pop_impl(arrayobject *self, Py_ssize_t i)
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
array.array.extend
|
array.array.extend
|
||||||
|
|
||||||
|
cls: defining_class
|
||||||
bb: object
|
bb: object
|
||||||
/
|
/
|
||||||
|
|
||||||
|
@ -1239,10 +1267,12 @@ Append items to the end of the array.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_array_extend(arrayobject *self, PyObject *bb)
|
array_array_extend_impl(arrayobject *self, PyTypeObject *cls, PyObject *bb)
|
||||||
/*[clinic end generated code: output=bbddbc8e8bef871d input=43be86aba5c31e44]*/
|
/*[clinic end generated code: output=e65eb7588f0bc266 input=8eb6817ec4d2cb62]*/
|
||||||
{
|
{
|
||||||
if (array_do_extend(self, bb) == -1)
|
array_state *state = get_array_state_by_class(cls);
|
||||||
|
|
||||||
|
if (array_do_extend(state, self, bb) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
@ -1928,6 +1958,7 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
|
||||||
PyObject *items)
|
PyObject *items)
|
||||||
/*[clinic end generated code: output=e05263141ba28365 input=2464dc8f4c7736b5]*/
|
/*[clinic end generated code: output=e05263141ba28365 input=2464dc8f4c7736b5]*/
|
||||||
{
|
{
|
||||||
|
array_state *state = get_array_state(module);
|
||||||
PyObject *converted_items;
|
PyObject *converted_items;
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
const struct arraydescr *descr;
|
const struct arraydescr *descr;
|
||||||
|
@ -1938,10 +1969,10 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
|
||||||
Py_TYPE(arraytype)->tp_name);
|
Py_TYPE(arraytype)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!PyType_IsSubtype(arraytype, &Arraytype)) {
|
if (!PyType_IsSubtype(arraytype, state->ArrayType)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%.200s is not a subtype of %.200s",
|
"%.200s is not a subtype of %.200s",
|
||||||
arraytype->tp_name, Arraytype.tp_name);
|
arraytype->tp_name, state->ArrayType->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (descr = descriptors; descr->typecode != '\0'; descr++) {
|
for (descr = descriptors; descr->typecode != '\0'; descr++) {
|
||||||
|
@ -2287,6 +2318,8 @@ array_repr(arrayobject *a)
|
||||||
static PyObject*
|
static PyObject*
|
||||||
array_subscr(arrayobject* self, PyObject* item)
|
array_subscr(arrayobject* self, PyObject* item)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(self));
|
||||||
|
|
||||||
if (PyIndex_Check(item)) {
|
if (PyIndex_Check(item)) {
|
||||||
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
||||||
if (i==-1 && PyErr_Occurred()) {
|
if (i==-1 && PyErr_Occurred()) {
|
||||||
|
@ -2310,10 +2343,10 @@ array_subscr(arrayobject* self, PyObject* item)
|
||||||
step);
|
step);
|
||||||
|
|
||||||
if (slicelength <= 0) {
|
if (slicelength <= 0) {
|
||||||
return newarrayobject(&Arraytype, 0, self->ob_descr);
|
return newarrayobject(state->ArrayType, 0, self->ob_descr);
|
||||||
}
|
}
|
||||||
else if (step == 1) {
|
else if (step == 1) {
|
||||||
PyObject *result = newarrayobject(&Arraytype,
|
PyObject *result = newarrayobject(state->ArrayType,
|
||||||
slicelength, self->ob_descr);
|
slicelength, self->ob_descr);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2323,7 +2356,7 @@ array_subscr(arrayobject* self, PyObject* item)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = newarrayobject(&Arraytype, slicelength, self->ob_descr);
|
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
|
||||||
if (!result) return NULL;
|
if (!result) return NULL;
|
||||||
|
|
||||||
ar = (arrayobject*)result;
|
ar = (arrayobject*)result;
|
||||||
|
@ -2349,6 +2382,7 @@ static int
|
||||||
array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
|
array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
|
||||||
{
|
{
|
||||||
Py_ssize_t start, stop, step, slicelength, needed;
|
Py_ssize_t start, stop, step, slicelength, needed;
|
||||||
|
array_state* state = find_array_state_by_type(Py_TYPE(self));
|
||||||
arrayobject* other;
|
arrayobject* other;
|
||||||
int itemsize;
|
int itemsize;
|
||||||
|
|
||||||
|
@ -2390,7 +2424,7 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
|
||||||
other = NULL;
|
other = NULL;
|
||||||
needed = 0;
|
needed = 0;
|
||||||
}
|
}
|
||||||
else if (array_Check(value)) {
|
else if (array_Check(value, state)) {
|
||||||
other = (arrayobject *)value;
|
other = (arrayobject *)value;
|
||||||
needed = Py_SIZE(other);
|
needed = Py_SIZE(other);
|
||||||
if (self == other) {
|
if (self == other) {
|
||||||
|
@ -2502,12 +2536,6 @@ array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyMappingMethods array_as_mapping = {
|
|
||||||
(lenfunc)array_length,
|
|
||||||
(binaryfunc)array_subscr,
|
|
||||||
(objobjargproc)array_ass_subscr
|
|
||||||
};
|
|
||||||
|
|
||||||
static const void *emptybuf = "";
|
static const void *emptybuf = "";
|
||||||
|
|
||||||
|
|
||||||
|
@ -2558,32 +2586,15 @@ array_buffer_relbuf(arrayobject *self, Py_buffer *view)
|
||||||
self->ob_exports--;
|
self->ob_exports--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PySequenceMethods array_as_sequence = {
|
|
||||||
(lenfunc)array_length, /*sq_length*/
|
|
||||||
(binaryfunc)array_concat, /*sq_concat*/
|
|
||||||
(ssizeargfunc)array_repeat, /*sq_repeat*/
|
|
||||||
(ssizeargfunc)array_item, /*sq_item*/
|
|
||||||
0, /*sq_slice*/
|
|
||||||
(ssizeobjargproc)array_ass_item, /*sq_ass_item*/
|
|
||||||
0, /*sq_ass_slice*/
|
|
||||||
(objobjproc)array_contains, /*sq_contains*/
|
|
||||||
(binaryfunc)array_inplace_concat, /*sq_inplace_concat*/
|
|
||||||
(ssizeargfunc)array_inplace_repeat /*sq_inplace_repeat*/
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyBufferProcs array_as_buffer = {
|
|
||||||
(getbufferproc)array_buffer_getbuf,
|
|
||||||
(releasebufferproc)array_buffer_relbuf
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(type);
|
||||||
int c;
|
int c;
|
||||||
PyObject *initial = NULL, *it = NULL;
|
PyObject *initial = NULL, *it = NULL;
|
||||||
const struct arraydescr *descr;
|
const struct arraydescr *descr;
|
||||||
|
|
||||||
if (type == &Arraytype && !_PyArg_NoKeywords("array.array", kwds))
|
if (type == state->ArrayType && !_PyArg_NoKeywords("array.array", kwds))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial))
|
if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial))
|
||||||
|
@ -2600,7 +2611,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
"an array with typecode '%c'", c);
|
"an array with typecode '%c'", c);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (array_Check(initial) &&
|
else if (array_Check(initial, state) &&
|
||||||
((arrayobject*)initial)->ob_descr->typecode == 'u') {
|
((arrayobject*)initial)->ob_descr->typecode == 'u') {
|
||||||
PyErr_Format(PyExc_TypeError, "cannot use a unicode array to "
|
PyErr_Format(PyExc_TypeError, "cannot use a unicode array to "
|
||||||
"initialize an array with typecode '%c'", c);
|
"initialize an array with typecode '%c'", c);
|
||||||
|
@ -2613,7 +2624,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|| PyBytes_Check(initial)
|
|| PyBytes_Check(initial)
|
||||||
|| PyTuple_Check(initial)
|
|| PyTuple_Check(initial)
|
||||||
|| ((c=='u') && PyUnicode_Check(initial))
|
|| ((c=='u') && PyUnicode_Check(initial))
|
||||||
|| (array_Check(initial)
|
|| (array_Check(initial, state)
|
||||||
&& c == ((arrayobject*)initial)->ob_descr->typecode))) {
|
&& c == ((arrayobject*)initial)->ob_descr->typecode))) {
|
||||||
it = PyObject_GetIter(initial);
|
it = PyObject_GetIter(initial);
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
|
@ -2634,7 +2645,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
len = 0;
|
len = 0;
|
||||||
else if (PyList_Check(initial))
|
else if (PyList_Check(initial))
|
||||||
len = PyList_GET_SIZE(initial);
|
len = PyList_GET_SIZE(initial);
|
||||||
else if (PyTuple_Check(initial) || array_Check(initial))
|
else if (PyTuple_Check(initial) || array_Check(initial, state))
|
||||||
len = Py_SIZE(initial);
|
len = Py_SIZE(initial);
|
||||||
else
|
else
|
||||||
len = 0;
|
len = 0;
|
||||||
|
@ -2643,7 +2654,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
if (a == NULL)
|
if (a == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (len > 0 && !array_Check(initial)) {
|
if (len > 0 && !array_Check(initial, state)) {
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
PyObject *v =
|
PyObject *v =
|
||||||
|
@ -2688,7 +2699,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
self->allocated = n;
|
self->allocated = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (initial != NULL && array_Check(initial) && len > 0) {
|
else if (initial != NULL && array_Check(initial, state) && len > 0) {
|
||||||
arrayobject *self = (arrayobject *)a;
|
arrayobject *self = (arrayobject *)a;
|
||||||
arrayobject *other = (arrayobject *)initial;
|
arrayobject *other = (arrayobject *)initial;
|
||||||
memcpy(self->ob_item, other->ob_item, len * other->ob_descr->itemsize);
|
memcpy(self->ob_item, other->ob_item, len * other->ob_descr->itemsize);
|
||||||
|
@ -2777,67 +2788,73 @@ itemsize -- the length in bytes of one array item\n\
|
||||||
|
|
||||||
static PyObject *array_iter(arrayobject *ao);
|
static PyObject *array_iter(arrayobject *ao);
|
||||||
|
|
||||||
static PyTypeObject Arraytype = {
|
static struct PyMemberDef array_members[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
{"__weaklistoffset__", T_PYSSIZET, offsetof(arrayobject, weakreflist), READONLY},
|
||||||
"array.array",
|
{NULL},
|
||||||
sizeof(arrayobject),
|
|
||||||
0,
|
|
||||||
(destructor)array_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_vectorcall_offset */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_as_async */
|
|
||||||
(reprfunc)array_repr, /* tp_repr */
|
|
||||||
0, /* tp_as_number*/
|
|
||||||
&array_as_sequence, /* tp_as_sequence*/
|
|
||||||
&array_as_mapping, /* tp_as_mapping*/
|
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
|
||||||
0, /* tp_setattro */
|
|
||||||
&array_as_buffer, /* tp_as_buffer*/
|
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
|
||||||
arraytype_doc, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
array_richcompare, /* tp_richcompare */
|
|
||||||
offsetof(arrayobject, weakreflist), /* tp_weaklistoffset */
|
|
||||||
(getiterfunc)array_iter, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
array_methods, /* tp_methods */
|
|
||||||
0, /* tp_members */
|
|
||||||
array_getsets, /* tp_getset */
|
|
||||||
0, /* tp_base */
|
|
||||||
0, /* tp_dict */
|
|
||||||
0, /* tp_descr_get */
|
|
||||||
0, /* tp_descr_set */
|
|
||||||
0, /* tp_dictoffset */
|
|
||||||
0, /* tp_init */
|
|
||||||
PyType_GenericAlloc, /* tp_alloc */
|
|
||||||
array_new, /* tp_new */
|
|
||||||
PyObject_Del, /* tp_free */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static PyType_Slot array_slots[] = {
|
||||||
|
{Py_tp_dealloc, array_dealloc},
|
||||||
|
{Py_tp_repr, array_repr},
|
||||||
|
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||||
|
{Py_tp_doc, (void *)arraytype_doc},
|
||||||
|
{Py_tp_richcompare, array_richcompare},
|
||||||
|
{Py_tp_iter, array_iter},
|
||||||
|
{Py_tp_methods, array_methods},
|
||||||
|
{Py_tp_members, array_members},
|
||||||
|
{Py_tp_getset, array_getsets},
|
||||||
|
{Py_tp_alloc, PyType_GenericAlloc},
|
||||||
|
{Py_tp_new, array_new},
|
||||||
|
{Py_tp_free, PyObject_Del},
|
||||||
|
|
||||||
|
/* as sequence */
|
||||||
|
{Py_sq_length, array_length},
|
||||||
|
{Py_sq_concat, array_concat},
|
||||||
|
{Py_sq_repeat, array_repeat},
|
||||||
|
{Py_sq_item, array_item},
|
||||||
|
{Py_sq_ass_item, array_ass_item},
|
||||||
|
{Py_sq_contains, array_contains},
|
||||||
|
{Py_sq_inplace_concat, array_inplace_concat},
|
||||||
|
{Py_sq_inplace_repeat, array_inplace_repeat},
|
||||||
|
|
||||||
|
/* as mapping */
|
||||||
|
{Py_mp_length, array_length},
|
||||||
|
{Py_mp_subscript, array_subscr},
|
||||||
|
{Py_mp_ass_subscript, array_ass_subscr},
|
||||||
|
|
||||||
|
/* as buffer */
|
||||||
|
{Py_bf_getbuffer, array_buffer_getbuf},
|
||||||
|
{Py_bf_releasebuffer, array_buffer_relbuf},
|
||||||
|
|
||||||
|
{0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static PyType_Spec array_spec = {
|
||||||
|
.name = "array.array",
|
||||||
|
.basicsize = sizeof(arrayobject),
|
||||||
|
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||||
|
.slots = array_slots,
|
||||||
|
};
|
||||||
|
|
||||||
/*********************** Array Iterator **************************/
|
/*********************** Array Iterator **************************/
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
class array.arrayiterator "arrayiterobject *" "&PyArrayIter_Type"
|
class array.arrayiterator "arrayiterobject *" "find_array_state_by_type(type)->ArrayIterType"
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5aefd2d74d8c8e30]*/
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=fb46d5ef98dd95ff]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
array_iter(arrayobject *ao)
|
array_iter(arrayobject *ao)
|
||||||
{
|
{
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(ao));
|
||||||
arrayiterobject *it;
|
arrayiterobject *it;
|
||||||
|
|
||||||
if (!array_Check(ao)) {
|
if (!array_Check(ao, state)) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
it = PyObject_GC_New(arrayiterobject, &PyArrayIter_Type);
|
it = PyObject_GC_New(arrayiterobject, state->ArrayIterType);
|
||||||
if (it == NULL)
|
if (it == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -2855,12 +2872,17 @@ arrayiter_next(arrayiterobject *it)
|
||||||
arrayobject *ao;
|
arrayobject *ao;
|
||||||
|
|
||||||
assert(it != NULL);
|
assert(it != NULL);
|
||||||
assert(PyArrayIter_Check(it));
|
#ifndef NDEBUG
|
||||||
|
array_state *state = find_array_state_by_type(Py_TYPE(it));
|
||||||
|
assert(PyObject_TypeCheck(it, state->ArrayIterType));
|
||||||
|
#endif
|
||||||
ao = it->ao;
|
ao = it->ao;
|
||||||
if (ao == NULL) {
|
if (ao == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
assert(array_Check(ao));
|
#ifndef NDEBUG
|
||||||
|
assert(array_Check(ao, state));
|
||||||
|
#endif
|
||||||
if (it->index < Py_SIZE(ao)) {
|
if (it->index < Py_SIZE(ao)) {
|
||||||
return (*it->getitem)(ao, it->index++);
|
return (*it->getitem)(ao, it->index++);
|
||||||
}
|
}
|
||||||
|
@ -2872,9 +2894,12 @@ arrayiter_next(arrayiterobject *it)
|
||||||
static void
|
static void
|
||||||
arrayiter_dealloc(arrayiterobject *it)
|
arrayiter_dealloc(arrayiterobject *it)
|
||||||
{
|
{
|
||||||
|
PyTypeObject *tp = Py_TYPE(it);
|
||||||
|
|
||||||
PyObject_GC_UnTrack(it);
|
PyObject_GC_UnTrack(it);
|
||||||
Py_XDECREF(it->ao);
|
Py_XDECREF(it->ao);
|
||||||
PyObject_GC_Del(it);
|
PyObject_GC_Del(it);
|
||||||
|
Py_DECREF(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2932,36 +2957,21 @@ static PyMethodDef arrayiter_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyTypeObject PyArrayIter_Type = {
|
static PyType_Slot arrayiter_slots[] = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
{Py_tp_dealloc, arrayiter_dealloc},
|
||||||
"arrayiterator", /* tp_name */
|
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||||
sizeof(arrayiterobject), /* tp_basicsize */
|
{Py_tp_traverse, arrayiter_traverse},
|
||||||
0, /* tp_itemsize */
|
{Py_tp_iter, PyObject_SelfIter},
|
||||||
/* methods */
|
{Py_tp_iternext, arrayiter_next},
|
||||||
(destructor)arrayiter_dealloc, /* tp_dealloc */
|
{Py_tp_methods, arrayiter_methods},
|
||||||
0, /* tp_vectorcall_offset */
|
{0, NULL},
|
||||||
0, /* tp_getattr */
|
};
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_as_async */
|
static PyType_Spec arrayiter_spec = {
|
||||||
0, /* tp_repr */
|
.name = "array.arrayiterator",
|
||||||
0, /* tp_as_number */
|
.basicsize = sizeof(arrayiterobject),
|
||||||
0, /* tp_as_sequence */
|
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||||
0, /* tp_as_mapping */
|
.slots = arrayiter_slots,
|
||||||
0, /* tp_hash */
|
|
||||||
0, /* tp_call */
|
|
||||||
0, /* tp_str */
|
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
|
||||||
0, /* tp_setattro */
|
|
||||||
0, /* tp_as_buffer */
|
|
||||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
|
|
||||||
0, /* tp_doc */
|
|
||||||
(traverseproc)arrayiter_traverse, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
PyObject_SelfIter, /* tp_iter */
|
|
||||||
(iternextfunc)arrayiter_next, /* tp_iternext */
|
|
||||||
arrayiter_methods, /* tp_methods */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2973,45 +2983,53 @@ static PyMethodDef a_methods[] = {
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CREATE_TYPE(module, type, spec) \
|
||||||
|
do { \
|
||||||
|
type = (PyTypeObject *)PyType_FromModuleAndSpec(m, spec, NULL); \
|
||||||
|
if (type == NULL) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
array_modexec(PyObject *m)
|
array_modexec(PyObject *m)
|
||||||
{
|
{
|
||||||
|
array_state *state = get_array_state(m);
|
||||||
char buffer[Py_ARRAY_LENGTH(descriptors)], *p;
|
char buffer[Py_ARRAY_LENGTH(descriptors)], *p;
|
||||||
PyObject *typecodes;
|
PyObject *typecodes;
|
||||||
const struct arraydescr *descr;
|
const struct arraydescr *descr;
|
||||||
|
|
||||||
if (PyType_Ready(&Arraytype) < 0)
|
CREATE_TYPE(m, state->ArrayType, &array_spec);
|
||||||
return -1;
|
CREATE_TYPE(m, state->ArrayIterType, &arrayiter_spec);
|
||||||
Py_SET_TYPE(&PyArrayIter_Type, &PyType_Type);
|
Py_SET_TYPE(state->ArrayIterType, &PyType_Type);
|
||||||
|
|
||||||
Py_INCREF((PyObject *)&Arraytype);
|
Py_INCREF((PyObject *)state->ArrayType);
|
||||||
if (PyModule_AddObject(m, "ArrayType", (PyObject *)&Arraytype) < 0) {
|
if (PyModule_AddObject(m, "ArrayType", (PyObject *)state->ArrayType) < 0) {
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)state->ArrayType);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *abc_mod = PyImport_ImportModule("collections.abc");
|
PyObject *abc_mod = PyImport_ImportModule("collections.abc");
|
||||||
if (!abc_mod) {
|
if (!abc_mod) {
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)state->ArrayType);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyObject *mutablesequence = PyObject_GetAttrString(abc_mod, "MutableSequence");
|
PyObject *mutablesequence = PyObject_GetAttrString(abc_mod, "MutableSequence");
|
||||||
Py_DECREF(abc_mod);
|
Py_DECREF(abc_mod);
|
||||||
if (!mutablesequence) {
|
if (!mutablesequence) {
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)state->ArrayType);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O", (PyObject *)&Arraytype);
|
PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O",
|
||||||
|
(PyObject *)state->ArrayType);
|
||||||
Py_DECREF(mutablesequence);
|
Py_DECREF(mutablesequence);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)state->ArrayType);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
|
|
||||||
Py_INCREF((PyObject *)&Arraytype);
|
if (PyModule_AddType(m, state->ArrayType) < 0) {
|
||||||
if (PyModule_AddObject(m, "array", (PyObject *)&Arraytype) < 0) {
|
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3035,15 +3053,12 @@ static PyModuleDef_Slot arrayslots[] = {
|
||||||
|
|
||||||
|
|
||||||
static struct PyModuleDef arraymodule = {
|
static struct PyModuleDef arraymodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
.m_base = PyModuleDef_HEAD_INIT,
|
||||||
"array",
|
.m_name = "array",
|
||||||
module_doc,
|
.m_size = sizeof(array_state),
|
||||||
0,
|
.m_doc = module_doc,
|
||||||
a_methods,
|
.m_methods = a_methods,
|
||||||
arrayslots,
|
.m_slots = arrayslots,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,28 @@ PyDoc_STRVAR(array_array_extend__doc__,
|
||||||
"Append items to the end of the array.");
|
"Append items to the end of the array.");
|
||||||
|
|
||||||
#define ARRAY_ARRAY_EXTEND_METHODDEF \
|
#define ARRAY_ARRAY_EXTEND_METHODDEF \
|
||||||
{"extend", (PyCFunction)array_array_extend, METH_O, array_array_extend__doc__},
|
{"extend", (PyCFunction)(void(*)(void))array_array_extend, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, array_array_extend__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
array_array_extend_impl(arrayobject *self, PyTypeObject *cls, PyObject *bb);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
array_array_extend(arrayobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
|
{
|
||||||
|
PyObject *return_value = NULL;
|
||||||
|
static const char * const _keywords[] = {"", NULL};
|
||||||
|
static _PyArg_Parser _parser = {"O:extend", _keywords, 0};
|
||||||
|
PyObject *bb;
|
||||||
|
|
||||||
|
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||||
|
&bb)) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
return_value = array_array_extend_impl(self, cls, bb);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(array_array_insert__doc__,
|
PyDoc_STRVAR(array_array_insert__doc__,
|
||||||
"insert($self, i, v, /)\n"
|
"insert($self, i, v, /)\n"
|
||||||
|
@ -514,4 +535,4 @@ PyDoc_STRVAR(array_arrayiterator___setstate____doc__,
|
||||||
|
|
||||||
#define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF \
|
#define ARRAY_ARRAYITERATOR___SETSTATE___METHODDEF \
|
||||||
{"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, array_arrayiterator___setstate____doc__},
|
{"__setstate__", (PyCFunction)array_arrayiterator___setstate__, METH_O, array_arrayiterator___setstate____doc__},
|
||||||
/*[clinic end generated code: output=91c1cded65a1285f input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=a7f71a18b994c88f input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -34,7 +34,7 @@ is_generic_alias_in_args(PyObject *args) {
|
||||||
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
|
||||||
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
|
for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) {
|
||||||
PyObject *arg = PyTuple_GET_ITEM(args, iarg);
|
PyObject *arg = PyTuple_GET_ITEM(args, iarg);
|
||||||
if (Py_TYPE(arg) == &Py_GenericAliasType) {
|
if (PyObject_TypeCheck(arg, &Py_GenericAliasType)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue