44 "M191", "M192", "M193", "M194", |
44 "M191", "M192", "M193", "M194", |
45 "M195", "M196", "M197", "M198", |
45 "M195", "M196", "M197", "M198", |
46 |
46 |
47 "M201", |
47 "M201", |
48 |
48 |
49 "M501", "M502", "M503", "M504", "M505", "M506", "M507", |
49 "M501", "M502", "M503", "M504", "M505", "M506", "M507", "M508", |
50 "M511", "M512", "M513", "M514", |
50 "M509", |
|
51 "M511", "M512", "M513", |
|
52 "M521", "M522", "M523", "M524", |
51 |
53 |
52 "M601", |
54 "M601", |
53 "M611", "M612", "M613", |
55 "M611", "M612", "M613", |
54 "M621", "M622", "M623", "M624", "M625", |
56 "M621", "M622", "M623", "M624", "M625", |
55 "M631", "M632", |
57 "M631", "M632", |
131 (self.__checkPep3101, ("M601",)), |
133 (self.__checkPep3101, ("M601",)), |
132 (self.__checkFormatString, ("M611", "M612", "M613", |
134 (self.__checkFormatString, ("M611", "M612", "M613", |
133 "M621", "M622", "M623", "M624", "M625", |
135 "M621", "M622", "M623", "M624", "M625", |
134 "M631", "M632")), |
136 "M631", "M632")), |
135 (self.__checkBugBear, ("M501", "M502", "M503", "M504", "M505", |
137 (self.__checkBugBear, ("M501", "M502", "M503", "M504", "M505", |
136 "M506", "M507", |
138 "M506", "M507", "M508", "M509", |
137 "M511", "M512", "M513", "M514")), |
139 "M511", "M512", "M513", |
|
140 "M521", "M522", "M523", "M524")), |
138 (self.__checkLogging, ("M651", "M652", "M653", "M654", "M655")), |
141 (self.__checkLogging, ("M651", "M652", "M653", "M654", "M655")), |
139 (self.__checkFuture, ("M701", "M702")), |
142 (self.__checkFuture, ("M701", "M702")), |
140 (self.__checkGettext, ("M711",)), |
143 (self.__checkGettext, ("M711",)), |
141 (self.__checkPrintStatements, ("M801",)), |
144 (self.__checkPrintStatements, ("M801",)), |
142 (self.__checkTuple, ("M811", )), |
145 (self.__checkTuple, ("M811", )), |
651 "deque", |
654 "deque", |
652 "dict", |
655 "dict", |
653 "list", |
656 "list", |
654 "set", |
657 "set", |
655 ) |
658 ) |
|
659 immutableCalls = ( |
|
660 "tuple", |
|
661 "frozenset", |
|
662 ) |
656 functionDefs = [ast.FunctionDef] |
663 functionDefs = [ast.FunctionDef] |
657 try: |
664 try: |
658 functionDefs.append(ast.AsyncFunctionDef) |
665 functionDefs.append(ast.AsyncFunctionDef) |
659 except AttributeError: |
666 except AttributeError: |
660 pass |
667 pass |
661 |
668 |
662 for node in ast.walk(self.__tree): |
669 for node in ast.walk(self.__tree): |
663 if any(isinstance(node, functionDef) |
670 if any(isinstance(node, functionDef) |
664 for functionDef in functionDefs): |
671 for functionDef in functionDefs): |
665 for default in node.args.defaults: |
672 for default in node.args.defaults + node.args.kw_defaults: |
666 if any(isinstance(default, mutableType) |
673 if any(isinstance(default, mutableType) |
667 for mutableType in mutableTypes): |
674 for mutableType in mutableTypes): |
668 typeName = type(default).__name__ |
675 typeName = type(default).__name__ |
669 if isinstance(default, ast.Call): |
676 if isinstance(default, ast.Call): |
670 callPath = '.'.join(composeCallPath(default.func)) |
677 callPath = '.'.join(composeCallPath(default.func)) |
671 if callPath in mutableCalls: |
678 if callPath in mutableCalls: |
672 self.__error(default.lineno - 1, |
679 self.__error(default.lineno - 1, |
673 default.col_offset, |
680 default.col_offset, |
674 "M823", callPath + "()") |
681 "M823", callPath + "()") |
675 else: |
682 elif callPath not in immutableCalls: |
676 self.__error(default.lineno - 1, |
683 self.__error(default.lineno - 1, |
677 default.col_offset, |
684 default.col_offset, |
678 "M822", typeName) |
685 "M822", typeName) |
679 else: |
686 else: |
680 self.__error(default.lineno - 1, |
687 self.__error(default.lineno - 1, |
729 self.__error(node.lineno - 1, node.col_offset, "M711", |
736 self.__error(node.lineno - 1, node.col_offset, "M711", |
730 node.names[0].name) |
737 node.names[0].name) |
731 |
738 |
732 def __checkBugBear(self): |
739 def __checkBugBear(self): |
733 """ |
740 """ |
734 Private method to bugbear checks. |
741 Private method for bugbear checks. |
735 """ |
742 """ |
736 visitor = BugBearVisitor() |
743 visitor = BugBearVisitor() |
737 visitor.visit(self.__tree) |
744 visitor.visit(self.__tree) |
738 for violation in visitor.violations: |
745 for violation in visitor.violations: |
739 node = violation[0] |
746 node = violation[0] |
1133 @type ast.Call |
1140 @type ast.Call |
1134 """ |
1141 """ |
1135 if sys.version_info >= (3, 0): |
1142 if sys.version_info >= (3, 0): |
1136 validPaths = ("six", "future.utils", "builtins") |
1143 validPaths = ("six", "future.utils", "builtins") |
1137 methodsDict = { |
1144 methodsDict = { |
1138 "M511": ("iterkeys", "itervalues", "iteritems", "iterlists"), |
1145 "M521": ("iterkeys", "itervalues", "iteritems", "iterlists"), |
1139 "M512": ("viewkeys", "viewvalues", "viewitems", "viewlists"), |
1146 "M522": ("viewkeys", "viewvalues", "viewitems", "viewlists"), |
1140 "M513": ("next",), |
1147 "M523": ("next",), |
1141 } |
1148 } |
1142 else: |
1149 else: |
1143 validPaths = () |
1150 validPaths = () |
1144 methodsDict = {} |
1151 methodsDict = {} |
1145 |
1152 |
1152 break |
1159 break |
1153 else: |
1160 else: |
1154 self.__checkForM502(node) |
1161 self.__checkForM502(node) |
1155 else: |
1162 else: |
1156 try: |
1163 try: |
|
1164 # bad super() call |
|
1165 if isinstance(node.func, ast.Name) and node.func.id == "super": |
|
1166 args = node.args |
|
1167 if ( |
|
1168 len(args) == 2 and |
|
1169 isinstance(args[0], ast.Attribute) and |
|
1170 isinstance(args[0].value, ast.Name) and |
|
1171 args[0].value.id == 'self' and |
|
1172 args[0].attr == '__class__' |
|
1173 ): |
|
1174 self.violations.append((node, "M509")) |
|
1175 |
|
1176 # bad getattr and setattr |
1157 if ( |
1177 if ( |
1158 node.func.id in ("getattr", "hasattr") and |
1178 node.func.id in ("getattr", "hasattr") and |
1159 node.args[1].s == "__call__" |
1179 node.args[1].s == "__call__" |
1160 ): |
1180 ): |
1161 self.violations.append((node, "M503")) |
1181 self.violations.append((node, "M511")) |
|
1182 if ( |
|
1183 node.func.id == "getattr" and |
|
1184 len(node.args) == 2 and |
|
1185 isinstance(node.args[1], ast.Str) |
|
1186 ): |
|
1187 self.violations.append((node, "M512")) |
|
1188 elif ( |
|
1189 node.func.id == "setattr" and |
|
1190 len(node.args) == 3 and |
|
1191 isinstance(node.args[1], ast.Str) |
|
1192 ): |
|
1193 self.violations.append((node, "M513")) |
1162 except (AttributeError, IndexError): |
1194 except (AttributeError, IndexError): |
1163 pass |
1195 pass |
1164 |
1196 |
1165 self.generic_visit(node) |
1197 self.generic_visit(node) |
1166 |
1198 |
1194 if isinstance(self.__nodeStack[-2], ast.ClassDef): |
1226 if isinstance(self.__nodeStack[-2], ast.ClassDef): |
1195 # By using 'hasattr' below we're ignoring starred arguments, slices |
1227 # By using 'hasattr' below we're ignoring starred arguments, slices |
1196 # and tuples for simplicity. |
1228 # and tuples for simplicity. |
1197 assignTargets = {t.id for t in node.targets if hasattr(t, 'id')} |
1229 assignTargets = {t.id for t in node.targets if hasattr(t, 'id')} |
1198 if '__metaclass__' in assignTargets and sys.version_info >= (3, 0): |
1230 if '__metaclass__' in assignTargets and sys.version_info >= (3, 0): |
1199 self.violations.append((node, "M514")) |
1231 self.violations.append((node, "M524")) |
1200 |
1232 |
1201 elif len(node.targets) == 1: |
1233 elif len(node.targets) == 1: |
1202 target = node.targets[0] |
1234 target = node.targets[0] |
1203 if isinstance(target, ast.Attribute) and \ |
1235 if isinstance(target, ast.Attribute) and \ |
1204 isinstance(target.value, ast.Name): |
1236 isinstance(target.value, ast.Name): |
1215 @type ast.For |
1247 @type ast.For |
1216 """ |
1248 """ |
1217 self.__checkForM507(node) |
1249 self.__checkForM507(node) |
1218 |
1250 |
1219 self.generic_visit(node) |
1251 self.generic_visit(node) |
|
1252 |
|
1253 def visit_Assert(self, node): |
|
1254 """ |
|
1255 Public method to handle 'assert' statements. |
|
1256 |
|
1257 @param node reference to the node to be processed |
|
1258 @type ast.Assert |
|
1259 """ |
|
1260 if isinstance(node.test, ast.NameConstant) and \ |
|
1261 node.test.value is False: |
|
1262 self.violations.append((node, "M503")) |
|
1263 |
|
1264 self.generic_visit(node) |
|
1265 |
|
1266 def visit_JoinedStr(self, node): |
|
1267 """ |
|
1268 Public method to handle f-string arguments. |
|
1269 |
|
1270 @param node reference to the node to be processed |
|
1271 @type ast.JoinedStr |
|
1272 """ |
|
1273 if sys.version_info >= (3, 6): |
|
1274 for value in node.values: |
|
1275 if isinstance(value, ast.FormattedValue): |
|
1276 return |
|
1277 |
|
1278 self.violations.append((node, "M508")) |
1220 |
1279 |
1221 def __checkForM502(self, node): |
1280 def __checkForM502(self, node): |
1222 """ |
1281 """ |
1223 Private method to check the use of *strip(). |
1282 Private method to check the use of *strip(). |
1224 |
1283 |