From 073cbf90b71dcb82053842fe6106dbd63302d767 Mon Sep 17 00:00:00 2001 From: jkchandalia Date: Mon, 24 Apr 2023 10:47:36 -0700 Subject: [PATCH 1/6] Add test case for both classmethod and staticmethod --- test-data/unit/check-classes.test | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 9e45da717426..a33f8b0e6eb9 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -1395,6 +1395,13 @@ main:8: note: def f(cls) -> None main:8: note: Subclass: main:8: note: def f(self) -> None +[case testClassMethodAndStaticMethod] +class C: + @classmethod # E: Cannot have both classmethod and staticmethod + @staticmethod + def foo(cls) -> None: pass +[builtins fixtures/classmethod.pyi] + -- Properties -- ---------- From 8b868c932d2dc53bed15a8f53ac172a873ef4b5a Mon Sep 17 00:00:00 2001 From: jkchandalia Date: Mon, 24 Apr 2023 11:24:02 -0700 Subject: [PATCH 2/6] Update message to raise --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index a33f8b0e6eb9..ac9ba7abd4d5 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -1397,7 +1397,7 @@ main:8: note: def f(self) -> None [case testClassMethodAndStaticMethod] class C: - @classmethod # E: Cannot have both classmethod and staticmethod + @classmethod # E: "Type[C]" cannot have both classmethod and staticmethod @staticmethod def foo(cls) -> None: pass [builtins fixtures/classmethod.pyi] From adfb75524f32d723ac82bdb19aa72258ad0f1616 Mon Sep 17 00:00:00 2001 From: jkchandalia Date: Mon, 24 Apr 2023 13:22:26 -0700 Subject: [PATCH 3/6] Update message --- test-data/unit/check-classes.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index ac9ba7abd4d5..a33f8b0e6eb9 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -1397,7 +1397,7 @@ main:8: note: def f(self) -> None [case testClassMethodAndStaticMethod] class C: - @classmethod # E: "Type[C]" cannot have both classmethod and staticmethod + @classmethod # E: Cannot have both classmethod and staticmethod @staticmethod def foo(cls) -> None: pass [builtins fixtures/classmethod.pyi] From 1e95381ab042b2a88b174c2b0ea16cf65cadfdcd Mon Sep 17 00:00:00 2001 From: jkchandalia Date: Mon, 24 Apr 2023 13:24:22 -0700 Subject: [PATCH 4/6] Add msg to registry --- mypy/message_registry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 130b94c7bf9a..523feb927007 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -268,6 +268,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ) CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = 'Duplicate keyword pattern "{}"' CLASS_PATTERN_UNKNOWN_KEYWORD: Final = 'Class "{}" has no attribute "{}"' +CLASS_PATTERN_CLASS_OR_STATIC_METHOD: Final = 'Cannot have both classmethod and staticmethod' MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = 'Multiple assignments to name "{}" in pattern' CANNOT_MODIFY_MATCH_ARGS: Final = 'Cannot assign to "__match_args__"' From 317aca6df772338c2480bb7caaa4d80fa29603de Mon Sep 17 00:00:00 2001 From: jkchandalia Date: Mon, 24 Apr 2023 13:25:22 -0700 Subject: [PATCH 5/6] Add message raising line --- mypy/semanal.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mypy/semanal.py b/mypy/semanal.py index ad470fbfd9de..c712b506c0c8 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1548,6 +1548,8 @@ def visit_decorator(self, dec: Decorator) -> None: self.fail("Only instance methods can be decorated with @property", dec) if dec.func.abstract_status == IS_ABSTRACT and dec.func.is_final: self.fail(f"Method {dec.func.name} is both abstract and final", dec) + if dec.func.is_static and dec.func.is_class: + self.fail(message_registry.CLASS_PATTERN_CLASS_OR_STATIC_METHOD, dec) def check_decorated_function_is_method(self, decorator: str, context: Context) -> None: if not self.type or self.is_func_scope(): From b0de626a975f806e5009f0a4999d23bd2fdc11ba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 20:30:51 +0000 Subject: [PATCH 6/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/message_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/message_registry.py b/mypy/message_registry.py index 523feb927007..fea5da236f70 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -268,7 +268,7 @@ def with_additional_msg(self, info: str) -> ErrorMessage: ) CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN: Final = 'Duplicate keyword pattern "{}"' CLASS_PATTERN_UNKNOWN_KEYWORD: Final = 'Class "{}" has no attribute "{}"' -CLASS_PATTERN_CLASS_OR_STATIC_METHOD: Final = 'Cannot have both classmethod and staticmethod' +CLASS_PATTERN_CLASS_OR_STATIC_METHOD: Final = "Cannot have both classmethod and staticmethod" MULTIPLE_ASSIGNMENTS_IN_PATTERN: Final = 'Multiple assignments to name "{}" in pattern' CANNOT_MODIFY_MATCH_ARGS: Final = 'Cannot assign to "__match_args__"'