From e5250d47cc69779c330809ae2c75baa99427f899 Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 26 Sep 2021 19:17:29 -0700 Subject: [PATCH 1/7] Make any callable compatible with (*args: Any, **kwargs: Any) Resolves #5876 --- mypy/subtypes.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 63cebc8aa483..da6734a92a40 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -18,7 +18,7 @@ # import mypy.solve from mypy.nodes import ( FuncBase, Var, Decorator, OverloadedFuncDef, TypeInfo, CONTRAVARIANT, COVARIANT, - + ARG_STAR, ARG_STAR2, ) from mypy.maptype import map_instance_to_supertype from mypy.expandtype import expand_type_by_instance @@ -893,6 +893,14 @@ def g(x: int) -> int: ... right_star = right.var_arg() right_star2 = right.kw_arg() + # Treat "def _(*a: Any, **kw: Any) -> X" similarly to "Callable[..., X]" + if ( + right.arg_kinds == [ARG_STAR, ARG_STAR2] + and right_star and isinstance(right_star.typ, AnyType) + and right_star2 and isinstance(right_star2.typ, AnyType) + ): + return True + # Match up corresponding arguments and check them for compatibility. In # every pair (argL, argR) of corresponding arguments from L and R, argL must # be "more general" than argR if L is to be a subtype of R. From eb7f3693402c8eab63984f761894ccbf74376b8c Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 26 Sep 2021 20:15:57 -0700 Subject: [PATCH 2/7] proper type --- mypy/subtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index da6734a92a40..32e4a6ebb195 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -896,8 +896,8 @@ def g(x: int) -> int: ... # Treat "def _(*a: Any, **kw: Any) -> X" similarly to "Callable[..., X]" if ( right.arg_kinds == [ARG_STAR, ARG_STAR2] - and right_star and isinstance(right_star.typ, AnyType) - and right_star2 and isinstance(right_star2.typ, AnyType) + and right_star and isinstance(get_proper_type(right_star.typ), AnyType) + and right_star2 and isinstance(get_proper_type(right_star2.typ), AnyType) ): return True From 3c6f9591c6f0486cf7e1954958390d6268066d8d Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 26 Sep 2021 20:18:30 -0700 Subject: [PATCH 3/7] fix up tests --- test-data/unit/check-functions.test | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 6279e34a2904..0b6e05cf5f35 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -188,9 +188,9 @@ if int(): ee_var = everywhere if int(): - ee_var = specific_1 # The difference between Callable[..., blah] and one with a *args: Any, **kwargs: Any is that the ... goes loosely both ways. + ee_var = specific_1 if int(): - ee_def = specific_1 # E: Incompatible types in assignment (expression has type "Callable[[int, str], None]", variable has type "Callable[[VarArg(Any), KwArg(Any)], None]") + ee_def = specific_1 [builtins fixtures/dict.pyi] @@ -1827,7 +1827,7 @@ def f2(*args, **kwargs) -> int: pass d(f1) e(f2) d(f2) -e(f1) # E: Argument 1 to "e" has incompatible type "Callable[[VarArg(Any)], int]"; expected "Callable[[VarArg(Any), KwArg(Any)], int]" +e(f1) [builtins fixtures/dict.pyi] @@ -2224,7 +2224,7 @@ from typing import Callable class A: def f(self) -> None: # In particular, test that the error message contains "g" of "A". - self.g() # E: Too few arguments for "g" of "A" + self.g() # E: Too few arguments for "g" of "A" self.g(1) @dec def g(self, x: str) -> None: pass From 5d7cc46d27f934b8f1b8d17ce37cc16dc5c3d04e Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Sun, 26 Sep 2021 21:20:47 -0700 Subject: [PATCH 4/7] another test --- test-data/unit/check-classes.test | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 78d261818380..f298236c8512 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -6891,3 +6891,14 @@ class B(A): # E: Final class __main__.B has abstract attributes "foo" [case testUndefinedBaseclassInNestedClass] class C: class C1(XX): pass # E: Name "XX" is not defined + + +[case testArgsKwargsInheritance] +from typing import Any + +class A(object): + def f(self, *args: Any, **kwargs: Any) -> int: ... + +class B(A): + def f(self, x: int) -> int: ... +[builtins fixtures/dict.pyi] From 83fe962315dc44fe90d508d4a53f32aebf934bfe Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Fri, 12 Aug 2022 23:57:14 +0100 Subject: [PATCH 5/7] Fix black --- mypy/subtypes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mypy/subtypes.py b/mypy/subtypes.py index 7a233e9aacb6..e8bb3bffa858 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -1296,8 +1296,10 @@ def are_parameters_compatible( # Treat "def _(*a: Any, **kw: Any) -> X" similarly to "Callable[..., X]" if ( right.arg_kinds == [ARG_STAR, ARG_STAR2] - and right_star and isinstance(get_proper_type(right_star.typ), AnyType) - and right_star2 and isinstance(get_proper_type(right_star2.typ), AnyType) + and right_star + and isinstance(get_proper_type(right_star.typ), AnyType) + and right_star2 + and isinstance(get_proper_type(right_star2.typ), AnyType) ): return True From 168e0647ed101edd7fe078d1f87f62b1cbe6e7be Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Sat, 13 Aug 2022 00:16:23 +0100 Subject: [PATCH 6/7] Fix a test --- test-data/unit/check-modules.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 60e95877336c..31f6beaf15cb 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -3160,7 +3160,7 @@ from test1 import aaaa # E: Module "test1" has no attribute "aaaa" import b [file a.py] class Foo: - def frobnicate(self, *args, **kwargs): pass + def frobnicate(self, x, *args, **kwargs): pass [file b.py] from a import Foo class Bar(Foo): @@ -3178,12 +3178,12 @@ class Bar(Foo): [out1] tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" tmp/b.py:3: note: Superclass: -tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: def frobnicate(self, x, *args: Any, **kwargs: Any) -> Any tmp/b.py:3: note: Subclass: tmp/b.py:3: note: def frobnicate(self) -> None [out2] tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" tmp/b.py:3: note: Superclass: -tmp/b.py:3: note: def frobnicate(self, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: def frobnicate(self, x, *args: Any, **kwargs: Any) -> Any tmp/b.py:3: note: Subclass: tmp/b.py:3: note: def frobnicate(self, *args: Any) -> None From 9edc6f859f0c34dcf0e2a46e92cade9475a7f35a Mon Sep 17 00:00:00 2001 From: Ivan Levkivskyi Date: Sat, 13 Aug 2022 00:46:17 +0100 Subject: [PATCH 7/7] Fix a test for real --- test-data/unit/check-modules.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 31f6beaf15cb..d83d0470c6b0 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -3178,12 +3178,12 @@ class Bar(Foo): [out1] tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" tmp/b.py:3: note: Superclass: -tmp/b.py:3: note: def frobnicate(self, x, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: def frobnicate(self, x: Any, *args: Any, **kwargs: Any) -> Any tmp/b.py:3: note: Subclass: tmp/b.py:3: note: def frobnicate(self) -> None [out2] tmp/b.py:3: error: Signature of "frobnicate" incompatible with supertype "Foo" tmp/b.py:3: note: Superclass: -tmp/b.py:3: note: def frobnicate(self, x, *args: Any, **kwargs: Any) -> Any +tmp/b.py:3: note: def frobnicate(self, x: Any, *args: Any, **kwargs: Any) -> Any tmp/b.py:3: note: Subclass: tmp/b.py:3: note: def frobnicate(self, *args: Any) -> None