43 "M191", "M192", "M193", "M194", |
43 "M191", "M192", "M193", "M194", |
44 "M195", "M196", "M197", "M198", |
44 "M195", "M196", "M197", "M198", |
45 |
45 |
46 "M201", |
46 "M201", |
47 |
47 |
48 "M501", "M502", "M503", "M504", "M505", |
48 "M501", "M502", "M503", "M504", "M505", "M506", "M507", |
49 "M511", "M512", "M513", |
49 "M511", "M512", "M513", "M514", |
50 |
50 |
51 "M601", |
51 "M601", |
52 "M611", "M612", "M613", |
52 "M611", "M612", "M613", |
53 "M621", "M622", "M623", "M624", "M625", |
53 "M621", "M622", "M623", "M624", "M625", |
54 "M631", "M632", |
54 "M631", "M632", |
128 (self.__checkDictWithSortedKeys, ("M201",)), |
128 (self.__checkDictWithSortedKeys, ("M201",)), |
129 (self.__checkPep3101, ("M601",)), |
129 (self.__checkPep3101, ("M601",)), |
130 (self.__checkFormatString, ("M611", "M612", "M613", |
130 (self.__checkFormatString, ("M611", "M612", "M613", |
131 "M621", "M622", "M623", "M624", "M625", |
131 "M621", "M622", "M623", "M624", "M625", |
132 "M631", "M632")), |
132 "M631", "M632")), |
133 (self.__checkBugBear, ("M501", "M502", "M503", "M504", "M505", "M511", "M512", "M513",)), |
133 (self.__checkBugBear, ("M501", "M502", "M503", "M504", "M505", |
|
134 "M506", "M507", |
|
135 "M511", "M512", "M513", "M514")), |
134 (self.__checkLogging, ("M651", "M652", "M653", "M654", "M655")), |
136 (self.__checkLogging, ("M651", "M652", "M653", "M654", "M655")), |
135 (self.__checkFuture, ("M701", "M702")), |
137 (self.__checkFuture, ("M701", "M702")), |
136 (self.__checkGettext, ("M711",)), |
138 (self.__checkGettext, ("M711",)), |
137 (self.__checkPrintStatements, ("M801",)), |
139 (self.__checkPrintStatements, ("M801",)), |
138 (self.__checkTuple, ("M811", )), |
140 (self.__checkTuple, ("M811", )), |
523 |
525 |
524 def __checkBuiltins(self): |
526 def __checkBuiltins(self): |
525 """ |
527 """ |
526 Private method to check, if built-ins are shadowed. |
528 Private method to check, if built-ins are shadowed. |
527 """ |
529 """ |
|
530 functionDefs = [ast.FunctionDef] |
|
531 try: |
|
532 functionDefs.append(ast.AsyncFunctionDef) |
|
533 except AttributeError: |
|
534 pass |
|
535 |
528 ignoreBuiltinAssignments = self.__args.get( |
536 ignoreBuiltinAssignments = self.__args.get( |
529 "BuiltinsChecker", self.__defaultArgs["BuiltinsChecker"]) |
537 "BuiltinsChecker", self.__defaultArgs["BuiltinsChecker"]) |
530 |
538 |
531 for node in ast.walk(self.__tree): |
539 for node in ast.walk(self.__tree): |
532 if isinstance(node, ast.Assign): |
540 if isinstance(node, ast.Assign): |
561 if isinstance(element, ast.Name) and \ |
569 if isinstance(element, ast.Name) and \ |
562 element.id in self.__builtins: |
570 element.id in self.__builtins: |
563 self.__error(element.lineno - 1, |
571 self.__error(element.lineno - 1, |
564 element.col_offset, |
572 element.col_offset, |
565 "M131", element.id) |
573 "M131", element.id) |
566 elif isinstance(node, ast.FunctionDef): |
574 elif any(isinstance(node, functionDef) |
567 # function definition |
575 for functionDef in functionDefs): |
|
576 # (asynchronous) function definition |
568 if sys.version_info >= (3, 0): |
577 if sys.version_info >= (3, 0): |
569 for arg in node.args.args: |
578 for arg in node.args.args: |
570 if isinstance(arg, ast.arg) and \ |
579 if isinstance(arg, ast.arg) and \ |
571 arg.arg in self.__builtins: |
580 arg.arg in self.__builtins: |
572 self.__error(arg.lineno - 1, arg.col_offset, |
581 self.__error(arg.lineno - 1, arg.col_offset, |
638 "deque", |
647 "deque", |
639 "dict", |
648 "dict", |
640 "list", |
649 "list", |
641 "set", |
650 "set", |
642 ) |
651 ) |
|
652 functionDefs = [ast.FunctionDef] |
|
653 try: |
|
654 functionDefs.append(ast.AsyncFunctionDef) |
|
655 except AttributeError: |
|
656 pass |
643 |
657 |
644 for node in ast.walk(self.__tree): |
658 for node in ast.walk(self.__tree): |
645 if isinstance(node, ast.FunctionDef): |
659 if any(isinstance(node, functionDef) |
|
660 for functionDef in functionDefs): |
646 for default in node.args.defaults: |
661 for default in node.args.defaults: |
647 if any(isinstance(default, mutableType) |
662 if any(isinstance(default, mutableType) |
648 for mutableType in mutableTypes): |
663 for mutableType in mutableTypes): |
649 typeName = type(default).__name__ |
664 typeName = type(default).__name__ |
650 if isinstance(default, ast.Call): |
665 if isinstance(default, ast.Call): |
714 """ |
729 """ |
715 Private method to bugbear checks. |
730 Private method to bugbear checks. |
716 """ |
731 """ |
717 visitor = BugBearVisitor() |
732 visitor = BugBearVisitor() |
718 visitor.visit(self.__tree) |
733 visitor.visit(self.__tree) |
719 for node, reason in visitor.violations: |
734 for violation in visitor.violations: |
720 self.__error(node.lineno - 1, node.col_offset, reason) |
735 node = violation[0] |
|
736 reason = violation[1] |
|
737 params = violation[2:] |
|
738 self.__error(node.lineno - 1, node.col_offset, reason, *params) |
721 |
739 |
722 |
740 |
723 class TextVisitor(ast.NodeVisitor): |
741 class TextVisitor(ast.NodeVisitor): |
724 """ |
742 """ |
725 Class implementing a node visitor for bytes and str instances. |
743 Class implementing a node visitor for bytes and str instances. |
783 def __visitDefinition(self, node): |
801 def __visitDefinition(self, node): |
784 """ |
802 """ |
785 Private method handling class and function definitions. |
803 Private method handling class and function definitions. |
786 |
804 |
787 @param node reference to the node to handle |
805 @param node reference to the node to handle |
788 @type ast.FunctionDef or ast.ClassDef |
806 @type ast.FunctionDef, ast.AsyncFunctionDef or ast.ClassDef |
789 """ |
807 """ |
790 # Manually traverse class or function definition |
808 # Manually traverse class or function definition |
791 # * Handle decorators normally |
809 # * Handle decorators normally |
792 # * Use special check for body content |
810 # * Use special check for body content |
793 # * Don't handle the rest (e.g. bases) |
811 # * Don't handle the rest (e.g. bases) |
835 """ |
853 """ |
836 Public method to handle a function definition. |
854 Public method to handle a function definition. |
837 |
855 |
838 @param node reference to the node to handle |
856 @param node reference to the node to handle |
839 @type ast.FunctionDef |
857 @type ast.FunctionDef |
|
858 """ |
|
859 # Skipped nodes: ('name', 'args', 'returns') |
|
860 self.__visitDefinition(node) |
|
861 |
|
862 def visit_AsyncFunctionDef(self, node): |
|
863 """ |
|
864 Public method to handle an asynchronous function definition. |
|
865 |
|
866 @param node reference to the node to handle |
|
867 @type ast.AsyncFunctionDef |
840 """ |
868 """ |
841 # Skipped nodes: ('name', 'args', 'returns') |
869 # Skipped nodes: ('name', 'args', 'returns') |
842 self.__visitDefinition(node) |
870 self.__visitDefinition(node) |
843 |
871 |
844 def visit_Call(self, node): |
872 def visit_Call(self, node): |
1139 for elem in reversed(self.__nodeStack[:-1]): |
1167 for elem in reversed(self.__nodeStack[:-1]): |
1140 if isinstance(elem, ast.ExceptHandler) and elem.name == name: |
1168 if isinstance(elem, ast.ExceptHandler) and elem.name == name: |
1141 self.violations.append((node, "M505")) |
1169 self.violations.append((node, "M505")) |
1142 break |
1170 break |
1143 |
1171 |
|
1172 def visit_Assign(self, node): |
|
1173 """ |
|
1174 Public method to handle assignments. |
|
1175 |
|
1176 @param node reference to the node to be processed |
|
1177 @type ast.Assign |
|
1178 """ |
|
1179 if isinstance(self.__nodeStack[-2], ast.ClassDef): |
|
1180 # By using 'hasattr' below we're ignoring starred arguments, slices |
|
1181 # and tuples for simplicity. |
|
1182 assignTargets = {t.id for t in node.targets if hasattr(t, 'id')} |
|
1183 if '__metaclass__' in assignTargets and sys.version_info >= (3, 0): |
|
1184 self.violations.append((node, "M514")) |
|
1185 |
|
1186 elif len(node.targets) == 1: |
|
1187 target = node.targets[0] |
|
1188 if isinstance(target, ast.Attribute) and \ |
|
1189 isinstance(target.value, ast.Name): |
|
1190 if (target.value.id, target.attr) == ('os', 'environ'): |
|
1191 self.violations.append((node, "M506")) |
|
1192 |
|
1193 self.generic_visit(node) |
|
1194 |
|
1195 def visit_For(self, node): |
|
1196 """ |
|
1197 Public method to handle 'for' statements. |
|
1198 |
|
1199 @param node reference to the node to be processed |
|
1200 @type ast.For |
|
1201 """ |
|
1202 self.__checkForM507(node) |
|
1203 |
|
1204 self.generic_visit(node) |
|
1205 |
1144 def __checkForM502(self, node): |
1206 def __checkForM502(self, node): |
1145 """ |
1207 """ |
1146 Private method to check the use of *strip(). |
1208 Private method to check the use of *strip(). |
1147 |
1209 |
1148 @param node reference to the node to be processed |
1210 @param node reference to the node to be processed |
1160 |
1222 |
1161 if len(s) == len(set(s)): |
1223 if len(s) == len(set(s)): |
1162 return # no characters appear more than once |
1224 return # no characters appear more than once |
1163 |
1225 |
1164 self.violations.append((node, "M502")) |
1226 self.violations.append((node, "M502")) |
|
1227 |
|
1228 def __checkForM507(self, node): |
|
1229 """ |
|
1230 Private method to check for unused loop variables. |
|
1231 |
|
1232 @param node reference to the node to be processed |
|
1233 @type ast.For |
|
1234 """ |
|
1235 targets = NameFinder() |
|
1236 targets.visit(node.target) |
|
1237 ctrlNames = set(filter(lambda s: not s.startswith('_'), |
|
1238 targets.getNames())) |
|
1239 body = NameFinder() |
|
1240 for expr in node.body: |
|
1241 body.visit(expr) |
|
1242 usedNames = set(body.getNames()) |
|
1243 for name in sorted(ctrlNames - usedNames): |
|
1244 n = targets.getNames()[name][0] |
|
1245 self.violations.append((n, "M507", name)) |
|
1246 |
|
1247 |
|
1248 class NameFinder(ast.NodeVisitor): |
|
1249 """ |
|
1250 Class to extract a name out of a tree of nodes. |
|
1251 """ |
|
1252 def __init__(self): |
|
1253 """ |
|
1254 Constructor |
|
1255 """ |
|
1256 super(NameFinder, self).__init__() |
|
1257 |
|
1258 self.__names = {} |
|
1259 |
|
1260 def visit_Name(self, node): |
|
1261 """ |
|
1262 Public method to handle 'Name' nodes. |
|
1263 |
|
1264 @param node reference to the node to be processed |
|
1265 @type ast.Name |
|
1266 """ |
|
1267 self.__names.setdefault(node.id, []).append(node) |
|
1268 |
|
1269 def visit(self, node): |
|
1270 """ |
|
1271 Public method to traverse a given AST node. |
|
1272 |
|
1273 @param node AST node to be traversed |
|
1274 @type ast.Node |
|
1275 """ |
|
1276 if isinstance(node, list): |
|
1277 for elem in node: |
|
1278 super(NameFinder, self).visit(elem) |
|
1279 else: |
|
1280 super(NameFinder, self).visit(node) |
|
1281 |
|
1282 def getNames(self): |
|
1283 """ |
|
1284 Public method to return the extracted names and Name nodes. |
|
1285 |
|
1286 @return dictionary containing the names as keys and the list of nodes |
|
1287 @rtype dict |
|
1288 """ |
|
1289 return self.__names |
1165 |
1290 |
1166 # |
1291 # |
1167 # eflag: noqa = M702 |
1292 # eflag: noqa = M702 |