Skip to content

Commit a61428c

Browse files
committed
Add tests for 'PySequence_*' functions.
1 parent 76dfd66 commit a61428c

File tree

3 files changed

+188
-11
lines changed

3 files changed

+188
-11
lines changed

graalpython/com.oracle.graal.python.cext/src/abstract.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,17 +227,16 @@ Py_ssize_t PySequence_Length(PyObject *s) {
227227
}
228228
#define PySequence_Length PySequence_Size
229229

230-
PyObject* PySequence_GetItem(PyObject *s, Py_ssize_t i)
231-
{
232-
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PyObject_GetItem", to_java(s), i, ERROR_MARKER);
230+
PyObject* PySequence_GetItem(PyObject *s, Py_ssize_t i) {
231+
void* result = polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_GetItem", to_java(s), i, ERROR_MARKER);
233232
if(result == ERROR_MARKER) {
234233
return NULL;
235234
}
236235
return to_sulong(result);
237236
}
238237

239238
int PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) {
240-
return polyglot_as_i32(polyglot_invoke(PY_TRUFFLE_CEXT, "PyObject_SetItem", to_java(s), i, to_java(o)));
239+
return polyglot_as_i32(polyglot_invoke(PY_TRUFFLE_CEXT, "PySequence_SetItem", to_java(s), i, to_java(o)));
241240
}
242241

243242
PyObject* PySequence_Tuple(PyObject *v) {

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

Lines changed: 156 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,40 @@ def _reference_next(args):
8686
raise SystemError
8787

8888

89+
def _reference_size(args):
90+
seq = args[0]
91+
if isinstance(seq, dict):
92+
return -1
93+
if not hasattr(seq, '__len__'):
94+
raise TypeError()
95+
return len(seq)
96+
97+
98+
def _reference_getitem(args):
99+
seq = args[0]
100+
idx = args[1]
101+
if not hasattr(seq, '__getitem__'):
102+
raise TypeError
103+
return seq.__getitem__(idx)
104+
105+
106+
def _reference_setitem(args):
107+
seq = args[0]
108+
idx = args[1]
109+
value = args[2]
110+
if not hasattr(seq, '__setitem__'):
111+
raise TypeError
112+
seq.__setitem__(idx, value)
113+
return seq
114+
115+
116+
def _reference_fast(args):
117+
obj = args[0]
118+
if isinstance(obj, tuple) or isinstance(obj, list):
119+
return obj
120+
return list(obj)
121+
122+
89123
class NoNumber():
90124
pass
91125

@@ -146,10 +180,10 @@ def _default_bin_arith_args():
146180
)
147181

148182

149-
class TestPyNumber(CPyExtTestCase):
183+
class TestAbstract(CPyExtTestCase):
150184
def compile_module(self, name):
151185
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
152-
super(TestPyNumber, self).compile_module(name)
186+
super(TestAbstract, self).compile_module(name)
153187

154188

155189
test_PyNumber_Check = CPyExtFunction(
@@ -440,11 +474,6 @@ def compile_module(self, name):
440474
cmpfunc=unhandled_error_compare
441475
)
442476

