Skip to content

Commit e709ee9

Browse files
committed
[GR-70731] Fix PyMapping_(Items|Keys|Values) with dict subclasses
PullRequest: graalpython/4051
2 parents 947a59b + bf8a2b2 commit e709ee9

File tree

3 files changed

+121
-69
lines changed

3 files changed

+121
-69
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_abstract.py

Lines changed: 100 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@
4040
import array
4141
import collections
4242
import mmap
43-
import os
4443
import sys
4544
import unittest
46-
from unittest import skipIf
45+
from collections import OrderedDict
4746

4847
from . import CPyExtTestCase, CPyExtFunction, CPyExtType, unhandled_error_compare
4948

49+
ORDERED_DICT = OrderedDict({'c': 3, 'a': 1, 'b': 2})
50+
ORDERED_DICT.move_to_end('c')
51+
assert list(ORDERED_DICT.items()) == [('a', 1), ('b', 2), ('c', 3)]
5052

5153
def _safe_check(v, type_check):
5254
try:
@@ -110,58 +112,58 @@ def raise_type_error():
110112

111113
def _reference_seq_size(args):
112114
seq = args[0]
113-
115+
114116
if istypeof(seq, [dict, type(type.__dict__)]):
115-
# checking for the exact type
117+
# checking for the exact type
116118
# even if a dict or mappingproxy isn't accepted
117-
# a subclass with overriden __len__ is
118-
raise_type_error()
119-
119+
# a subclass with overriden __len__ is
120+
raise_type_error()
121+
120122
return len(seq)
121123

122124
def _reference_mapping_size(args):
123125
m = args[0]
124-
126+
125127
if istypeof(m, [set, frozenset, collections.deque]):
126-
# checking for the exact type
128+
# checking for the exact type
127129
# even if a set or deque isn't accepted
128-
# a subclass with overriden __len__ is
129-
raise_type_error()
130-
130+
# a subclass with overriden __len__ is
131+
raise_type_error()
132+
131133
try:
132-
return len(m)
134+
return len(m)
133135
except:
134136
pass
135-
137+
136138
raise_type_error()
137-
139+
138140
def _reference_object_size(args):
139-
obj = args[0]
140-
141+
obj = args[0]
142+
141143
try:
142144
return len(obj)
143145
except:
144146
pass
145-
147+
146148
raise_type_error()
147149

148150
def _reference_sequence_check(args):
149151
obj = args[0]
150152

151153
if isinstanceof(obj, [dict, type(type.__dict__), set, frozenset]):
152-
return False
153-
154+
return False
155+
154156
return hasattr(obj, '__getitem__')
155157

156158
def _reference_mapping_check(args):
157159
obj = args[0]
158-
160+
159161
if isinstanceof(obj, [collections.deque]):
160-
return False
161-
162+
return False
163+
162164
if isinstanceof(obj, [array.array, bytearray, bytes, dict, type(type.__dict__), list, memoryview, range]):
163165
return True
164-
166+
165167
return hasattr(obj, '__getitem__')
166168

167169
def isinstanceof(obj, types):
@@ -257,37 +259,37 @@ class DummySequence():
257259

258260
def __getitem__(self, idx):
259261
raise IndexError
260-
262+
261263
class DummyLen():
262264
def __len__(self):
263265
return 42
264-
266+
265267
class DummyDict(dict):
266268
pass
267269

268-
class DummyDictLen(dict):
270+
class DummyDictLen(dict):
269271
def __len__(self):
270272
return 42
271-
273+
272274

273275
class DummyListSubclass(list):
274276
pass
275277

276-
class DummyListLen(list):
278+
class DummyListLen(list):
277279
def __len__(self):
278280
return 42
279-
280-
class DummySet(set):
281+
282+
class DummySet(set):
281283
pass
282-
283-
class DummySetLen(set):
284+
285+
class DummySetLen(set):
284286
def __len__(self):
285287
return 42
286-
287-
class DummyDeque(set):
288+
289+
class DummyDeque(set):
288290
pass
289-
290-
class DummyDequeLen(set):
291+
292+
class DummyDequeLen(set):
291293
def __len__(self):
292294
return 42
293295

