4
4
5
5
raise -> raise
6
6
raise E -> raise E
7
- raise E, V -> raise E(V)
7
+ raise E, 5 -> raise E(5)
8
+ raise E, 5, T -> raise E(5).with_traceback(T)
9
+ raise E, None, T -> raise E.with_traceback(T)
8
10
9
- raise (((E, E'), E''), E'''), V -> raise E(V)
11
+ raise (((E, E'), E''), E'''), 5 -> raise E(5)
12
+ raise "foo", V, T -> warns about string exceptions
10
13
14
+ raise E, (V1, V2) -> raise E(V1, V2)
15
+ raise E, (V1, V2), T -> raise E(V1, V2).with_traceback(T)
11
16
12
- CAVEATS:
13
- 1) "raise E, V" will be incorrectly translated if V is an exception
14
- instance. The correct Python 3 idiom is
15
17
16
- raise E from V
18
+ CAVEATS:
19
+ 1) "raise E, V, T" cannot be translated safely in general. If V
20
+ is not a tuple or a (number, string, None) literal, then:
17
21
18
- but since we can't detect instance-hood by syntax alone and since
19
- any client code would have to be changed as well, we don't automate
20
- this.
22
+ raise E, V, T -> from future.utils import raise_
23
+ raise_(E, V, T)
21
24
"""
22
- # Author: Collin Winter, Armin Ronacher
25
+ # Author: Collin Winter, Armin Ronacher, Mark Huang
23
26
24
27
# Local imports
25
28
from lib2to3 import pytree , fixer_base
26
29
from lib2to3 .pgen2 import token
27
- from lib2to3 .fixer_util import Name , Call , is_tuple
30
+ from lib2to3 .fixer_util import Name , Call , is_tuple , Comma , Attr , ArgList
31
+
32
+ from libfuturize .fixer_util import touch_import_top
33
+
28
34
29
35
class FixRaise (fixer_base .BaseFix ):
30
36
31
37
BM_compatible = True
32
38
PATTERN = """
33
- raise_stmt< 'raise' exc=any [',' val=any] >
39
+ raise_stmt< 'raise' exc=any [',' val=any [',' tb=any] ] >
34
40
"""
35
41
36
42
def transform (self , node , results ):
@@ -55,19 +61,47 @@ def transform(self, node, results):
55
61
exc = exc .children [1 ].children [0 ].clone ()
56
62
exc .prefix = u" "
57
63
58
- if "val" not in results :
59
- # One-argument raise
60
- new = pytree .Node (syms .raise_stmt , [Name (u"raise" ), exc ])
61
- new .prefix = node .prefix
62
- return new
63
-
64
- val = results ["val" ].clone ()
65
- if is_tuple (val ):
66
- args = [c .clone () for c in val .children [1 :- 1 ]]
64
+ if "tb" in results :
65
+ tb = results ["tb" ].clone ()
66
+ else :
67
+ tb = None
68
+
69
+ if "val" in results :
70
+ val = results ["val" ].clone ()
71
+ if is_tuple (val ):
72
+ # Assume that exc is a subclass of Exception and call exc(*val).
73
+ args = [c .clone () for c in val .children [1 :- 1 ]]
74
+ exc = Call (exc , args )
75
+ elif val .type in (token .NUMBER , token .STRING ):
76
+ # Handle numeric and string literals specially, e.g.
77
+ # "raise Exception, 5" -> "raise Exception(5)".
78
+ val .prefix = u""
79
+ exc = Call (exc , [val ])
80
+ elif val .type == token .NAME and val .value == u"None" :
81
+ # Handle None specially, e.g.
82
+ # "raise Exception, None" -> "raise Exception".
83
+ pass
84
+ else :
85
+ # val is some other expression. If val evaluates to an instance
86
+ # of exc, it should just be raised. If val evaluates to None,
87
+ # a default instance of exc should be raised (as above). If val
88
+ # evaluates to a tuple, exc(*val) should be called (as
89
+ # above). Otherwise, exc(val) should be called. We can only
90
+ # tell what to do at runtime, so defer to future.utils.raise_(),
91
+ # which handles all of these cases.
92
+ touch_import_top (u"future.utils" , u"raise_" , node )
93
+ exc .prefix = u""
94
+ args = [exc , Comma (), val ]
95
+ if tb is not None :
96
+ args += [Comma (), tb ]
97
+ return Call (Name (u"raise_" ), args )
98
+
99
+ if tb is not None :
100
+ tb .prefix = ""
101
+ exc_list = Attr (exc , Name ('with_traceback' )) + [ArgList ([tb ])]
67
102
else :
68
- val .prefix = u""
69
- args = [val ]
103
+ exc_list = [exc ]
70
104
71
105
return pytree .Node (syms .raise_stmt ,
72
- [Name (u"raise" ), Call ( exc , args )] ,
106
+ [Name (u"raise" )] + exc_list ,
73
107
prefix = node .prefix )
0 commit comments