def do_ExceptHandler(self, node):
result = []
result.append(self.indent('except'))
if getattr(node, 'type', None):
result.append(' %s' % self.visit(node.type))
if getattr(node, 'name', None):
if isinstance(node.name, ast.AST):
result.append(' as %s' % self.visit(node.name))
else:
result.append(' as %s' % node.name) # Python 3.x.
result.append(':\n')
for z in node.body:
self.level += 1
result.append(self.visit(z))
self.level -= 1
return ''.join(result)
# Python 2.x only
python类AST的实例源码
def eval_numeric_constexpr(node: ast.AST) -> int:
if isinstance(node, ast.Num):
return node.n
if isinstance(node, ast.UnaryOp):
if isinstance(node.op, ast.UAdd):
return +eval_numeric_constexpr(node.operand)
elif isinstance(node.op, ast.USub):
return -eval_numeric_constexpr(node.operand)
else:
return None
if isinstance(node, ast.BinOp):
if isinstance(node.op, ast.Add):
return eval_numeric_constexpr(node.left) + eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Sub):
return eval_numeric_constexpr(node.left) - eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Mult):
return eval_numeric_constexpr(node.left) * eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Div):
return eval_numeric_constexpr(node.left) / eval_numeric_constexpr(node.right)
return None
def parse_decorator(node: ast.AST):
if isinstance(node, ast.Name):
ret = Decorator()
ret.name = node.id
return ret
elif isinstance(node, ast.Call):
ret = Decorator()
ret.name = node.func.id
for arg in node.args:
if isinstance(arg, ast.Num):
ret.args.append(str(arg.n))
elif isinstance(arg, ast.Str):
ret.args.append(str(arg.n))
elif isinstance(arg, ast.Name):
ret.args.append(arg.id)
else:
v = eval_numeric_constexpr(arg)
if v:
ret.args.append(str(v))
else:
error(loc(node), "Unsupported decorator type")
return ret
else:
error(loc(node), "Supported decorators are Name and Call")
return None
def cmpop_str(op: ast.AST) -> str:
if isinstance(op, ast.Eq):
return '=='
if isinstance(op, ast.NotEq):
return '!='
if isinstance(op, ast.Lt):
return '<'
if isinstance(op, ast.LtE):
return '<='
if isinstance(op, ast.Gt):
return '>'
if isinstance(op, ast.GtE):
return '>='
error(loc(op), "Invalid compare operator encountered: {0}:{1}. Check supported intrisics.".format(op.lineno, op.col_offset))
return 'INVALID_CMPOP'
# Parsers
# ------------------------------------------------------------------------------
def vars_defined_in_all_cases(self, node):
if isinstance(node, ast.If):
vars_defined = None
for if_node in u.ifs_in_elif_block(node):
cur_vars_defined = self.vars_defined_in_all_cases(if_node.body)
if vars_defined is None:
vars_defined = cur_vars_defined
else:
vars_defined = vars_defined & cur_vars_defined
elif isinstance(node, list):
vars_defined = set()
for stmt_node in node:
vars_defined = vars_defined | self.vars_defined_in_all_cases(stmt_node)
elif isinstance(node, ast.AST):
vars_defined = set()
if u.is_set_to(node):
vars_defined.add(node.value.func.value.id)
return vars_defined
def test_AST_objects(self):
if not test_support.check_impl_detail():
# PyPy also provides a __dict__ to the ast.AST base class.
return
x = ast.AST()
self.assertEqual(x._fields, ())
with self.assertRaises(AttributeError):
x.vararg
with self.assertRaises(AttributeError):
x.foobar = 21
with self.assertRaises(AttributeError):
ast.AST(lineno=2)
with self.assertRaises(TypeError):
# "_ast.AST constructor takes 0 positional arguments"
ast.AST(2)
def test_AST_objects(self):
x = ast.AST()
self.assertEqual(x._fields, ())
with self.assertRaises(AttributeError):
x.vararg
with self.assertRaises(AttributeError):
x.foobar = 21
with self.assertRaises(AttributeError):
ast.AST(lineno=2)
with self.assertRaises(TypeError):
# "_ast.AST constructor takes 0 positional arguments"
ast.AST(2)
def __call__(self, t):
if isinstance(t, list):
for child in t:
self.visit(child)
elif isinstance(t, ast.AST):
self.visit(t)
else:
assert False, "Unexpected type: %r" % (t,)
def visit_Num(self, t):
# -0.0 is distinct from +0.0, but my compiler would mistakenly
# coalesce the two, if both appear among the constants. Likewise
# for -0.0 as a component of a complex number. As a hack, instead
# of handling this case correctly in the compiler, we just forbid
# it. It's especially unlikely to crop up because the parser even
# parses -0.0 as UnaryOp(op=USub(), operand=Num(0.0)) -- you'd
# have to build the AST some other way, to get Num(-0.0).
assert not has_negzero(t.n), "Negative-zero literals not supported: %r" % (t,)
def to_ast(value, file: str = None) -> ast.AST:
"""
Returns node object for any value.
"""
raise TypeError('Unexpected type for value: {}'.format(str(type(value))))
def node_to_ast(node: ast.AST, file: str = None) -> ast.AST:
"""
"""
if node and not isinstance(node, ast.AST):
raise TypeError('Unexpected type: {}'.format(str(type(node))))
return node
def ast_to_module(node: ast.AST, old_module: types.ModuleType = None, file: str = None) -> types.ModuleType:
"""
Compile node object to module.
"""
if node and not isinstance(node, ast.AST):
raise TypeError('Unexpected type for node: {}'.format(str(type(node))))
if old_module and not isinstance(old_module, types.ModuleType):
raise TypeError('Unexpected type for old_module: {}'.format(str(type(old_module))))
if not isinstance(node, ast.Module):
node = ast.copy_location(ast.Module(body = [node]), node)
file = file or (inspect.getfile(old_module) if old_module else None)
code = _call_with_frames_removed\
( compile
, source = node
, filename = file or '<file>'
, mode = 'exec'
, dont_inherit = True
)
module = old_module or types.ModuleType()
exec(code, module.__dict__)
return module
def ast_to_func(node: ast.AST, old_func: types.FunctionType, file: str = None) -> types.FunctionType:
"""
Compile node object to function.
"""
if node and not isinstance(node, (ast.Module, ast.FunctionDef)):
raise TypeError('Unexpected type for node: {}'.format(str(type(node))))
if old_func and not isinstance(old_func, types.FunctionType):
raise TypeError('Unexpected type for old_func: {}'.format(str(type(old_func))))
result = old_func
if node and old_func:
old_code = getattr(old_func, '__code__', None)
if not isinstance(node, ast.Module):
mod_node = ast.copy_location(ast.Module(body = [node]), node)
fun_node = node
else:
mod_node = node
fun_node = node.body[0]
module = ast_to_code(mod_node, old_code, file=file)
for code in module.co_consts:
if not isinstance(code, types.CodeType):
continue
if code.co_name == fun_node.name and code.co_firstlineno == fun_node.lineno:
result.__code__ = code
break
else:
raise ValueError('Not specified value')
return result
def ast_to_method(node: ast.AST, old_method: types.MethodType, file: str = None) -> types.MethodType:
"""
:param node:
:param old_method:
:param file:
:return:
"""
raise NotImplementedError
return NotImplemented
def ast_to_node(node: ast.AST, old_node: ast.AST = None, file: str = None) -> ast.AST:
"""
"""
if node and not isinstance(node, ast.AST):
raise TypeError('Unexpected type for node: {}'.format(str(type(node))))
if old_node and not isinstance(old_node, ast.AST):
raise TypeError('Unexpected type for old_node: {}'.format(str(type(old_node))))
return node or old_node
def from_ast(node: ast.AST, old_object, file: str = None):
"""
:param node:
:param old_object:
:return:
"""
if isinstance(old_object, types.CodeType):
compiler = ast_to_code
elif isinstance(old_object, types.ModuleType):
compiler = ast_to_module
elif isinstance(old_object, types.FunctionType):
compiler = ast_to_func
elif isinstance(old_object, types.MethodType):
compiler = ast_to_method
elif isinstance(old_object, str):
compiler = ast_to_source
elif isinstance(old_object, type):
compiler = ast_to_class
elif isinstance(old_object, ast.AST):
compiler = ast_to_node
elif old_object:
raise TypeError('Unexpected type for node: {}'.format(str(type(node))))
else:
raise ValueError('Not specified value')
result = compiler(node, old_object, file=file)
return result
def childHasTag(a, tag):
""" Includes the AST itself"""
if hasattr(a, tag):
return True
if type(a) == list:
for child in a:
if childHasTag(child, tag):
return True
return False
elif not isinstance(a, ast.AST):
return False
for node in ast.walk(a):
if hasattr(node, tag):
return True
return False
def noneSpecialFunction(cv):
"""If the old type is 'None' (which won't show up in the original), move up in the AST to get the metadata"""
if (not isinstance(cv, AddVector)) and cv.oldSubtree == None:
cvCopy = cv.deepcopy()
if cv.path[0] == ('value', 'Return'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.Return(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] == ('value', 'Name Constant'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.NameConstant(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] in [('lower', 'Slice'), ('upper', 'Slice'), ('step', 'Slice')]:
tmpNew = cv.newSubtree
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = deepcopy(cv.oldSubtree) # use the same slice
if cv.path[0][0] == 'lower':
cv.newSubtree.lower = tmpNew
elif cv.path[0][0] == 'upper':
cv.newSubtree.upper = tmpNew
else:
cv.newSubtree.step = tmpNew
cv.path = cv.path[1:] # get rid of None and the val
else:
log("Individualize\tmapEdit\tMissing option in None special case 1: " + str(cv.path[0]), "bug")
elif cv.oldSubtree == "None":
cv.path = cv.path[1:] # get rid of None and the id
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('value', 'Return'):
cv.newSubtree = ast.Return(ast.Name(cv.newSubtree, ast.Load()))
else:
log("Individualize\tmapEdit\tMissing option in None special case 2: " + str(cv.path[0]), "bug")
cv.path = cv.path[1:]
return cv
def hasMultiComp(a):
if not isinstance(a, ast.AST):
return False
for node in ast.walk(a):
if hasattr(node, "multiComp") and node.multiComp:
return True
return False
def getLineNumberFromAst(a):
if not isinstance(a, ast.AST):
return None
if hasattr(a, "lineno"):
return a.lineno
line = None
for child in ast.iter_child_nodes(a):
line = getLineNumberFromAst(child)
if line != None:
return line
return line