15e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis"""Fixer for 'raise E, V, T'
25e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
35e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise         -> raise
45e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise E       -> raise E
55e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise E, V    -> raise E(V)
65e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise E, V, T -> raise E(V).with_traceback(T)
7a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Petersonraise E, None, T -> raise E.with_traceback(T)
85e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
95e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise (((E, E'), E''), E'''), V -> raise E(V)
105e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisraise "foo", V, T               -> warns about string exceptions
115e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
125e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
135e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. LöwisCAVEATS:
145e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis1) "raise E, V" will be incorrectly translated if V is an exception
155e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis   instance. The correct Python 3 idiom is
16ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis
175e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        raise E from V
18ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis
195e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis   but since we can't detect instance-hood by syntax alone and since
205e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis   any client code would have to be changed as well, we don't automate
215e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis   this.
225e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis"""
235e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis# Author: Collin Winter
245e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
255e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis# Local imports
265e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisfrom .. import pytree
275e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwisfrom ..pgen2 import token
28e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonfrom .. import fixer_base
29e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonfrom ..fixer_util import Name, Call, Attr, ArgList, is_tuple
305e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
31e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonclass FixRaise(fixer_base.BaseFix):
325e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
33a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson    BM_compatible = True
345e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    PATTERN = """
355e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] >
365e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    """
375e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
385e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    def transform(self, node, results):
395e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        syms = self.syms
405e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
415e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        exc = results["exc"].clone()
42a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson        if exc.type == token.STRING:
43a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            msg = "Python 3 does not support string exceptions"
44a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            self.cannot_convert(node, msg)
455e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            return
465e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
475e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        # Python 2 supports
485e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        #  raise ((((E1, E2), E3), E4), E5), V
495e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        # as a synonym for
505e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        #  raise E1, V
515e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        # Since Python 3 will not support this, we recurse down any tuple
525e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        # literals, always taking the first element.
535e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        if is_tuple(exc):
54ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis            while is_tuple(exc):
55ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis                # exc.children[1:-1] is the unparenthesized tuple
56ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis                # exc.children[1].children[0] is the first element of the tuple
57ab41b370a3eb1444b8ada38311a1bb498575a81cMartin v. Löwis                exc = exc.children[1].children[0].clone()
58a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            exc.prefix = u" "
595e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
605e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        if "val" not in results:
615e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            # One-argument raise
6284ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson            new = pytree.Node(syms.raise_stmt, [Name(u"raise"), exc])
636118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson            new.prefix = node.prefix
645e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            return new
655e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
665e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        val = results["val"].clone()
675e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        if is_tuple(val):
685e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            args = [c.clone() for c in val.children[1:-1]]
695e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        else:
706118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson            val.prefix = u""
715e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            args = [val]
725e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
735e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        if "tb" in results:
745e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            tb = results["tb"].clone()
756118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson            tb.prefix = u""
765e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
77a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            e = exc
78a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            # If there's a traceback and None is passed as the value, then don't
79a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            # add a call, since the user probably just wants to add a
80a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            # traceback. See issue #9661.
81a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson            if val.type != token.NAME or val.value != u"None":
82a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson                e = Call(exc, args)
8384ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson            with_tb = Attr(e, Name(u'with_traceback')) + [ArgList([tb])]
8484ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson            new = pytree.Node(syms.simple_stmt, [Name(u"raise")] + with_tb)
856118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson            new.prefix = node.prefix
865e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            return new
875e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        else:
885e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis            return pytree.Node(syms.raise_stmt,
8984ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson                               [Name(u"raise"), Call(exc, args)],
906118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson                               prefix=node.prefix)
91