44
55raise -> raise
66raise 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)
810
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
1013
14+ raise E, (V1, V2) -> raise E(V1, V2)
15+ raise E, (V1, V2), T -> raise E(V1, V2).with_traceback(T)
1116
12- CAVEATS:
13- 1) "raise E, V" will be incorrectly translated if V is an exception
14- instance. The correct Python 3 idiom is
1517
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:
1721
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)
2124"""
22- # Author: Collin Winter, Armin Ronacher
25+ # Author: Collin Winter, Armin Ronacher, Mark Huang
2326
2427# Local imports
2528from lib2to3 import pytree , fixer_base
2629from 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+
2834
2935class FixRaise (fixer_base .BaseFix ):
3036
3137 BM_compatible = True
3238 PATTERN = """
33- raise_stmt< 'raise' exc=any [',' val=any] >
39+ raise_stmt< 'raise' exc=any [',' val=any [',' tb=any] ] >
3440 """
3541
3642 def transform (self , node , results ):
@@ -55,19 +61,47 @@ def transform(self, node, results):
5561 exc = exc .children [1 ].children [0 ].clone ()
5662 exc .prefix = u" "
5763
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 ])]
67102 else :
68- val .prefix = u""
69- args = [val ]
103+ exc_list = [exc ]
70104
71105 return pytree .Node (syms .raise_stmt ,
72- [Name (u"raise" ), Call ( exc , args )] ,
106+ [Name (u"raise" )] + exc_list ,
73107 prefix = node .prefix )
0 commit comments