37 |
37 |
38 import AstUtilities |
38 import AstUtilities |
39 |
39 |
40 from .eradicate import Eradicator |
40 from .eradicate import Eradicator |
41 from .MiscellaneousDefaults import MiscellaneousCheckerDefaultArgs |
41 from .MiscellaneousDefaults import MiscellaneousCheckerDefaultArgs |
42 |
|
43 |
42 |
44 BugbearMutableLiterals = ("Dict", "List", "Set") |
43 BugbearMutableLiterals = ("Dict", "List", "Set") |
45 BugbearMutableComprehensions = ("ListComp", "DictComp", "SetComp") |
44 BugbearMutableComprehensions = ("ListComp", "DictComp", "SetComp") |
46 BugbearMutableCalls = ( |
45 BugbearMutableCalls = ( |
47 "Counter", |
46 "Counter", |
1645 ## Original: Copyright (c) 2016 Łukasz Langa |
1644 ## Original: Copyright (c) 2016 Łukasz Langa |
1646 ####################################################################### |
1645 ####################################################################### |
1647 |
1646 |
1648 BugBearContext = namedtuple("BugBearContext", ["node", "stack"]) |
1647 BugBearContext = namedtuple("BugBearContext", ["node", "stack"]) |
1649 |
1648 |
|
1649 |
1650 @dataclass |
1650 @dataclass |
1651 class M540CaughtException: |
1651 class M540CaughtException: |
1652 """ |
1652 """ |
1653 Class to hold the data for a caught exception. |
1653 Class to hold the data for a caught exception. |
1654 """ |
1654 """ |
1655 name : str |
1655 |
|
1656 name: str |
1656 hasNote: bool |
1657 hasNote: bool |
1657 |
1658 |
1658 |
1659 |
1659 class BugBearVisitor(ast.NodeVisitor): |
1660 class BugBearVisitor(ast.NodeVisitor): |
1660 """ |
1661 """ |
2042 else: |
2043 else: |
2043 self.__M540CaughtException = M540CaughtException(node.name, False) |
2044 self.__M540CaughtException = M540CaughtException(node.name, False) |
2044 |
2045 |
2045 names = self.__checkForM513_M529_M530(node) |
2046 names = self.__checkForM513_M529_M530(node) |
2046 |
2047 |
2047 if ( |
2048 if "BaseException" in names and not ExceptBaseExceptionVisitor(node).reRaised(): |
2048 "BaseException" in names |
|
2049 and not ExceptBaseExceptionVisitor(node).reRaised() |
|
2050 ): |
|
2051 self.violations.append((node, "M536")) |
2049 self.violations.append((node, "M536")) |
2052 |
2050 |
2053 self.generic_visit(node) |
2051 self.generic_visit(node) |
2054 |
2052 |
2055 if ( |
2053 if ( |
2502 """ |
2500 """ |
2503 Private method to check various exception handler situations. |
2501 Private method to check various exception handler situations. |
2504 |
2502 |
2505 @param node reference to the node to be processed |
2503 @param node reference to the node to be processed |
2506 @type ast.ExceptHandler |
2504 @type ast.ExceptHandler |
|
2505 @return list of exception handler names |
|
2506 @rtype list of str |
2507 """ |
2507 """ |
2508 handlers = self.__flattenExcepthandler(node.type) |
2508 handlers = self.__flattenExcepthandler(node.type) |
2509 names = [] |
2509 names = [] |
2510 badHandlers = [] |
2510 badHandlers = [] |
2511 ignoredHandlers = [] |
2511 ignoredHandlers = [] |
2649 return |
2649 return |
2650 |
2650 |
2651 # Preserve decorator order so we can get the lineno from the decorator node |
2651 # Preserve decorator order so we can get the lineno from the decorator node |
2652 # rather than the function node (this location definition changes in Python 3.8) |
2652 # rather than the function node (this location definition changes in Python 3.8) |
2653 resolvedDecorators = ( |
2653 resolvedDecorators = ( |
2654 ".".join(composeCallPath(decorator)) |
2654 ".".join(composeCallPath(decorator)) for decorator in node.decorator_list |
2655 for decorator in node.decorator_list |
|
2656 ) |
2655 ) |
2657 for idx, decorator in enumerate(resolvedDecorators): |
2656 for idx, decorator in enumerate(resolvedDecorators): |
2658 if decorator in {"classmethod", "staticmethod"}: |
2657 if decorator in {"classmethod", "staticmethod"}: |
2659 return |
2658 return |
2660 |
2659 |
3116 """ |
3115 """ |
3117 Private method to check the usage of exceptions with added note. |
3116 Private method to check the usage of exceptions with added note. |
3118 |
3117 |
3119 @param node reference to the node to be processed |
3118 @param node reference to the node to be processed |
3120 @type ast.expr or None |
3119 @type ast.expr or None |
3121 """ |
3120 """ # noqa: D234y |
|
3121 |
3122 def superwalk(node: ast.AST | list[ast.AST]): |
3122 def superwalk(node: ast.AST | list[ast.AST]): |
3123 """ |
3123 """ |
3124 Function to walk an AST node or a list of AST nodes. |
3124 Function to walk an AST node or a list of AST nodes. |
3125 |
3125 |
3126 @param node reference to the node or a list of nodes to be processed |
3126 @param node reference to the node or a list of nodes to be processed |
3481 |
3481 |
3482 # Check if function call is actually a float infinity/NaN literal |
3482 # Check if function call is actually a float infinity/NaN literal |
3483 if callPath == "float" and len(node.args) == 1: |
3483 if callPath == "float" and len(node.args) == 1: |
3484 try: |
3484 try: |
3485 value = float(ast.literal_eval(node.args[0])) |
3485 value = float(ast.literal_eval(node.args[0])) |
3486 except Exception: |
3486 except Exception: # secok |
3487 pass |
3487 pass |
3488 else: |
3488 else: |
3489 if math.isfinite(value): |
3489 if math.isfinite(value): |
3490 self.errors.append((node, self.__errorCodeLiterals)) |
3490 self.errors.append((node, self.__errorCodeLiterals)) |
3491 else: |
3491 else: |