1# -*- coding: utf-8 -*- 2import ast 3import inspect 4import sys 5 6 7try: 8 from flake8.engine import pep8 as stdin_utils 9except ImportError: 10 from flake8 import utils as stdin_utils 11 12 13WHITE_LIST = { 14 '__name__', 15 '__doc__', 16 'credits', 17 '_', 18} 19 20 21if sys.version_info >= (3, 0): 22 import builtins 23 BUILTINS = [ 24 a[0] 25 for a in inspect.getmembers(builtins) 26 if a[0] not in WHITE_LIST 27 ] 28 PY3 = True 29else: 30 import __builtin__ 31 BUILTINS = [ 32 a[0] 33 for a in inspect.getmembers(__builtin__) 34 if a[0] not in WHITE_LIST 35 ] 36 PY3 = False 37 38if sys.version_info >= (3, 6): 39 AnnAssign = ast.AnnAssign 40else: # There was no `AnnAssign` before python3.6 41 AnnAssign = type('AnnAssign', (ast.AST, ), {}) 42 43if sys.version_info >= (3, 8): 44 NamedExpr = ast.NamedExpr 45else: # There was no walrus operator before python3.8 46 NamedExpr = type('NamedExpr', (ast.AST, ), {}) 47 48 49class BuiltinsChecker(object): 50 name = 'flake8_builtins' 51 version = '1.5.2' 52 assign_msg = 'A001 variable "{0}" is shadowing a python builtin' 53 argument_msg = 'A002 argument "{0}" is shadowing a python builtin' 54 class_attribute_msg = 'A003 class attribute "{0}" is shadowing a python builtin' 55 56 def __init__(self, tree, filename): 57 self.tree = tree 58 self.filename = filename 59 60 def run(self): 61 tree = self.tree 62 63 if self.filename == 'stdin': 64 lines = stdin_utils.stdin_get_value() 65 tree = ast.parse(lines) 66 67 for statement in ast.walk(tree): 68 for child in ast.iter_child_nodes(statement): 69 child.__flake8_builtins_parent = statement 70 71 function_nodes = [ast.FunctionDef] 72 if getattr(ast, 'AsyncFunctionDef', None): 73 function_nodes.append(ast.AsyncFunctionDef) 74 function_nodes = tuple(function_nodes) 75 76 for_nodes = [ast.For] 77 if getattr(ast, 'AsyncFor', None): 78 for_nodes.append(ast.AsyncFor) 79 for_nodes = tuple(for_nodes) 80 81 with_nodes = [ast.With] 82 if getattr(ast, 'AsyncWith', None): 83 with_nodes.append(ast.AsyncWith) 84 with_nodes = tuple(with_nodes) 85 86 comprehension_nodes = ( 87 ast.ListComp, 88 ast.SetComp, 89 ast.DictComp, 90 ast.GeneratorExp, 91 ) 92 93 value = None 94 for statement in ast.walk(tree): 95 if isinstance(statement, (ast.Assign, AnnAssign, NamedExpr)): 96 value = self.check_assignment(statement) 97 98 elif isinstance(statement, function_nodes): 99 value = self.check_function_definition(statement) 100 101 elif isinstance(statement, for_nodes): 102 value = self.check_for_loop(statement) 103 104 elif isinstance(statement, with_nodes): 105 value = self.check_with(statement) 106 107 elif isinstance(statement, ast.excepthandler): 108 value = self.check_exception(statement) 109 110 elif isinstance(statement, comprehension_nodes): 111 value = self.check_comprehension(statement) 112 113 elif isinstance(statement, (ast.Import, ast.ImportFrom)): 114 value = self.check_import(statement) 115 116 elif isinstance(statement, ast.ClassDef): 117 value = self.check_class(statement) 118 119 if value: 120 for line, offset, msg, rtype in value: 121 yield line, offset, msg, rtype 122 123 def check_assignment(self, statement): 124 msg = self.assign_msg 125 if type(statement.__flake8_builtins_parent) is ast.ClassDef: 126 msg = self.class_attribute_msg 127 128 if isinstance(statement, ast.Assign): 129 stack = list(statement.targets) 130 else: # This is `ast.AnnAssign` or `ast.NamedExpr`: 131 stack = [statement.target] 132 133 while stack: 134 item = stack.pop() 135 if isinstance(item, (ast.Tuple, ast.List)): 136 stack.extend(list(item.elts)) 137 elif isinstance(item, ast.Name) and \ 138 item.id in BUILTINS: 139 yield self.error(item, message=msg, variable=item.id) 140 elif PY3 and isinstance(item, ast.Starred): 141 if hasattr(item.value, 'id') and item.value.id in BUILTINS: 142 yield self.error( 143 statement, 144 message=msg, 145 variable=item.value.id, 146 ) 147 elif hasattr(item.value, 'elts'): 148 stack.extend(list(item.value.elts)) 149 150 def check_function_definition(self, statement): 151 if statement.name in BUILTINS: 152 msg = self.assign_msg 153 if type(statement.__flake8_builtins_parent) is ast.ClassDef: 154 msg = self.class_attribute_msg 155 156 yield self.error(statement, message=msg, variable=statement.name) 157 158 if PY3: 159 all_arguments = [] 160 all_arguments.extend(statement.args.args) 161 all_arguments.extend(getattr(statement.args, 'kwonlyargs', [])) 162 all_arguments.extend(getattr(statement.args, 'posonlyargs', [])) 163 164 for arg in all_arguments: 165 if isinstance(arg, ast.arg) and \ 166 arg.arg in BUILTINS: 167 yield self.error( 168 arg, 169 message=self.argument_msg, 170 variable=arg.arg, 171 ) 172 else: 173 for arg in statement.args.args: 174 if isinstance(arg, ast.Name) and \ 175 arg.id in BUILTINS: 176 yield self.error(arg, message=self.argument_msg) 177 178 def check_for_loop(self, statement): 179 stack = [statement.target] 180 while stack: 181 item = stack.pop() 182 if isinstance(item, (ast.Tuple, ast.List)): 183 stack.extend(list(item.elts)) 184 elif isinstance(item, ast.Name) and \ 185 item.id in BUILTINS: 186 yield self.error(statement, variable=item.id) 187 elif PY3 and isinstance(item, ast.Starred): 188 if hasattr(item.value, 'id') and item.value.id in BUILTINS: 189 yield self.error( 190 statement, 191 variable=item.value.id, 192 ) 193 elif hasattr(item.value, 'elts'): 194 stack.extend(list(item.value.elts)) 195 196 def check_with(self, statement): 197 if not PY3: 198 var = statement.optional_vars 199 if isinstance(var, (ast.Tuple, ast.List)): 200 for element in var.elts: 201 if isinstance(element, ast.Name) and \ 202 element.id in BUILTINS: 203 yield self.error(statement, variable=element.id) 204 205 elif isinstance(var, ast.Name) and var.id in BUILTINS: 206 yield self.error(statement, variable=var.id) 207 else: 208 for item in statement.items: 209 var = item.optional_vars 210 if isinstance(var, (ast.Tuple, ast.List)): 211 for element in var.elts: 212 if isinstance(element, ast.Name) and \ 213 element.id in BUILTINS: 214 yield self.error(statement, variable=element.id) 215 elif isinstance(element, ast.Starred) and \ 216 element.value.id in BUILTINS: 217 yield self.error( 218 element, 219 variable=element.value.id, 220 ) 221 222 elif isinstance(var, ast.Name) and var.id in BUILTINS: 223 yield self.error(statement, variable=var.id) 224 225 def check_exception(self, statement): 226 exception_name = statement.name 227 value = '' 228 if isinstance(exception_name, ast.Name): 229 value = exception_name.id 230 elif isinstance(exception_name, str): # Python +3.x 231 value = exception_name 232 233 if value in BUILTINS: 234 yield self.error(statement, variable=value) 235 236 def check_comprehension(self, statement): 237 for generator in statement.generators: 238 if isinstance(generator.target, ast.Name) \ 239 and generator.target.id in BUILTINS: 240 yield self.error(statement, variable=generator.target.id) 241 242 elif isinstance(generator.target, (ast.Tuple, ast.List)): 243 for tuple_element in generator.target.elts: 244 if isinstance(tuple_element, ast.Name) and \ 245 tuple_element.id in BUILTINS: 246 yield self.error(statement, variable=tuple_element.id) 247 248 def check_import(self, statement): 249 for name in statement.names: 250 if name.asname in BUILTINS: 251 yield self.error(statement, variable=name.asname) 252 253 def check_class(self, statement): 254 if statement.name in BUILTINS: 255 yield self.error(statement, variable=statement.name) 256 257 def error( 258 self, 259 statement, 260 message=None, 261 variable=None, 262 line=None, 263 column=None, 264 ): 265 if not message: 266 message = self.assign_msg 267 if not variable: 268 variable = statement.id 269 if not line: 270 line = statement.lineno 271 if not column: 272 column = statement.col_offset 273 274 return ( 275 line, 276 column, 277 message.format(variable), 278 type(self), 279 ) 280