Im using pytest framework with mypy and when writing fixtures I created Protocols to mimic return types. (I could not import it directly because of env instantiation)
This example greatly simplifies my troubles:
from typing_extensions import Protocol
class LoadServiceType(Protocol):
z: int
class LoadService:
z: int
#This works as expected
load_serivce: LoadServiceType = LoadService()
# But now I dont know why this does not work
class FooType(Protocol):
load_service: LoadServiceType
class Boo:
x:int
load_service:LoadService
bb: int
cc: FooType = Boo()
Basically I want to use my FooType as a return type because of import issues. Is there any solution ?
This problem can be represented by the following minimal example:
from dataclasses import dataclass
from typing import Protocol
@dataclass
class Fooish:
bar: int
class FooLike(Protocol):
bar: float
foo: FooLike = Fooish(bar=321)
mypy raises the following error:
foo.py:18: error: Incompatible types in assignment (expression has type "Fooish", variable has type "FooLike") [assignment]
foo.py:18: note: Following member(s) of "Fooish" have conflicts:
foo.py:18: note: bar: expected "float", got "int"
The FooLike
protocol represents a set of objects which have a writable float member named bar
. The Fooish
class' bar
member is an int
and does not accept float
values to be assigned, thus is incompatible.
According to foo: FooLike
, the following should be valid, but isn't:
foo: FooLike = Fooish(bar=321)
foo.bar = 21.37
To fix the compatibility issue, one should define the variable as read-only via a @property
:
from dataclasses import dataclass
from typing import Protocol
@dataclass
class Fooish:
bar: int
class FooLike(Protocol):
@property
def bar(self) -> float:
...
foo: FooLike = Fooish(bar=321)
So, going back to your original example, the following snippet works as expected:
from typing_extensions import Protocol
class LoadServiceType(Protocol):
z: int
class LoadService:
z: int
load_serivce: LoadServiceType = LoadService()
class FooType(Protocol):
@property
def load_service(self) -> LoadServiceType:
...
class Boo:
x: int
load_service: LoadService
bb: int
cc: FooType = Boo()