@@ -401,7 +403,7 @@ def _size_and_check_args():
401403
(DummySet([1,2,3]),),
402404
(DummySetLen(),),
403405
(DummySetLen([1,2,3]),),
404-
({1,2,3},),
406+
({1,2,3},),
405407
(frozenset({1,2,3}),),
406408
(dict(),),
407409
({'a':0, 'b':1},),
@@ -417,14 +419,14 @@ def _size_and_check_args():
417419
(bytearray(b'abc'),),
418420
(memoryview(b'abc'),),
419421
(array.array('I', [1,2,3]),),
420-
(collections.deque([1,2,3,]),),
421-
(DummyDeque(),),
422-
(DummyDeque([1,2,3]),),
423-
(DummyDequeLen(),),
422+
(collections.deque([1,2,3,]),),
423+
(DummyDeque(),),
424+
(DummyDeque([1,2,3]),),
425+
(DummyDequeLen(),),
424426
(DummyDequeLen([1,2,3]),),
425427
(DictSubclassWithSequenceMethods(),),
426428
)
427-
429+
428430
class TestAbstractWithNative(unittest.TestCase):
429431
def test_sequence_check(self):
430432
TestSequenceCheck = CPyExtType("TestSequenceCheck",
@@ -462,7 +464,7 @@ def test_sequence_size(self):
462464
)
463465
tester = TestSequenceSize()
464466
assert tester.callSize(tester) == 10
465-
467+
466468
def test_sequence_size_err(self):
467469
TestSequenceSizeErr = CPyExtType("TestSequenceSizeErr",
468470
"""
@@ -481,14 +483,14 @@ def test_sequence_size_err(self):
481483
tp_methods='{"callSize", (PyCFunction)callSize, METH_O, ""}',
482484
sq_length="&test_sq_length",
483485
)
484-
tester = TestSequenceSizeErr()
486+
tester = TestSequenceSizeErr()
485487
try:
486488
tester.callSize(tester)
487489
except TypeError:
488490
assert True
489491
else:
490492
assert False
491-
493+
492494
def test_sequence_size_err2(self):
493495
TestSequenceSizeErr2 = CPyExtType("TestSequenceSizeErr2",
494496
"""
@@ -507,14 +509,14 @@ def test_sequence_size_err2(self):
507509
tp_methods='{"callSize", (PyCFunction)callSize, METH_O, ""}',
508510
sq_length="&test_sq_length",
509511
)
510-
tester = TestSequenceSizeErr2()
512+
tester = TestSequenceSizeErr2()
511513
try:
512514
tester.callSize(tester)
513515
except TypeError:
514516
assert True
515517
else:
516-
assert False
517-
518+
assert False
519+
518520
def test_mapping_check(self):
519521
TestMappingCheck = CPyExtType("TestMappingCheck",
520522
"""
@@ -531,7 +533,7 @@ def test_mapping_check(self):
531533
)
532534
tester = TestMappingCheck()
533535
assert tester.callCheck(tester)
534-
536+
535537
def test_mapping_size(self):
536538
TestMappingSize = CPyExtType("TestMappingSize",
537539
"""
@@ -551,7 +553,7 @@ def test_mapping_size(self):
551553
)
552554
tester = TestMappingSize()
553555
assert tester.callSize(tester) == 11
554-
556+
555557
def test_mapping_size_err(self):
556558
TestMappingSizeErr = CPyExtType("TestMappingSizeErr",
557559
"""
@@ -570,14 +572,14 @@ def test_mapping_size_err(self):
570572
tp_methods='{"callSize", (PyCFunction)callSize, METH_O, ""}',
571573
mp_length="&test_mp_length",
572574
)
573-
tester = TestMappingSizeErr()
575+
tester = TestMappingSizeErr()
574576
try:
575577
tester.callSize(tester)
576578
except TypeError:
577579
assert True
578580
else:
579581
assert False
580-
582+
581583
def test_object_size_sq(self):
582584
TestObjectSizeSQ = CPyExtType("TestObjectSizeSQ",
583585
"""
@@ -597,7 +599,7 @@ def test_object_size_sq(self):
597599
)
598600
tester = TestObjectSizeSQ()
599601
assert tester.callSize(tester) == 12
600-
602+
601603
def test_object_size_mp(self):
602604
TestObjectSizeMP = CPyExtType("TestObjectSizeMP",
603605
"""
@@ -616,8 +618,8 @@ def test_object_size_mp(self):
616618
mp_length="&test_sq_length",
617619
)
618620
tester = TestObjectSizeMP()
619-
assert tester.callSize(tester) == 13
620-
621+
assert tester.callSize(tester) == 13
622+
621623
def test_object_size_err(self):
622624
TestObjectSizeErr = CPyExtType("TestObjectSizeErr",
623625
"""
@@ -1085,7 +1087,7 @@ class TestAbstract(CPyExtTestCase):
10851087

10861088
test_PySequence_Fast_GET_SIZE = CPyExtFunction(
10871089
lambda args: len(args[0]),
1088-
lambda: (
1090+
lambda: (
10891091
(tuple(),),
10901092
(list(),),
10911093
((1, 2, 3),),
@@ -1240,7 +1242,7 @@ class TestAbstract(CPyExtTestCase):
12401242
arguments=["PyObject* sequence", "Py_ssize_t ilow", "Py_ssize_t ihigh"],
12411243
cmpfunc=unhandled_error_compare
12421244
)
1243-
1245+
12441246
test_PySequence_Contains = CPyExtFunction(
12451247
lambda args: args[1] in args[0],
12461248
lambda: (
@@ -1422,7 +1424,7 @@ def _reference_delslice(args):
14221424
arguments=["PyObject* sequence"],
14231425
cmpfunc=unhandled_error_compare
14241426
)
1425-
1427+
14261428
test_PySequence_List = CPyExtFunction(
14271429
lambda args: list(args[0]),
14281430
lambda: (
@@ -1528,16 +1530,52 @@ def _reference_delslice(args):
15281530
argspec='O',
15291531
arguments=["PyObject* mapping"],
15301532
)
1531-
1533+
15321534
test_PyMapping_Size = CPyExtFunction(
15331535
_reference_mapping_size,
15341536
_size_and_check_args,
15351537
resultspec="n",
15361538
argspec='O',
15371539
arguments=["PyObject* mapping"],
15381540
cmpfunc=unhandled_error_compare
1539-
)
1540-
1541+
)
1542+
1543+
test_PyMapping_Keys = CPyExtFunction(
1544+
lambda args: list(args[0].keys()),
1545+
lambda: (
1546+
({'a': 1, 'b': 2},),
1547+
(ORDERED_DICT,),
1548+
),
1549+
argspec='O',
1550+
resultspec='O',
1551+
arguments=["PyObject* mapping"],
1552+
cmpfunc=unhandled_error_compare,
1553+
)
1554+
1555+
test_PyMapping_Values = CPyExtFunction(
1556+
lambda args: list(args[0].values()),
1557+
lambda: (
1558+
({'a': 1, 'b': 2},),
1559+
(ORDERED_DICT,),
1560+
),
1561+
argspec='O',
1562+
resultspec='O',
1563+
arguments=["PyObject* mapping"],
1564+
cmpfunc=unhandled_error_compare,
1565+
)
1566+
1567+
test_PyMapping_Items = CPyExtFunction(
1568+
lambda args: list(args[0].items()),
1569+
lambda: (
1570+
({'a': 1, 'b': 2},),
1571+
(ORDERED_DICT,),
1572+
),
1573+
argspec='O',
1574+
resultspec='O',
1575+
arguments=["PyObject* mapping"],
1576+
cmpfunc=unhandled_error_compare,
1577+
)
1578+
15411579
test_PyIndex_Check = CPyExtFunction(
15421580
lambda args: hasattr(args[0], "__index__"),
15431581
lambda: (

0 commit comments

Comments
 (0)