1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 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()))
|