from abc import ABC, abstractmethod
from typing import Any, Dict, Generic, TYPE_CHECKING, Type, TypeVar, cast
T = TypeVar("T")
RT = TypeVar("RT")
class Base(Generic[T, RT]):
registry: Dict[Type[Any], Type[Any]] = {}
def __init_subclass__(cls, return_type: Type[RT]) -> None:
Base.registry[return_type] = cls
@staticmethod
def get(return_type: Type[Any]) -> T:
subclass = Base.registry[return_type]
return cast(T, subclass)
class InterfaceA(Generic[RT], ABC):
@property
@abstractmethod
def prop_a1(self) -> RT:
pass
@property
@abstractmethod
def prop_a2(self) -> RT:
pass
class ConcreteA(InterfaceA[str], Base[InterfaceA[str], str], return_type=str):
@property
def prop_a1(self) -> str:
return "prop_a1"
@property
def prop_a2(self) -> str:
return "prop_a2"
x = Base[InterfaceA[str], str].get(str)
print(x) # <class '__main__.ConcreteA'>
# "object" not callable [operator] mypy(error)
print(x().prop_a1) # prop_a1
# "T" has no attribute "prop_a1" [attr-defined] mypy(error)
print(x.prop_a1) # <property object at 0x7fdc69f4c5e0>
if TYPE_CHECKING:
# Type of "x" is "InterfaceA[str]" Pylance
# Revealed type is "T`1" mypy(note)
reveal_type(x)
I recognise that this may seem odd, but the Base class is meant to be part of a library, whereas the code below is part of the implementation. The user implements Event classes (not shown) and NotificationTemplates (InterfaceA) which specify target types for the Notification (prop_a1, prop_a2) that differ for each NotificationTemplate (InterfaceA). The NotificationTemplates (InterfaceA) then has concrete implementations for an Email adapter or Firebase Messaging adapter (ConcreteA, etc.) which have a specific return type (RT) such as EmailMessage (str) and so on.
When sending the notification after the event triggers, the worker checks on a user's contact preferences to see which notification adapter to use, then uses NotificationTemplate[
PostPublishedNotificationTemplate[EmailMessage], EmailMessage
].get(PostPublishedEvent, EmailNotificationAdapter) (Base[InterfaceA[str], str].get(str)) to get the concrete implementation of the notification adapter which has the correct interface for the event, and returns the right object for the notification adapter :sweat_smile:
Hi all, question about PEP 561 and mypy 0.900 -- with stubs unbundling from typeshed, have there been changes to the order in which mypy selects type information? If I install a stubs-only package types-foo and foo also has inline type hints + is marked with py.typed, what takes priority? Per my interpretation of https://www.python.org/dev/peps/pep-0561/#type-checker-module-resolution-order, I assume the stubs-only package types-foo wins
Stub packages - these packages SHOULD supersede any installed inline package.
type_guard key not being there feels like it might be a regression?
from typing import Generic, Protocol, TypeVar, cast
T = TypeVar("T")
RT_co = TypeVar("RT_co", covariant=True)
class HasMyprop(Protocol[RT_co]):
@property
def myprop(self) -> RT_co:
...
class Concrete(HasMyprop[str]):
@property
def myprop(self) -> str:
return "beans"
class MyPropFactory(Generic[T]):
@staticmethod
def get() -> T:
return cast(T, Concrete())
my_instance = MyPropFactory[HasMyprop[str]].get()
# pylance: (variable) my_instance: HasMyprop[str]
# mypy: "T" has no attribute "myprop" [attr-defined] mypy(error)
my_instance.myprop # pylance: (property) myprop: str
my_instance.myprop it outputs "beans"
from typing import Generic, TypeVar, cast
T = TypeVar("T")
class MyClass(Generic[T]):
@staticmethod
def get() -> T:
return cast(T, object())
x: str = MyClass[str].get()
# Incompatible types in assignment (expression has type "T", variable has type "str") [assignment]mypy(error)
from typing import Any, Dict, Generic, Protocol, Type, TypeVar
RT = TypeVar("RT")
class MyProtocol(Protocol[RT]):
implementations: Dict[Type[Any], Type["MyProtocol[RT]"]] = {}
def run(self) -> RT:
...
def __init_subclass__(cls, return_type: Type[Any]) -> None:
# Access to generic instance variables via class is ambiguous [misc]mypy(error)
MyProtocol.implementations[return_type] = cls
class MyImplementation(MyProtocol[str], return_type=str):
def run(self) -> str:
return "beans"
x: str = MyProtocol.implementations[str]().run()
@flyte the following seems to work for me
from typing import Any, Dict, Generic, Protocol, Type, TypeVar
T = TypeVar("T")
RT = TypeVar("RT", covariant=True)
class MyProtocol(Protocol[RT]):
@staticmethod
def get_implementation(x: Type[T]) -> MyProtocol[T]:
...
def run(self) -> RT:
...
reveal_type(MyProtocol.get_implementation(str).run())if you really need implementations to be a dict, you can create something with the appropriately typed __getitem__
__init_subclass__ implementaiton but I figure if you run into issues there a type ignore isn't too bad since it doesn't affect users of your abstraction
$ mypy --strict test2.py
test2.py:107: error: "object" not callable
test2.py:111: error: "TemplateT" has no attribute "post_author"
Found 2 errors in 1 file (checked 1 source file)
flyte@demosthenes:~/dev/mything
$ echo $?
1
flyte@demosthenes:~/dev/mything
$ mypy --version
mypy 0.902
--strict)
f(b) be inferred here?from typing import TypeVar, Generic, Sequence
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, a: T) -> None:
self.a = a
def f(a: Container[Sequence[T]]) -> None:
pass
'''
l: Sequence[int] = [1, 2, 3]
b = Container(l)
'''
b = Container([1, 2, 3])
'''#'''
f(b)
@Pyprohly You need to make T typevar covariant for that to work
T = TypeVar('T')
T_co = TypeVar('T_co', covariant=True)
class Container(Generic[T_co]):
def __init__(self, a: T_co) -> None:
self.a = a
def f(a: Container[Sequence[T]]) -> None:
pass
b = Container([1, 2, 3])
reveal_type(b)
f(b)
Hello!
I have an abstract base class. In an abstract method, how can I express that one of the argument must be a subclass of a a base class?
from dataclasses import dataclass
from abc import ABC, abstractmethod
@dataclass
class ItemBase:
a: int
@dataclass
class Item1(ItemBase):
b: int
class Base(ABC):
@abstractmethod
def meth(self, x: ItemBase) -> None:
print(x.a)
class Derived(Base):
def meth(self, x: Item1) -> None:
print(x.a, x.b)For example, I would like to ensure that argument x of Base.meth must be a subclass of ItemBase.
Thanks!
i'm seeing the exact same behavior as python/mypy#10273, and i've tried the recommendations in https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules but i'm not getting it to work.
basically, i have a file src/tasks/foo.py and a file tests/tasks/test_foo.py, where test_foo.py contains import tasks.foo, and i get the error (on the import statement) if i run mypy tests/tasks/test_foo.py, but not if i run mypy src/tasks/foo.py tests/tasks/test_foo.py.
since the editor integration runs mypy on one file at a time, i don't understand how to make it understand that the types for bar.py are available. what do i do to tell mypy that bar.py exports types, when running mypy foo.py?
os.environ if some_bool else {}, but it fails, and just makes it object. Pyright correctly deduces it to be Union[_Environ, dict], which then is acceped in a place that requires a Mapping. See https://github.com/henryiii/cibuildwheel/pull/2#discussion_r654112955