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
|
# ticket: t228
__doc__ = u"""
>>> def py_iterator():
... if True: return
... yield None
>>> list(py_iterator())
[]
>>> list(cy_iterator())
[]
>>> try:
... raise ValueError
... except:
... print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
... a = list(py_iterator())
... print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
True
True
>>> print(sys.exc_info()[0] is None or sys.exc_info()[0])
True
>>> try:
... raise ValueError
... except:
... print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
... a = list(py_iterator())
... print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
... a = list(cy_iterator())
... print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
True
True
True
>>> print(sys.exc_info()[0] is None or sys.exc_info()[0])
True
>>> double_raise(py_iterator)
True
True
True
>>> print(sys.exc_info()[0] is None or sys.exc_info()[0])
True
"""
import sys
if sys.version_info[0] < 3:
sys.exc_clear()
cdef class cy_iterator(object):
def __iter__(self):
return self
def __next__(self):
raise StopIteration
def double_raise(py_iterator):
try:
raise ValueError
except:
print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
a = list(py_iterator())
print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
a = list(cy_iterator())
print(sys.exc_info()[0] is ValueError or sys.exc_info()[0])
###### Tests to do with the optimization of StopIteration to "return NULL" #######
# we're mainly checking that
# 1. Calling __next__ manually doesn't crash (the wrapper function adds the exception)
# 2. if you raise a value then that value gets raised
# 3. putting the exception in various places try...finally / try...except blocks works
def call_next_directly():
"""
>>> call_next_directly()
Traceback (most recent call last):
...
StopIteration
"""
cy_iterator().__next__()
cdef class cy_iter_many_options:
cdef what
def __init__(self, what):
self.what = what
def __iter__(self):
return self
def __next__(self):
if self.what == "StopIteration in finally no return":
try:
raise StopIteration
finally:
print "Finally..."
elif self.what == "StopIteration in finally return":
try:
raise StopIteration
finally:
self.what = None
return "in finally" # but will stop iterating next time
elif self.what == "StopIteration from finally":
try:
raise ValueError
finally:
raise StopIteration
elif self.what == "catch StopIteration":
try:
raise StopIteration
except StopIteration:
self.what = None
return "in except" # but will stop next time
elif self.what == "don't catch StopIteration":
try:
raise StopIteration
except ValueError:
return 0
elif self.what == "StopIteration from except":
try:
raise ValueError
except ValueError:
raise StopIteration
elif self.what == "StopIteration with value":
raise StopIteration("I'm a value!")
elif self.what is None:
raise StopIteration
else:
raise ValueError("self.what didn't match anything")
def test_cy_iter_many_options(option):
"""
>>> test_cy_iter_many_options("StopIteration in finally no return")
Finally...
[]
>>> test_cy_iter_many_options("StopIteration in finally return")
['in finally']
>>> test_cy_iter_many_options("StopIteration from finally")
[]
>>> test_cy_iter_many_options("catch StopIteration")
['in except']
>>> test_cy_iter_many_options("don't catch StopIteration")
[]
>>> try:
... cy_iter_many_options("StopIteration with value").__next__()
... except StopIteration as e:
... print(e.args)
("I'm a value!",)
"""
return list(cy_iter_many_options(option))
|