diff --git a/mypy/join.py b/mypy/join.py index 5f1d292d65e2..8989a596b70e 100644 --- a/mypy/join.py +++ b/mypy/join.py @@ -187,6 +187,11 @@ def visit_callable_type(self, t: CallableType) -> ProperType: if is_equivalent(t, self.s): return combine_similar_callables(t, self.s) result = join_similar_callables(t, self.s) + # We set the from_type_type flag to suppress error when a collection of + # concrete class objects gets inferred as their common abstract superclass. + if not ((t.is_type_obj() and t.type_object().is_abstract) or + (self.s.is_type_obj() and self.s.type_object().is_abstract)): + result.from_type_type = True if any(isinstance(tp, (NoneType, UninhabitedType)) for tp in get_proper_types(result.arg_types)): # We don't want to return unusable Callable, attempt fallback instead. diff --git a/mypy/meet.py b/mypy/meet.py index 6e9c68d29529..608faf8f25fe 100644 --- a/mypy/meet.py +++ b/mypy/meet.py @@ -533,6 +533,11 @@ def visit_callable_type(self, t: CallableType) -> ProperType: if is_equivalent(t, self.s): return combine_similar_callables(t, self.s) result = meet_similar_callables(t, self.s) + # We set the from_type_type flag to suppress error when a collection of + # concrete class objects gets inferred as their common abstract superclass. + if not ((t.is_type_obj() and t.type_object().is_abstract) or + (self.s.is_type_obj() and self.s.type_object().is_abstract)): + result.from_type_type = True if isinstance(get_proper_type(result.ret_type), UninhabitedType): # Return a plain None or instead of a weird function. return self.default(self.s) diff --git a/test-data/unit/check-abstract.test b/test-data/unit/check-abstract.test index 692943083fa5..1fcbf8bf9f4e 100644 --- a/test-data/unit/check-abstract.test +++ b/test-data/unit/check-abstract.test @@ -951,3 +951,51 @@ default = Config({'cannot': 'modify'}) # OK default[1] = 2 # E: Unsupported target for indexed assignment [builtins fixtures/dict.pyi] [typing fixtures/typing-full.pyi] + +[case testSubclassOfABCFromDictionary] +from abc import abstractmethod, ABCMeta + +class MyAbstractType(metaclass=ABCMeta): + @abstractmethod + def do(self): pass + +class MyConcreteA(MyAbstractType): + def do(self): + print('A') + +class MyConcreteB(MyAbstractType): + def do(self): + print('B') + +class MyAbstractA(MyAbstractType): + @abstractmethod + def do(self): pass + +class MyAbstractB(MyAbstractType): + @abstractmethod + def do(self): pass + +my_concrete_types = { + 'A': MyConcreteA, + 'B': MyConcreteB, +} + +my_abstract_types = { + 'A': MyAbstractA, + 'B': MyAbstractB, +} + +reveal_type(my_concrete_types) # N: Revealed type is 'builtins.dict[builtins.str*, def () -> __main__.MyAbstractType]' +reveal_type(my_abstract_types) # N: Revealed type is 'builtins.dict[builtins.str*, def () -> __main__.MyAbstractType]' + +a = my_concrete_types['A']() +a.do() +b = my_concrete_types['B']() +b.do() + +c = my_abstract_types['A']() # E: Cannot instantiate abstract class 'MyAbstractType' with abstract attribute 'do' +c.do() +d = my_abstract_types['B']() # E: Cannot instantiate abstract class 'MyAbstractType' with abstract attribute 'do' +d.do() + +[builtins fixtures/dict.pyi] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy