Commit c1bbe81a authored by Stefan Behnel's avatar Stefan Behnel

enable except-as target deletion only when language level is 3

parent f49d1f6f
......@@ -1573,7 +1573,8 @@ def p_except_clause(s):
exc_type = exc_type.args
else:
exc_type = [exc_type]
if s.sy == ',':
if s.sy == ',' or (s.sy == 'IDENT' and s.systring == 'as'
and s.context.language_level == 2):
s.next()
exc_value = p_test(s)
elif s.sy == 'IDENT' and s.systring == 'as':
......
# cython: language_level=3
# mode: run
# tag: generators, python3
# tag: generators, python3, exceptions
cimport cython
......@@ -11,6 +11,11 @@ __doc__ = """
a = 1
b = 2
x = u'abc'
>>> except_as_deletes
True
>>> no_match_does_not_touch_target
True
"""
import sys
......@@ -22,6 +27,115 @@ def locals_function(a, b=2):
return locals()
### module level except-as tests
exc = [None]
e = None
try:
raise KeyError
except AttributeError as e:
exc[0] = e
except KeyError as e:
exc[0] = e
except IndexError as e:
exc[0] = e
except:
exc[0] = 'SOMETHING ELSE'
try:
e
except NameError:
except_as_deletes = True
else:
except_as_deletes = False
e = 123
try:
raise TypeError
except NameError as e:
pass
except TypeError:
pass
no_match_does_not_touch_target = (e == 123)
### more except-as tests
def except_as_raise_deletes_target(x, a):
"""
>>> except_as_raise_deletes_target(None, TypeError)
1
1
>>> except_as_raise_deletes_target(TypeError('test'), TypeError)
Traceback (most recent call last):
UnboundLocalError: local variable 'b' referenced before assignment
>>> except_as_raise_deletes_target(ValueError('test'), TypeError)
Traceback (most recent call last):
ValueError: test
>>> except_as_raise_deletes_target(None, TypeError)
1
1
"""
b = 1
try:
i = 1
if x:
raise x
except a as b:
i = 2
assert isinstance(b, a)
print(b) # raises UnboundLocalError if except clause was executed
return i
def except_as_raise_with_empty_except(x, a):
"""
>>> except_as_raise_with_empty_except(None, TypeError)
>>> except_as_raise_with_empty_except(TypeError('test'), TypeError)
>>> except_as_raise_with_empty_except(ValueError('test'), TypeError)
Traceback (most recent call last):
ValueError: test
>>> except_as_raise_with_empty_except(None, TypeError)
"""
try:
if x:
raise x
b = 1
except a as b: # previously raised UnboundLocalError
pass
def except_as_deletes_target_in_gen(x, a):
"""
>>> list(except_as_deletes_target_in_gen(None, TypeError))
[(1, 1), (2, 1), (5, 1)]
>>> list(except_as_deletes_target_in_gen(TypeError('test'), TypeError))
[(1, 1), 3, 6]
>>> list(except_as_deletes_target_in_gen(ValueError('test'), TypeError))
[(1, 1), (4, 1), (5, 1)]
"""
b = 1
try:
i = 1
yield (1, b)
if x:
raise x
yield (2, b)
except a as b:
i = 2
assert isinstance(b, a)
yield 3
except:
yield (4, b)
try:
yield (5, b)
except UnboundLocalError:
yield 6
### Py3 feature tests
def print_function(*args):
"""
>>> print_function(1,2,3)
......@@ -29,6 +143,7 @@ def print_function(*args):
"""
print(*args) # this isn't valid Py2 syntax
def exec3_function(cmd):
"""
>>> exec3_function('a = 1+1')['a']
......
......@@ -14,9 +14,9 @@ __doc__ = u"""
>>> exc[3] is val
True
>>> except_as_deletes
True
>>> no_match_does_not_delete
>>> except_as_deletes # Py2 behaviour
False
>>> no_match_does_not_touch_target
True
"""
......@@ -81,7 +81,7 @@ except NameError as e:
pass
except TypeError:
pass
no_match_does_not_delete = (e == 123)
no_match_does_not_touch_target = (e == 123)
try:
raise IndexError
......
......@@ -358,19 +358,16 @@ def except_as_no_raise_does_not_touch_target(a):
i = 2
return i, b
def except_as_raise_deletes_target(x, a):
def except_as_raise_does_not_delete_target(x, a):
"""
>>> except_as_raise_deletes_target(None, TypeError)
>>> except_as_raise_does_not_delete_target(None, TypeError)
1
1
>>> except_as_raise_deletes_target(TypeError('test'), TypeError)
Traceback (most recent call last):
UnboundLocalError: local variable 'b' referenced before assignment
>>> except_as_raise_deletes_target(ValueError('test'), TypeError)
>>> except_as_raise_does_not_delete_target(TypeError('test'), TypeError)
2
>>> except_as_raise_does_not_delete_target(ValueError('test'), TypeError)
Traceback (most recent call last):
ValueError: test
>>> except_as_raise_deletes_target(None, TypeError)
1
>>> except_as_raise_does_not_delete_target(None, TypeError)
1
"""
b = 1
......@@ -381,7 +378,12 @@ def except_as_raise_deletes_target(x, a):
except a as b:
i = 2
assert isinstance(b, a)
print(b) # raises UnboundLocalError if except clause was executed
# exception variable leaks with Py2 except-as semantics
if x:
assert isinstance(b, a)
else:
assert b == 1
return i
def except_as_raise_with_empty_except(x, a):
......@@ -397,35 +399,12 @@ def except_as_raise_with_empty_except(x, a):
if x:
raise x
b = 1
except a as b: # previously raised UnboundLocalError
pass
def except_as_deletes_target_in_gen(x, a):
"""
>>> list(except_as_deletes_target_in_gen(None, TypeError))
[(1, 1), (2, 1), (5, 1)]
>>> list(except_as_deletes_target_in_gen(TypeError('test'), TypeError))
[(1, 1), 3, 6]
>>> list(except_as_deletes_target_in_gen(ValueError('test'), TypeError))
[(1, 1), (4, 1), (5, 1)]
"""
b = 1
try:
i = 1
yield (1, b)
if x:
raise x
yield (2, b)
except a as b:
i = 2
pass
if x:
assert isinstance(b, a)
yield 3
except:
yield (4, b)
try:
yield (5, b)
except UnboundLocalError:
yield 6
else:
assert b == 1
def complete_except_as_no_raise(a, b):
"""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment