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) 91