1 | """Fixer for 'raise E, V, T'
|
---|
2 |
|
---|
3 | raise -> raise
|
---|
4 | raise E -> raise E
|
---|
5 | raise E, V -> raise E(V)
|
---|
6 | raise E, V, T -> raise E(V).with_traceback(T)
|
---|
7 | raise E, None, T -> raise E.with_traceback(T)
|
---|
8 |
|
---|
9 | raise (((E, E'), E''), E'''), V -> raise E(V)
|
---|
10 | raise "foo", V, T -> warns about string exceptions
|
---|
11 |
|
---|
12 |
|
---|
13 | CAVEATS:
|
---|
14 | 1) "raise E, V" will be incorrectly translated if V is an exception
|
---|
15 | instance. The correct Python 3 idiom is
|
---|
16 |
|
---|
17 | raise E from V
|
---|
18 |
|
---|
19 | but since we can't detect instance-hood by syntax alone and since
|
---|
20 | any client code would have to be changed as well, we don't automate
|
---|
21 | this.
|
---|
22 | """
|
---|
23 | # Author: Collin Winter
|
---|
24 |
|
---|
25 | # Local imports
|
---|
26 | from .. import pytree
|
---|
27 | from ..pgen2 import token
|
---|
28 | from .. import fixer_base
|
---|
29 | from ..fixer_util import Name, Call, Attr, ArgList, is_tuple
|
---|
30 |
|
---|
31 | class FixRaise(fixer_base.BaseFix):
|
---|
32 |
|
---|
33 | BM_compatible = True
|
---|
34 | PATTERN = """
|
---|
35 | raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] >
|
---|
36 | """
|
---|
37 |
|
---|
38 | def transform(self, node, results):
|
---|
39 | syms = self.syms
|
---|
40 |
|
---|
41 | exc = results["exc"].clone()
|
---|
42 | if exc.type == token.STRING:
|
---|
43 | msg = "Python 3 does not support string exceptions"
|
---|
44 | self.cannot_convert(node, msg)
|
---|
45 | return
|
---|
46 |
|
---|
47 | # Python 2 supports
|
---|
48 | # raise ((((E1, E2), E3), E4), E5), V
|
---|
49 | # as a synonym for
|
---|
50 | # raise E1, V
|
---|
51 | # Since Python 3 will not support this, we recurse down any tuple
|
---|
52 | # literals, always taking the first element.
|
---|
53 | if is_tuple(exc):
|
---|
54 | while is_tuple(exc):
|
---|
55 | # exc.children[1:-1] is the unparenthesized tuple
|
---|
56 | # exc.children[1].children[0] is the first element of the tuple
|
---|
57 | exc = exc.children[1].children[0].clone()
|
---|
58 | exc.prefix = u" "
|
---|
59 |
|
---|
60 | if "val" not in results:
|
---|
61 | # One-argument raise
|
---|
62 | new = pytree.Node(syms.raise_stmt, [Name(u"raise"), exc])
|
---|
63 | new.prefix = node.prefix
|
---|
64 | return new
|
---|
65 |
|
---|
66 | val = results["val"].clone()
|
---|
67 | if is_tuple(val):
|
---|
68 | args = [c.clone() for c in val.children[1:-1]]
|
---|
69 | else:
|
---|
70 | val.prefix = u""
|
---|
71 | args = [val]
|
---|
72 |
|
---|
73 | if "tb" in results:
|
---|
74 | tb = results["tb"].clone()
|
---|
75 | tb.prefix = u""
|
---|
76 |
|
---|
77 | e = exc
|
---|
78 | # If there's a traceback and None is passed as the value, then don't
|
---|
79 | # add a call, since the user probably just wants to add a
|
---|
80 | # traceback. See issue #9661.
|
---|
81 | if val.type != token.NAME or val.value != u"None":
|
---|
82 | e = Call(exc, args)
|
---|
83 | with_tb = Attr(e, Name(u'with_traceback')) + [ArgList([tb])]
|
---|
84 | new = pytree.Node(syms.simple_stmt, [Name(u"raise")] + with_tb)
|
---|
85 | new.prefix = node.prefix
|
---|
86 | return new
|
---|
87 | else:
|
---|
88 | return pytree.Node(syms.raise_stmt,
|
---|
89 | [Name(u"raise"), Call(exc, args)],
|
---|
90 | prefix=node.prefix)
|
---|