New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inheritance from base class with property in class makes them non-instantiatable #91393
Comments
Hi, According to https://peps.python.org/pep-0544/#explicitly-declaring-implementation it should be possible to explicitly inherit from Protocols. This however breaks the dataclass constructor when using the @Property decorator in the protocol, see this example: from typing import Protocol
from dataclasses import dataclass
class SomeProtocol(Protocol):
@property
def some_value(self) -> str: ...
@dataclass
class SomeDataclasss(SomeProtocol):
some_value: str
if __name__ == '__main__':
a = SomeDataclasss(some_value="value") # this crashes with AttributeError: can't set attribute 'some_value' The pattern of @Property in the protocol is one taken from the mypy docs (see https://mypy.readthedocs.io/en/stable/protocols.html#recursive-protocols for example). When removing the explicit inheritiance mypy also correctly typechecks the dataclass implementation when doing something like, only the explicit inheritance seems to fail in python a: SomeProtocol = SomeDataclass() |
Here's the error without dataclasses: ------ from typing import Protocol
class SomeProtocol(Protocol):
@property
def some_value(self) -> str: ...
class SomeClass(SomeProtocol):
def __init__(self, some_value):
self.some_value = some_value
if __name__ == '__main__':
a = SomeClass(some_value="value") Traceback (most recent call last):
File "foo.py", line 12, in <module>
a = SomeClass(some_value="value")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "foo.py", line 9, in __init__
self.some_value = some_value
^^^^^^^^^^^^^^^
AttributeError: property 'some_value' of 'SomeClass' object has no setter And here it is without Protocol: class SomeProperty:
@property
def some_value(self) -> str: ...
class SomeClass(SomeProperty):
def __init__(self, some_value):
self.some_value = some_value
if __name__ == '__main__':
a = SomeClass(some_value="value") Traceback (most recent call last):
File "foo.py", line 10, in <module>
a = SomeClass(some_value="value")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "foo.py", line 7, in __init__
self.some_value = some_value
^^^^^^^^^^^^^^^
AttributeError: property 'some_value' of 'SomeClass' object has no setter |
So is the conclusion that this should be closed as "not a bug"? |
I think the behavior with regular classes is expected (that's just how inheritance works), but a case could be made that dataclasses should handle this case specially. |
What would dataclasses do that's different from a regular class? |
With CPython 3.10.7 and mypy 0.982 import abc
import dataclasses as dc
from typing import Protocol
class Proto(Protocol):
@property
@abc.abstractmethod
def prop(self) -> int:
raise NotImplementedError
@dc.dataclass
class Implicit:
prop: int
@dc.dataclass
class Explicit(Proto):
prop: int
x: Proto = Implicit(42)
y: Proto = Explicit(42) The results are:
|
I see this as a perhaps surprising result of how all these things work, not as a bug. Note that |
Another workaround that removes inheritance but preserves explicit type checking at the place of definition: if TYPE_CHECKING:
_: type[Proto] = Explicit
@dc.dataclass
class Explicit:
prop: int |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: