diff options
Diffstat (limited to 'tests/run/genexpr_arg_order.py')
-rw-r--r-- | tests/run/genexpr_arg_order.py | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/tests/run/genexpr_arg_order.py b/tests/run/genexpr_arg_order.py new file mode 100644 index 000000000..5b9e27238 --- /dev/null +++ b/tests/run/genexpr_arg_order.py @@ -0,0 +1,181 @@ +# mode: run +# tag: genexpr, py3, py2 + +from __future__ import print_function + +# Tests that function arguments to generator expressions are +# evaluated in the correct order (even after optimization) +# WARNING: there may be an amount of luck in this working correctly (since it +# isn't strictly enforced). Therefore perhaps be prepared to disable these +# tests if they stop working and aren't easily fixed + +import cython + +@cython.cfunc +@cython.returns(cython.int) +def zero(): + print("In zero") + return 0 + +@cython.cfunc +@cython.returns(cython.int) +def five(): + print("In five") + return 5 + +@cython.cfunc +@cython.returns(cython.int) +def one(): + print("In one") + return 1 + +# FIXME - I don't think this is easy to enforce unfortunately, but it is slightly wrong +#@cython.test_assert_path_exists("//ForFromStatNode") +#def genexp_range_argument_order(): +# """ +# >>> list(genexp_range_argument_order()) +# In zero +# In five +# [0, 1, 2, 3, 4] +# """ +# return (a for a in range(zero(), five())) +# +#@cython.test_assert_path_exists("//ForFromStatNode") +#@cython.test_assert_path_exists( +# "//InlinedGeneratorExpressionNode", +# "//ComprehensionAppendNode") +#def list_range_argument_order(): +# """ +# >>> list_range_argument_order() +# In zero +# In five +# [0, 1, 2, 3, 4] +# """ +# return list(a for a in range(zero(), five())) + +@cython.test_assert_path_exists("//ForFromStatNode") +def genexp_array_slice_order(): + """ + >>> list(genexp_array_slice_order()) + In zero + In five + [0, 1, 2, 3, 4] + """ + # TODO ideally find a way to add the evaluation of x to this test too + x = cython.declare(cython.int[20]) + x = list(range(20)) + return (a for a in x[zero():five()]) + +@cython.test_assert_path_exists("//ForFromStatNode") +@cython.test_assert_path_exists( + "//InlinedGeneratorExpressionNode", + "//ComprehensionAppendNode") +def list_array_slice_order(): + """ + >>> list(list_array_slice_order()) + In zero + In five + [0, 1, 2, 3, 4] + """ + # TODO ideally find a way to add the evaluation of x to this test too + x = cython.declare(cython.int[20]) + x = list(range(20)) + return list(a for a in x[zero():five()]) + +class IndexableClass: + def __getitem__(self, idx): + print("In indexer") + return [ idx.start, idx.stop, idx.step ] + +class NoisyAttributeLookup: + @property + def indexer(self): + print("Getting indexer") + return IndexableClass() + + @property + def function(self): + print("Getting function") + def func(a, b, c): + print("In func") + return [a, b, c] + return func + +def genexp_index_order(): + """ + >>> list(genexp_index_order()) + Getting indexer + In zero + In five + In one + In indexer + Made generator expression + [0, 5, 1] + """ + obj = NoisyAttributeLookup() + ret = (a for a in obj.indexer[zero():five():one()]) + print("Made generator expression") + return ret + +@cython.test_assert_path_exists("//InlinedGeneratorExpressionNode") +def list_index_order(): + """ + >>> list_index_order() + Getting indexer + In zero + In five + In one + In indexer + [0, 5, 1] + """ + obj = NoisyAttributeLookup() + return list(a for a in obj.indexer[zero():five():one()]) + + +def genexpr_fcall_order(): + """ + >>> list(genexpr_fcall_order()) + Getting function + In zero + In five + In one + In func + Made generator expression + [0, 5, 1] + """ + obj = NoisyAttributeLookup() + ret = (a for a in obj.function(zero(), five(), one())) + print("Made generator expression") + return ret + +@cython.test_assert_path_exists("//InlinedGeneratorExpressionNode") +def list_fcall_order(): + """ + >>> list_fcall_order() + Getting function + In zero + In five + In one + In func + [0, 5, 1] + """ + obj = NoisyAttributeLookup() + return list(a for a in obj.function(zero(), five(), one())) + +def call1(): + print("In call1") + return ["a"] +def call2(): + print("In call2") + return ["b"] + +def multiple_genexps_to_call_order(): + """ + >>> multiple_genexps_to_call_order() + In call1 + In call2 + """ + def takes_two_genexps(a, b): + pass + + return takes_two_genexps((x for x in call1()), (x for x in call2())) |