""" Fixer for ' raise E, V '
From Armin Ronacher ' s ``python-modernize``.
raise - > raise
raise E - > raise E
raise E , 5 - > raise E ( 5 )
raise E , 5 , T - > raise E ( 5 ) . with_traceback ( T )
raise E , None , T - > raise E . with_traceback ( T )
raise ( ( ( E , E ' ), E ' ' ), E ' ' ' ) , 5 - > raise E ( 5 )
raise " foo " , V , T - > warns about string exceptions
raise E , ( V1 , V2 ) - > raise E ( V1 , V2 )
raise E , ( V1 , V2 ) , T - > raise E ( V1 , V2 ) . with_traceback ( T )
CAVEATS :
1 ) " raise E, V, T " cannot be translated safely in general . If V
is not a tuple or a ( number , string , None ) literal , then :
raise E , V , T - > from future . utils import raise_
raise_ ( E , V , T )
"""
# Author: Collin Winter, Armin Ronacher, Mark Huang
# Local imports
from lib2to3 import pytree , fixer_base
from lib2to3 . pgen2 import token
from lib2to3 . fixer_util import Name , Call , is_tuple , Comma , Attr , ArgList
from libfuturize . fixer_util import touch_import_top
class FixRaise ( fixer_base . BaseFix ) :
BM_compatible = True
PATTERN = """
raise_stmt < ' raise ' exc = any [ ' , ' val = any [ ' , ' tb = any ] ] >
"""
def transform ( self , node , results ) :
syms = self . syms
exc = results [ " exc " ] . clone ( )
if exc . type == token . STRING :
msg = " Python 3 does not support string exceptions "
self . cannot_convert ( node , msg )
return
# Python 2 supports
# raise ((((E1, E2), E3), E4), E5), V
# as a synonym for
# raise E1, V
# Since Python 3 will not support this, we recurse down any tuple
# literals, always taking the first element.
if is_tuple ( exc ) :
while is_tuple ( exc ) :
# exc.children[1:-1] is the unparenthesized tuple
# exc.children[1].children[0] is the first element of the tuple
exc = exc . children [ 1 ] . children [ 0 ] . clone ( )
exc . prefix = u " "
if " tb " in results :
tb = results [ " tb " ] . clone ( )
else :
tb = None
if " val " in results :
val = results [ " val " ] . clone ( )
if is_tuple ( val ) :
# Assume that exc is a subclass of Exception and call exc(*val).
args = [ c . clone ( ) for c in val . children [ 1 : - 1 ] ]
exc = Call ( exc , args )
elif val . type in ( token . NUMBER , token . STRING ) :
# Handle numeric and string literals specially, e.g.
# "raise Exception, 5" -> "raise Exception(5)".
val . prefix = u " "
exc = Call ( exc , [ val ] )
elif val . type == token . NAME and val . value == u " None " :
# Handle None specially, e.g.
# "raise Exception, None" -> "raise Exception".
pass
else :
# val is some other expression. If val evaluates to an instance
# of exc, it should just be raised. If val evaluates to None,
# a default instance of exc should be raised (as above). If val
# evaluates to a tuple, exc(*val) should be called (as
# above). Otherwise, exc(val) should be called. We can only
# tell what to do at runtime, so defer to future.utils.raise_(),
# which handles all of these cases.
touch_import_top ( u " future.utils " , u " raise_ " , node )
exc . prefix = u " "
args = [ exc , Comma ( ) , val ]
if tb is not None :
args + = [ Comma ( ) , tb ]
return Call ( Name ( u " raise_ " ) , args , prefix = node . prefix )
if tb is not None :
tb . prefix = " "
exc_list = Attr ( exc , Name ( ' with_traceback ' ) ) + [ ArgList ( [ tb ] ) ]
else :
exc_list = [ exc ]
return pytree . Node ( syms . raise_stmt ,
[ Name ( u " raise " ) ] + exc_list ,
prefix = node . prefix )