From 76f6a740742843b03725d10e579cb8470f07699d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 27 Sep 2021 15:15:53 -0400 Subject: [PATCH] don't rewrite old-super for staticmethods --- pyupgrade/_plugins/legacy.py | 11 +++++++++++ tests/features/super_test.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pyupgrade/_plugins/legacy.py b/pyupgrade/_plugins/legacy.py index f7ba3763..3ae702a2 100644 --- a/pyupgrade/_plugins/legacy.py +++ b/pyupgrade/_plugins/legacy.py @@ -8,6 +8,7 @@ from typing import List from typing import Set from typing import Tuple +from typing import Union from tokenize_rt import Offset from tokenize_rt import Token @@ -25,6 +26,7 @@ FUNC_TYPES = (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef) NON_LAMBDA_FUNC_TYPES = (ast.FunctionDef, ast.AsyncFunctionDef) +NonLambdaFuncTypes_T = Union[ast.FunctionDef, ast.AsyncFunctionDef] def _fix_yield(i: int, tokens: List[Token]) -> None: @@ -44,6 +46,14 @@ def _is_simple_base(base: ast.AST) -> bool: ) +def _is_staticmethod_decorated(node: NonLambdaFuncTypes_T) -> bool: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Name) and decorator.id == 'staticmethod': + return True + else: + return False + + class Scope: def __init__(self, node: ast.AST) -> None: self.node = node @@ -127,6 +137,7 @@ def visit_Call(self, node: ast.Call) -> None: isinstance(self._scopes[-1].node, NON_LAMBDA_FUNC_TYPES) and node.func.attr == self._scopes[-1].node.name and node.func.attr != '__new__' and + not _is_staticmethod_decorated(self._scopes[-1].node) and len(self._scopes[-1].node.args.args) >= 1 and node.args[0].id == self._scopes[-1].node.args.args[0].arg and # the function is an attribute of the contained class name diff --git a/tests/features/super_test.py b/tests/features/super_test.py index 8e3be14f..e58ffeab 100644 --- a/tests/features/super_test.py +++ b/tests/features/super_test.py @@ -188,6 +188,13 @@ def test_fix_super(s, expected): ' return tuple.__new__(cls, (arg,))\n', id='super() does not work properly for __new__', ), + pytest.param( + 'class C(B):\n' + ' @staticmethod\n' + ' def f(arg):\n' + ' return B.f(arg)\n', + id='skip staticmethod', + ), ), ) def test_old_style_class_super_noop(s): @@ -207,6 +214,17 @@ def test_old_style_class_super_noop(s): ' super().f()\n' ' super().f(arg, arg)\n', ), + pytest.param( + 'class C(B):\n' + ' @classmethod\n' + ' def f(cls):\n' + ' B.f(cls)\n', + 'class C(B):\n' + ' @classmethod\n' + ' def f(cls):\n' + ' super().f()\n', + id='@classmethod', + ), pytest.param( 'class C(B):\n' ' def f(self, a):\n'