mirror of
https://github.com/thegeeklab/ansible-later.git
synced 2024-11-18 02:40:40 +00:00
252 lines
8.4 KiB
Python
252 lines
8.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
import ast
|
|
import inspect
|
|
import sys
|
|
|
|
|
|
try:
|
|
from flake8.engine import pep8 as stdin_utils
|
|
except ImportError:
|
|
from flake8 import utils as stdin_utils
|
|
|
|
|
|
WHITE_LIST = [
|
|
'__name__',
|
|
'__doc__',
|
|
'credits',
|
|
'_',
|
|
]
|
|
|
|
|
|
if sys.version_info >= (3, 0):
|
|
import builtins
|
|
BUILTINS = [
|
|
a[0]
|
|
for a in inspect.getmembers(builtins)
|
|
if a[0] not in WHITE_LIST
|
|
]
|
|
PY3 = True
|
|
else:
|
|
import __builtin__
|
|
BUILTINS = [
|
|
a[0]
|
|
for a in inspect.getmembers(__builtin__)
|
|
if a[0] not in WHITE_LIST
|
|
]
|
|
PY3 = False
|
|
|
|
|
|
class BuiltinsChecker(object):
|
|
name = 'flake8_builtins'
|
|
version = '1.4.1'
|
|
assign_msg = 'A001 "{0}" is a python builtin and is being shadowed, ' \
|
|
'consider renaming the variable'
|
|
argument_msg = 'A002 "{0}" is used as an argument and thus shadows a ' \
|
|
'python builtin, consider renaming the argument'
|
|
class_attribute_msg = 'A003 "{0}" is a python builtin, consider ' \
|
|
'renaming the class attribute'
|
|
|
|
def __init__(self, tree, filename):
|
|
self.tree = tree
|
|
self.filename = filename
|
|
|
|
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
|
|
|
|
function_nodes = [ast.FunctionDef]
|
|
if getattr(ast, 'AsyncFunctionDef', None):
|
|
function_nodes.append(ast.AsyncFunctionDef)
|
|
function_nodes = tuple(function_nodes)
|
|
|
|
for_nodes = [ast.For]
|
|
if getattr(ast, 'AsyncFor', None):
|
|
for_nodes.append(ast.AsyncFor)
|
|
for_nodes = tuple(for_nodes)
|
|
|
|
with_nodes = [ast.With]
|
|
if getattr(ast, 'AsyncWith', None):
|
|
with_nodes.append(ast.AsyncWith)
|
|
with_nodes = tuple(with_nodes)
|
|
|
|
for statement in ast.walk(tree):
|
|
value = None
|
|
if isinstance(statement, ast.Assign):
|
|
value = self.check_assignment(statement)
|
|
|
|
elif isinstance(statement, function_nodes):
|
|
value = self.check_function_definition(statement)
|
|
|
|
elif isinstance(statement, for_nodes):
|
|
value = self.check_for_loop(statement)
|
|
|
|
elif isinstance(statement, with_nodes):
|
|
value = self.check_with(statement)
|
|
|
|
elif isinstance(statement, ast.excepthandler):
|
|
value = self.check_exception(statement)
|
|
|
|
elif isinstance(statement, ast.ListComp):
|
|
value = self.check_list_comprehension(statement)
|
|
|
|
elif isinstance(statement, (ast.Import, ast.ImportFrom)):
|
|
value = self.check_import(statement)
|
|
|
|
elif isinstance(statement, ast.ClassDef):
|
|
value = self.check_class(statement)
|
|
|
|
if value:
|
|
for line, offset, msg, rtype in value:
|
|
yield line, offset, msg, rtype
|
|
|
|
def check_assignment(self, statement):
|
|
msg = self.assign_msg
|
|
if type(statement.__flake8_builtins_parent) is ast.ClassDef:
|
|
msg = self.class_attribute_msg
|
|
|
|
stack = list(statement.targets)
|
|
while stack:
|
|
item = stack.pop()
|
|
if isinstance(item, (ast.Tuple, ast.List)):
|
|
stack.extend(list(item.elts))
|
|
elif isinstance(item, ast.Name) and \
|
|
item.id in BUILTINS:
|
|
yield self.error(item, message=msg, variable=item.id)
|
|
elif PY3 and \
|
|
isinstance(item, ast.Starred) and \
|
|
item.value.id in BUILTINS:
|
|
yield self.error(
|
|
statement,
|
|
message=msg,
|
|
variable=item.value.id,
|
|
)
|
|
|
|
def check_function_definition(self, statement):
|
|
if statement.name in BUILTINS:
|
|
msg = self.assign_msg
|
|
if type(statement.__flake8_builtins_parent) is ast.ClassDef:
|
|
msg = self.class_attribute_msg
|
|
|
|
yield self.error(statement, message=msg, variable=statement.name)
|
|
|
|
if PY3:
|
|
for arg in statement.args.args:
|
|
if isinstance(arg, ast.arg) and \
|
|
arg.arg in BUILTINS:
|
|
yield self.error(
|
|
arg,
|
|
message=self.argument_msg,
|
|
variable=arg.arg,
|
|
)
|
|
else:
|
|
for arg in statement.args.args:
|
|
if isinstance(arg, ast.Name) and \
|
|
arg.id in BUILTINS:
|
|
yield self.error(arg, message=self.argument_msg)
|
|
|
|
def check_for_loop(self, statement):
|
|
stack = [statement.target]
|
|
while stack:
|
|
item = stack.pop()
|
|
if isinstance(item, (ast.Tuple, ast.List)):
|
|
stack.extend(list(item.elts))
|
|
elif isinstance(item, ast.Name) and \
|
|
item.id in BUILTINS:
|
|
yield self.error(statement, variable=item.id)
|
|
elif PY3 and \
|
|
isinstance(item, ast.Starred) and \
|
|
item.value.id in BUILTINS:
|
|
yield self.error(statement, variable=item.value.id)
|
|
|
|
def check_with(self, statement):
|
|
if not PY3:
|
|
var = statement.optional_vars
|
|
if isinstance(var, (ast.Tuple, ast.List)):
|
|
for element in var.elts:
|
|
if isinstance(element, ast.Name) and \
|
|
element.id in BUILTINS:
|
|
yield self.error(statement, variable=element.id)
|
|
|
|
elif isinstance(var, ast.Name) and var.id in BUILTINS:
|
|
yield self.error(statement, variable=var.id)
|
|
else:
|
|
for item in statement.items:
|
|
var = item.optional_vars
|
|
if isinstance(var, (ast.Tuple, ast.List)):
|
|
for element in var.elts:
|
|
if isinstance(element, ast.Name) and \
|
|
element.id in BUILTINS:
|
|
yield self.error(statement, variable=element.id)
|
|
elif isinstance(element, ast.Starred) and \
|
|
element.value.id in BUILTINS:
|
|
yield self.error(
|
|
element,
|
|
variable=element.value.id,
|
|
)
|
|
|
|
elif isinstance(var, ast.Name) and var.id in BUILTINS:
|
|
yield self.error(statement, variable=var.id)
|
|
|
|
def check_exception(self, statement):
|
|
exception_name = statement.name
|
|
value = ''
|
|
if isinstance(exception_name, ast.Name):
|
|
value = exception_name.id
|
|
elif isinstance(exception_name, str): # Python +3.x
|
|
value = exception_name
|
|
|
|
if value in BUILTINS:
|
|
yield self.error(statement, variable=value)
|
|
|
|
def check_list_comprehension(self, statement):
|
|
for generator in statement.generators:
|
|
if isinstance(generator.target, ast.Name) \
|
|
and generator.target.id in BUILTINS:
|
|
yield self.error(statement, variable=generator.target.id)
|
|
|
|
elif isinstance(generator.target, (ast.Tuple, ast.List)):
|
|
for tuple_element in generator.target.elts:
|
|
if isinstance(tuple_element, ast.Name) and \
|
|
tuple_element.id in BUILTINS:
|
|
yield self.error(statement, variable=tuple_element.id)
|
|
|
|
def check_import(self, statement):
|
|
for name in statement.names:
|
|
if name.asname in BUILTINS:
|
|
yield self.error(statement, variable=name.asname)
|
|
|
|
def check_class(self, statement):
|
|
if statement.name in BUILTINS:
|
|
yield self.error(statement, variable=statement.name)
|
|
|
|
def error(
|
|
self,
|
|
statement,
|
|
message=None,
|
|
variable=None,
|
|
line=None,
|
|
column=None,
|
|
):
|
|
if not message:
|
|
message = self.assign_msg
|
|
if not variable:
|
|
variable = statement.id
|
|
if not line:
|
|
line = statement.lineno
|
|
if not column:
|
|
column = statement.col_offset
|
|
|
|
return (
|
|
line,
|
|
column,
|
|
message.format(variable),
|
|
type(self),
|
|
)
|