443-
class TestPySequence(CPyExtTestCase):
444-
def compile_module(self, name):
445-
type(self).mro()[1].__dict__["test_%s" % name].create_module(name)
446-
super(TestPySequence, self).compile_module(name)
447-
448477
test_PySequence_Fast_GET_SIZE = CPyExtFunction(
449478
lambda args: len(args[0]),
450479
lambda: (
@@ -561,3 +590,123 @@ def compile_module(self, name):
561590
arguments=["PyObject* sequence"],
562591
)
563592

593+
test_PySequence_Size = CPyExtFunction(
594+
_reference_size,
595+
lambda: (
596+
(tuple(),),
597+
((1,2,3),),
598+
((None,),),
599+
([],),
600+
(['a','b','c'],),
601+
([None],),
602+
(set(),),
603+
(DummyListSubclass(),),
604+
),
605+
resultspec="n",
606+
argspec='O',
607+
arguments=["PyObject* sequence"],
608+
cmpfunc=unhandled_error_compare
609+
)
610+
611+
# 'PySequence_Length' is just a redefinition of 'PySequence_Size'
612+
test_PySequence_Length = test_PySequence_Size
613+
614+
test_PySequence_GetItem = CPyExtFunction(
615+
_reference_getitem,
616+
lambda: (
617+
(tuple(), 10),
618+
((1,2,3), 2),
619+
((None,), 0),
620+
([], 10),
621+
(['a','b','c'], 2),
622+
([None], 0),
623+
(set(), 0),
624+
({'a', 'b'}, 0),
625+
(DummyListSubclass(), 1),
626+
),
627+
resultspec="O",
628+
argspec='On',
629+
arguments=["PyObject* sequence", "Py_ssize_t idx"],
630+
cmpfunc=unhandled_error_compare
631+
)
632+
633+
test_PySequence_SetItem = CPyExtFunction(
634+
_reference_setitem,
635+
lambda: (
636+
(tuple(), 0, 'a'),
637+
((1,2,3), 2, 99),
638+
((None,), 1, None),
639+
([], 10, 1),
640+
(['a','b','c'], 2, 'z'),
641+
),
642+
code=''' PyObject* wrap_PySequence_SetItem(PyObject* sequence, Py_ssize_t idx, PyObject* value) {
643+
if (PySequence_SetItem(sequence, idx, value) < 0) {
644+
return NULL;
645+
}
646+
return sequence;
647+
}
648+
''',
649+
resultspec="O",
650+
argspec='OnO',
651+
arguments=["PyObject* sequence", "Py_ssize_t idx", "PyObject* value"],
652+
callfunction="wrap_PySequence_SetItem",
653+
cmpfunc=unhandled_error_compare
654+
)
655+
656+
test_PySequence_Tuple = CPyExtFunction(
657+
lambda args: tuple(args[0]),
658+
lambda: (
659+
(tuple(), ),
660+
((1,2,3), ),
661+
((None,), ),
662+
([], ),
663+
(['a','b','c'],),
664+
({'a','b','c'},),
665+
({'a': 0,'b': 1,'c': 2},),
666+
(None,),
667+
(0,),
668+
),
669+
resultspec="O",
670+
argspec='O',
671+
arguments=["PyObject* sequence"],
672+
cmpfunc=unhandled_error_compare
673+
)
674+
675+
test_PySequence_Fast = CPyExtFunction(
676+
_reference_fast,
677+
lambda: (
678+
(tuple(), "should not be an error"),
679+
((1,2,3), "should not be an error"),
680+
((None,), "should not be an error"),
681+
([], "should not be an error"),
682+
(['a','b','c'],"should not be an error"),
683+
({'a','b','c'}, "should not be an error"),
684+
({'a': 0,'b': 1,'c': 2}, "should not be an error"),
685+
(None, "None cannot be a sequence"),
686+
(0, "int cannot be a sequence"),
687+
),
688+
resultspec="O",
689+
argspec='Os',
690+
arguments=["PyObject* sequence", "char* error_msg"],
691+
cmpfunc=unhandled_error_compare
692+
)
693+
694+
# test_PyMapping_GetItemString = CPyExtFunction(
695+
# _reference_fast,
696+
# lambda: (
697+
# (tuple(), "should not be an error"),
698+
# ((1,2,3), "should not be an error"),
699+
# ((None,), "should not be an error"),
700+
# ([], "should not be an error"),
701+
# #(['a','b','c'],"should not be an error"),
702+
# #({'a','b','c'}, "should not be an error"),
703+
# #({'a': 0,'b': 1,'c': 2}, "should not be an error"),
704+
# #(None, "None cannot be a sequence"),
705+
# #(0, "int cannot be a sequence"),
706+
# ),
707+
# resultspec="O",
708+
# argspec='Os',
709+
# arguments=["PyObject* sequence", "char* error_msg"],
710+
# cmpfunc=unhandled_error_compare
711+
# )
712+

graalpython/lib-graalpython/python_cext.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,35 @@ def PySequence_Check(obj):
499499
return hasattr(obj, '__getitem__')
500500

501501

502+
def PySequence_GetItem(obj, key, error_marker):
503+
typ = val = tb = None
504+
try:
505+
if not hasattr(obj, '__getitem__'):
506+
raise TypeError("'%s' object does not support indexing)" % repr(obj))
507+
if len(obj) < 0:
508+
return error_marker
509+
return obj[key]
510+
except BaseException as e:
511+
typ, val, tb = sys.exc_info()
512+
PyErr_Restore(typ, val, tb)
513+
return error_marker
514+
515+
516+
def PySequence_SetItem(obj, key, value):
517+
typ = val = tb = None
518+
try:
519+
if not hasattr(obj, '__setitem__'):
520+
raise TypeError("'%s' object does not support item assignment)" % repr(obj))
521+
if len(obj) < 0:
522+
return -1
523+
obj.__setitem__(key, value)
524+
return 0
525+
except BaseException as e:
526+
typ, val, tb = sys.exc_info()
527+
PyErr_Restore(typ, val, tb)
528+
return -1
529+
530+
502531
##################### UNICODE
503532

504533

0 commit comments

Comments
 (0)