Issue 47237: Inheritance from base class with property in class makes them non-instantiatable (original) (raw)

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 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 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