def get_contracts_and_defs_and_globals(code):
_contracts = {}
_events = []
_globals = {}
_defs = []
_getters = []
for item in code:
# Contract references
if isinstance(item, ast.ClassDef):
if _events or _globals or _defs:
raise StructureException("External contract declarations must come before event declarations, global declarations, and function definitions", item)
_contracts[item.name] = add_contract(item.body)
# Statements of the form:
# variable_name: type
elif isinstance(item, ast.AnnAssign):
_contracts, _events, _globals, _getters = add_globals_and_events(_contracts, _defs, _events, _getters, _globals, item)
# Function definitions
elif isinstance(item, ast.FunctionDef):
_defs.append(item)
else:
raise StructureException("Invalid top-level statement", item)
return _contracts, _events, _defs + _getters, _globals
# Header code
python类FunctionDef()的实例源码
def visit_Call(self, node):
_id = get_call_names_as_string(node.func)
self.function_return_stack.append(_id)
logging.debug(_id)
ast_node = None
local_definitions = self.module_definitions_stack[-1]
definition = local_definitions.get_definition(_id)
if definition:
if isinstance(definition.node, ast.ClassDef):
init = local_definitions.get_definition(_id + '.__init__')
self.add_builtin(node)
elif isinstance(definition.node, ast.FunctionDef):
self.undecided = False
return self.add_function(node, definition)
else:
raise Exception('Definition was neither FunctionDef or ClassDef, cannot add the function ')
return self.add_builtin(node)
def createNameMap(a, d=None):
if d == None:
d = { }
if not isinstance(a, ast.AST):
return d
if type(a) == ast.Module: # Need to go through the functions backwards to make this right
for i in range(len(a.body) - 1, -1, -1):
createNameMap(a.body[i], d)
return d
if type(a) in [ast.FunctionDef, ast.ClassDef]:
if hasattr(a, "originalId") and a.name not in d:
d[a.name] = a.originalId
elif type(a) == ast.arg:
if hasattr(a, "originalId") and a.arg not in d:
d[a.arg] = a.originalId
return d
elif type(a) == ast.Name:
if hasattr(a, "originalId") and a.id not in d:
d[a.id] = a.originalId
return d
for child in ast.iter_child_nodes(a):
createNameMap(child, d)
return d
def occursIn(sub, super):
"""Does the first AST occur as a subtree of the second?"""
superStatementTypes = [ ast.Module, ast.Interactive, ast.Suite,
ast.FunctionDef, ast.ClassDef, ast.For,
ast.While, ast.If, ast.With, ast.Try,
ast.ExceptHandler ]
if (not isinstance(super, ast.AST)):
return False
if type(sub) == type(super) and compareASTs(sub, super, checkEquality=True) == 0:
return True
# we know that a statement can never occur in an expression
# (or in a non-statement-holding statement), so cut the search off now to save time.
if isStatement(sub) and type(super) not in superStatementTypes:
return False
for child in ast.iter_child_nodes(super):
if occursIn(sub, child):
return True
return False
def getAllGlobalNames(a):
# Finds all names that can be accessed at the global level in the AST
if type(a) != ast.Module:
return []
names = []
for obj in a.body:
if type(obj) in [ast.FunctionDef, ast.ClassDef]:
names.append(obj.name)
elif type(obj) in [ast.Assign, ast.AugAssign]:
targets = obj.targets if type(obj) == ast.Assign else [obj.target]
for target in obj.targets:
if type(target) == ast.Name:
names.append(target.id)
elif type(target) in [ast.Tuple, ast.List]:
for elt in target.elts:
if type(elt) == ast.Name:
names.append(elt.id)
elif type(obj) in [ast.Import, ast.ImportFrom]:
for module in obj.names:
names.append(module.asname if module.asname != None else module.name)
return names
def isDefault(a):
"""Our programs have a default setting of return 42, so we should detect that"""
if type(a) == ast.Module and len(a.body) == 1:
a = a.body[0]
else:
return False
if type(a) != ast.FunctionDef:
return False
if len(a.body) == 0:
return True
elif len(a.body) == 1:
if type(a.body[0]) == ast.Return:
if a.body[0].value == None or \
type(a.body[0].value) == ast.Num and a.body[0].value.n == 42:
return True
return False
def varse(node):
vv = VarsVisitor()
if isinstance(node.ast_node, ast.FunctionDef) or\
isinstance(node.ast_node, ast.ClassDef):
return list()
elif isinstance(node.ast_node, ast.While)\
or isinstance(node.ast_node, ast.If):
vv.visit(node.ast_node.test)
else:
try:
vv.visit(node.ast_node)
except AttributeError:
return list()
if isinstance(node, AssignmentNode):
result = list()
for var in vv.result:
if var not in node.left_hand_side:
result.append(var)
return result
else:
return vv.result
def visit_Compare(self, node):
"""
:type node: _ast.FunctionDef
"""
is_lambda_def = len(node.ops) == 1\
and type(node.ops[0]) is _ast.Gt \
and (type(node.left) is _ast.Tuple or type(node.left) is _ast.Name) \
and all(map(lambda t: type(t) == _ast.Name, getattr(node.left, 'elts', [])))
if not is_lambda_def:
return node
arguments = _transform_function_arguments(node.left)
function_body = node.comparators[0]
lambda_ast_transform = ast.Lambda(args=arguments,
body=function_body,
lineno=node.lineno,
col_offset=node.col_offset)
return lambda_ast_transform
def match_type(self, typ, node):
if typ == 'class':
return isinstance(node, ast.ClassDef)
if typ == 'def':
return isinstance(node, ast.FunctionDef)
if typ == 'import':
return isinstance(node, (ast.Import, ast.ImportFrom))
if typ == 'assign':
return isinstance(node, ast.Assign)
if typ == 'attr':
return isinstance(node, ast.Attribute)
if typ == 'call':
if isinstance(node, ast.Call):
return True
# Python 2.x compatibility
return hasattr(ast, 'Print') and isinstance(node, ast.Print)
def _get_module_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by the python module.
Module commands consist of a docopt-style module docstring and a callable
Command class.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
cls = next((n for n in module.body
if isinstance(n, ast.ClassDef) and n.name == 'Command'), None)
if not cls:
return
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' not in methods:
return
docstring = ast.get_docstring(module)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None), None)
def _get_class_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python classes in the module.
Class commands are detected by inspecting all callable classes in the
module for docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.ClassDef))
for cls in nodes:
methods = (n.name for n in cls.body if isinstance(n, ast.FunctionDef))
if '__call__' in methods:
docstring = ast.get_docstring(cls)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
cls.name)
def _get_function_commands(module):
# type: (ast.Module) -> typing.Generator[_EntryPoint, None, None]
"""Yield all Command objects represented by python functions in the module.
Function commands consist of all top-level functions that contain
docopt-style docstrings.
Args:
module: An ast.Module object used to retrieve docopt-style commands.
Yields:
Command objects that represent entry points to append to setup.py.
"""
nodes = (n for n in module.body if isinstance(n, ast.FunctionDef))
for func in nodes:
docstring = ast.get_docstring(func)
for commands, _ in usage.parse_commands(docstring):
yield _EntryPoint(commands[0], next(iter(commands[1:]), None),
func.name)
def run(self):
tree = self.tree
if self.filename == 'stdin':
lines = stdin_utils.stdin_get_value()
tree = ast.parse(lines)
for statement in ast.walk(tree):
for child in ast.iter_child_nodes(statement):
child.__flake8_builtins_parent = statement
for statement in ast.walk(tree):
value = None
if isinstance(statement, ast.Assign):
value = self.check_assignment(statement)
elif isinstance(statement, ast.FunctionDef):
value = self.check_function_definition(statement)
if value:
for line, offset, msg, rtype in value:
yield line, offset, msg, rtype
def _fine_property_definition(self, property_name):
"""Find the lines in the source code that contain this property's name and definition.
This function can find both attribute assignments as well as methods/functions.
Args:
property_name (str): the name of the property to look up in the template definition
Returns:
tuple: line numbers for the start and end of the attribute definition
"""
for node in ast.walk(ast.parse(self._source)):
if isinstance(node, ast.Assign) and node.targets[0].id == property_name:
return node.targets[0].lineno - 1, self._get_node_line_end(node)
elif isinstance(node, ast.FunctionDef) and node.name == property_name:
return node.lineno - 1, self._get_node_line_end(node)
raise ValueError('The requested node could not be found.')
def _is_chalice_view(self, node):
# type: (ast.FunctionDef) -> bool
# We can certainly improve on this, but this check is more
# of a heuristic for the time being. The ideal way to do this
# is to infer the Chalice type and ensure the function is
# decorated with the Chalice type's route() method.
decorator_list = node.decorator_list
if not decorator_list:
return False
for decorator in decorator_list:
if isinstance(decorator, ast.Call) and \
isinstance(decorator.func, ast.Attribute):
if decorator.func.attr == 'route' and \
decorator.args:
return True
# For lambda_function and schedule decorator.args
# not present.
if decorator.func.attr in ('lambda_function', 'schedule'):
return True
return False
def get_function_return_type(self, function_name, args_type=[]):
function = self.functions[function_name]
if is_system_function(function_name):
return SystemFunction.get_function(function_name).return_type
if function is not None:
if function.is_args_type_match(args_type):
return function.return_type
else:
raise ParamTypeMismatchError("Function '%s' parameter type is not match", function_name)
else:
for node in self.module_node.body:
if isinstance(node, ast.FunctionDef) and node.name == function_name:
generator, return_type = self.analysis_function(node, args_type)
self.functions.append(Function(function_name, args_type, return_type, generator))
return return_type
return Type.STRING # when function is not exist: string
def visit_FunctionDef(self, node, phase):
'''Visitor for AST FunctionDef nodes
add relevant information about the node to
the context for use in tests which inspect function definitions.
Add the function name to the current namespace for all descendants.
:param node: The node that is being inspected
:return: -
'''
self.context['function'] = node
qualname = self.namespace + '.' + b_utils.get_func_name(node)
name = qualname.split('.')[-1]
self.context['qualname'] = qualname
self.context['name'] = name
# For all child nodes and any tests run, add this function name to
# current namespace
self.namespace = b_utils.namespace_path_join(self.namespace, name)
self.update_scores(self.tester.run_tests(self.context, 'FunctionDef', phase=phase))
def method_could_be_class(node, context, search_classes):
if isinstance(node, ast.Call):
call_node = node
parent = get_top_parent_node(call_node)
klass_found = next(
(klass for klass in iter_method_classes(parent, call_node, context) if klass in search_classes),
None
)
return klass_found is not None
elif isinstance(node, ast.FunctionDef):
klass_node = node.parent
if not isinstance(klass_node, ast.ClassDef):
# not sure what happened here
return False
for base_klass in klass_node.bases:
base_klass = base_klass.id
if base_klass in search_classes:
return True
if name_is_imported(base_klass, context, search_classes):
return True
else:
raise ValueError('node must be either an ast.Call or ast.FunctionDef instance')
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
def parse_bzl(self, bzl_file):
"""Extracts documentation for all public macros from the given .bzl file.
Args:
bzl_file: The .bzl file to extract macro documentation from.
"""
try:
tree = ast.parse(open(bzl_file).read(), bzl_file)
self._add_file_docs(tree)
for stmt in tree.body:
if isinstance(stmt, ast.FunctionDef) and not stmt.name.startswith("_"):
self._add_macro_doc(stmt)
except IOError as e:
# Ignore missing extension
print("Failed to parse {0}: {1}".format(bzl_file, e.strerror))
pass
def get_compound_bodies(node):
"""Returns a list of bodies of a compound statement node.
Args:
node: AST node.
Returns:
A list of bodies of the node. If the given node does not represent
a compound statement, an empty list is returned.
"""
if isinstance(node, (ast.Module, ast.FunctionDef, ast.ClassDef, ast.With)):
return [node.body]
elif isinstance(node, (ast.If, ast.While, ast.For)):
return [node.body, node.orelse]
elif PY2 and isinstance(node, ast.TryFinally):
return [node.body, node.finalbody]
elif PY2 and isinstance(node, ast.TryExcept):
return [node.body, node.orelse] + [h.body for h in node.handlers]
elif PY3 and isinstance(node, ast.Try):
return ([node.body, node.orelse, node.finalbody]
+ [h.body for h in node.handlers])
end
return []
def check_methods_per_class(self, **kwargs):
"""
Inspect the code for too many methods per
class.
"""
try:
methods_per_class = kwargs['methods_per_class']
except KeyError:
return
klass = self.parsed_code.body[0]
if not isinstance(klass, ast.ClassDef):
return
methods = [(node, node.lineno) for node in ast.walk(klass)
if isinstance(node, ast.FunctionDef)]
try:
# Get the last method of the class
# and its line number:
line_number = methods[-1][1]
self.issues[line_number].add(
self.code_errors.too_many_methods_per_class(
len(methods), methods_per_class
)
)
except IndexError:
return
def check_arity(self, **kwargs):
"""
Inspect the code for too many arguments per
function/method.
"""
try:
max_arity = kwargs['max_arity']
except KeyError:
return
node = self.parsed_code.body[0]
if not isinstance(node, ast.FunctionDef):
return
arity = len(node.args.args)
if arity > max_arity:
line_number = node.lineno
self.issues[line_number].add(
self.code_errors.too_many_arguments(arity, max_arity)
)
def check_lines_per_function(self, **kwargs):
"""
Inspect the code for too many lines
per function/method.
"""
try:
max_lines = kwargs['max_lines_per_function']
except KeyError:
return
function_definition = self.parsed_code.body[0]
if not isinstance(function_definition, ast.FunctionDef):
return
code_lines = self.code.splitlines()[1:]
# Filter out the lines, which do
# not consist only of whitespaces:
logic_lines = len(list(filter(lambda line:
line != re.search('\s+', line).group(),
code_lines)))
if logic_lines > max_lines:
line_number = function_definition.lineno
self.issues[line_number].add(
self.code_errors.too_many_lines(
logic_lines, max_lines)
)
def run_call(args, node, process, get_func, **kwargs):
# Get function expression
if isinstance(node, ast.FunctionDef): # function name
func_expr = ast.Name(id=node.name, ctx=ast.Load())
elif isinstance(node, ast.Lambda): # lambda body expr
func_expr = node
else: raise TypeError("Only function definition or lambda may be called")
# args is a call string or argument list/dict
if isinstance(args, str):
parsed = ast.parse(args).body[0].value
parsed.func = func_expr
ast.fix_missing_locations(parsed)
return get_func(process = process, tree = parsed, **kwargs)
else:
# e.g. list -> {args: [...], kwargs: {}}
fmt_args = fix_format(args)
ast.fix_missing_locations(func_expr)
return get_func(process = process, tree=func_expr, call = fmt_args, **kwargs)
def get_all_filters():
"""Return all the available filters"""
return (
# TODO: Add ast.Module to the docstring search.
DocString('d', 'doc', (ast.FunctionDef, ast.ClassDef, ast.Module),
help="Match class and function docstrings."),
NameFilter('c', 'class', (ast.ClassDef, ),
help="Match class names."),
DefFilter('f', 'def', (ast.FunctionDef, ), (ast.AST, ),
help="Match all defs."),
DefFilter('F', 'function', (ast.FunctionDef, ), (ast.Module, ),
help="Match function names at the module level."),
DefFilter('m', 'method', (ast.FunctionDef, ), (ast.ClassDef, ),
help="Match class method names."),
DefFilter('j', 'closure', (ast.FunctionDef, ), (ast.FunctionDef, ),
help="Match closure def names."),
ImportFilter('i', 'import', (ast.Import, ast.ImportFrom, ),
help="Match imported package names."),
CallFilter('C', 'call', (ast.Call, ),
help="Match call statements."),
AttrFilter('a', 'attr', (ast.Attribute, ),
help="Match attributes on objects"),
)
def _generate_nodes(parent, level=0, breadcrumb=''):
nodes = []
for child in parent.body:
if isinstance(child, ast.ClassDef):
style = OutlineNodeItem.Style.cls
elif isinstance(child, ast.FunctionDef):
style = OutlineNodeItem.Style.fn
else:
style = None
if style:
node = OutlineNodeItem(style, child.name, child.lineno, child.col_offset, level, breadcrumb)
nodes.append(node)
if breadcrumb:
bc = '{} • {}'.format(breadcrumb, child.name)
else:
bc = child.name
child_nodes = OutlineDataSource._generate_nodes(child, level + 1, bc)
if child_nodes:
nodes.extend(child_nodes)
return nodes
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
def get_coverable_nodes(cls):
return {
ast.Assert,
ast.Assign,
ast.AugAssign,
ast.Break,
ast.Continue,
ast.Delete,
ast.Expr,
ast.Global,
ast.Import,
ast.ImportFrom,
ast.Nonlocal,
ast.Pass,
ast.Raise,
ast.Return,
ast.FunctionDef,
ast.ClassDef,
ast.TryExcept,
ast.TryFinally,
ast.ExceptHandler,
ast.If,
ast.For,
ast.While,
}
def get_coverable_nodes(cls):
return {
ast.Assert,
ast.Assign,
ast.AugAssign,
ast.Break,
ast.Continue,
ast.Delete,
ast.Expr,
ast.Global,
ast.Import,
ast.ImportFrom,
ast.Nonlocal,
ast.Pass,
ast.Raise,
ast.Return,
ast.ClassDef,
ast.FunctionDef,
ast.Try,
ast.ExceptHandler,
ast.If,
ast.For,
ast.While,
}