660 coding = "utf-8" |
660 coding = "utf-8" |
661 |
661 |
662 visitor = TextVisitor() |
662 visitor = TextVisitor() |
663 visitor.visit(self.__tree) |
663 visitor.visit(self.__tree) |
664 for node in visitor.nodes: |
664 for node in visitor.nodes: |
665 text = node.s |
665 text = node.value |
666 if isinstance(text, bytes): |
666 if isinstance(text, bytes): |
667 try: |
667 try: |
668 text = text.decode(coding) |
668 text = text.decode(coding) |
669 except UnicodeDecodeError: |
669 except UnicodeDecodeError: |
670 continue |
670 continue |
941 if node.func.id == "reversed": |
941 if node.func.id == "reversed": |
942 reverseFlagValue = False |
942 reverseFlagValue = False |
943 for kw in node.args[0].keywords: |
943 for kw in node.args[0].keywords: |
944 if kw.arg != "reverse": |
944 if kw.arg != "reverse": |
945 continue |
945 continue |
946 if isinstance(kw.value, ast.NameConstant): |
946 reverseFlagValue = ( |
947 reverseFlagValue = kw.value.value |
947 bool(kw.value.value) |
948 elif isinstance(kw.value, ast.Num): |
948 if isinstance(kw.value, ast.Constant) |
949 reverseFlagValue = bool(kw.value.n) |
949 else None |
950 else: |
950 ) |
951 # Complex value |
|
952 reverseFlagValue = None |
|
953 |
951 |
954 if reverseFlagValue is None: |
952 if reverseFlagValue is None: |
955 self.__error( |
953 self.__error( |
956 node.lineno - 1, |
954 node.lineno - 1, |
957 node.col_offset, |
955 node.col_offset, |
1009 and isinstance(node.args[0].slice, ast.Slice) |
1007 and isinstance(node.args[0].slice, ast.Slice) |
1010 and node.args[0].slice.lower is None |
1008 and node.args[0].slice.lower is None |
1011 and node.args[0].slice.upper is None |
1009 and node.args[0].slice.upper is None |
1012 and isinstance(node.args[0].slice.step, ast.UnaryOp) |
1010 and isinstance(node.args[0].slice.step, ast.UnaryOp) |
1013 and isinstance(node.args[0].slice.step.op, ast.USub) |
1011 and isinstance(node.args[0].slice.step.op, ast.USub) |
1014 and isinstance(node.args[0].slice.step.operand, ast.Num) |
1012 and isinstance(node.args[0].slice.step.operand, ast.Constant) |
1015 and node.args[0].slice.step.operand.n == 1 |
1013 and node.args[0].slice.step.operand.n == 1 |
1016 ): |
1014 ): |
1017 self.__error(node.lineno - 1, node.col_offset, "M189", node.func.id) |
1015 self.__error(node.lineno - 1, node.col_offset, "M189", node.func.id) |
1018 |
1016 |
1019 elif isinstance(node, (ast.ListComp, ast.SetComp)) and ( |
1017 elif isinstance(node, (ast.ListComp, ast.SetComp)) and ( |
1133 Private method to check, if dictionary keys appear in sorted order. |
1131 Private method to check, if dictionary keys appear in sorted order. |
1134 """ |
1132 """ |
1135 for node in ast.walk(self.__tree): |
1133 for node in ast.walk(self.__tree): |
1136 if isinstance(node, ast.Dict) and self.__dictShouldBeChecked(node): |
1134 if isinstance(node, ast.Dict) and self.__dictShouldBeChecked(node): |
1137 for key1, key2 in zip(node.keys, node.keys[1:]): |
1135 for key1, key2 in zip(node.keys, node.keys[1:]): |
1138 if key2.s < key1.s: |
1136 if key2.value < key1.value: |
1139 self.__error( |
1137 self.__error( |
1140 key2.lineno - 1, key2.col_offset, "M201", key2.s, key1.s |
1138 key2.lineno - 1, |
|
1139 key2.col_offset, |
|
1140 "M201", |
|
1141 key2.value, |
|
1142 key1.value, |
1141 ) |
1143 ) |
1142 |
1144 |
1143 def __checkLogging(self): |
1145 def __checkLogging(self): |
1144 """ |
1146 """ |
1145 Private method to check logging statements. |
1147 Private method to check logging statements. |
1325 @type ast.AST |
1327 @type ast.AST |
1326 """ |
1328 """ |
1327 if not hasattr(node, "is_docstring"): |
1329 if not hasattr(node, "is_docstring"): |
1328 node.is_docstring = False |
1330 node.is_docstring = False |
1329 self.nodes.append(node) |
1331 self.nodes.append(node) |
1330 |
|
1331 def visit_Str(self, node): |
|
1332 """ |
|
1333 Public method to record a string node. |
|
1334 |
|
1335 @param node reference to the string node |
|
1336 @type ast.Str |
|
1337 """ |
|
1338 self.__addNode(node) |
|
1339 |
|
1340 def visit_Bytes(self, node): |
|
1341 """ |
|
1342 Public method to record a bytes node. |
|
1343 |
|
1344 @param node reference to the bytes node |
|
1345 @type ast.Bytes |
|
1346 """ |
|
1347 self.__addNode(node) |
|
1348 |
1332 |
1349 def visit_Constant(self, node): |
1333 def visit_Constant(self, node): |
1350 """ |
1334 """ |
1351 Public method to handle constant nodes. |
1335 Public method to handle constant nodes. |
1352 |
1336 |
2015 self.violations.append((node, "M582")) |
1999 self.violations.append((node, "M582")) |
2016 |
2000 |
2017 # bad getattr and setattr |
2001 # bad getattr and setattr |
2018 if ( |
2002 if ( |
2019 node.func.id in ("getattr", "hasattr") |
2003 node.func.id in ("getattr", "hasattr") |
2020 and node.args[1].s == "__call__" |
2004 and node.args[1].value == "__call__" |
2021 ): |
2005 ): |
2022 self.violations.append((node, "M504")) |
2006 self.violations.append((node, "M504")) |
2023 if ( |
2007 if ( |
2024 node.func.id == "getattr" |
2008 node.func.id == "getattr" |
2025 and len(node.args) == 2 |
2009 and len(node.args) == 2 |
2634 isinstance(expr, ast.Attribute) and expr.attr == "overload" |
2618 isinstance(expr, ast.Attribute) and expr.attr == "overload" |
2635 ) |
2619 ) |
2636 |
2620 |
2637 def emptyBody(body): |
2621 def emptyBody(body): |
2638 def isStrOrEllipsis(node): |
2622 def isStrOrEllipsis(node): |
2639 # ast.Ellipsis and ast.Str used in python<3.8 |
2623 return ( |
2640 return isinstance(node, (ast.Ellipsis, ast.Str)) or ( |
|
2641 isinstance(node, ast.Constant) |
2624 isinstance(node, ast.Constant) |
2642 and (node.value is Ellipsis or isinstance(node.value, str)) |
2625 and (node.value is Ellipsis or isinstance(node.value, str)) |
2643 ) |
2626 ) |
2644 |
2627 |
2645 # Function body consist solely of `pass`, `...`, and/or (doc)string literals |
2628 # Function body consist solely of `pass`, `...`, and/or (doc)string literals |