Skip to content

Recognize valid pattern of dataclasses with @property #11361

@Cs4System

Description

@Cs4System

I tried a pattern which is absolutely fine in runtime and should be valid code, but pylance is complaining a lot:

from dataclasses import InitVar, dataclass, field


@dataclass
class Animal:
    name: str

    def alive(self) -> str:
        return f"{self.name} is alive"


@dataclass
class Duck(Animal):
    age: InitVar[int]
    _age: int = field(init=False, repr=False)  # do not initialize, only register datafield

    def __post_init__(self, age: int):
        self.age = age  # uses setter!

    @property
    def age(self) -> int:
        return self._age

    @age.setter
    def age(self, value: int):
        if value < 0:
            raise ValueError("Age cannot be negative!")
        self._age = value

    def fly(self) -> str:
        return f"{self.name} flies"

    def swim(self) -> str:
        return f"{self.name} swims"


def main() -> None:
    duck = Duck(name="Daisy", age=2)
    print(duck.alive())
    print(duck.fly())
    print(duck.swim())
    print(duck.age)


if __name__ == "__main__":
    main()

problem detected by pylance:

[{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportRedeclaration",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportRedeclaration.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Declaration \"age\" is obscured by a declaration of the same name",
	"source": "Pylance",
	"startLineNumber": 23,
	"startColumn": 5,
	"endLineNumber": 23,
	"endColumn": 8,
	"relatedInformation": [
		{
			"startLineNumber": 34,
			"startColumn": 9,
			"endLineNumber": 34,
			"endColumn": 12,
			"message": "See method declaration",
			"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py"
		}
	],
	"modelVersionId": 565,
	"origin": "extHost1"
},{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportGeneralTypeIssues",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportGeneralTypeIssues.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Dataclass __post_init__ method parameter type mismatch for field \"age\"\n  \"property\" is not assignable to \"int\"",
	"source": "Pylance",
	"startLineNumber": 26,
	"startColumn": 34,
	"endLineNumber": 26,
	"endColumn": 37,
	"relatedInformation": [
		{
			"startLineNumber": 23,
			"startColumn": 5,
			"endLineNumber": 23,
			"endColumn": 8,
			"message": "Field declaration",
			"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py"
		}
	],
	"modelVersionId": 565,
	"origin": "extHost1"
},{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportAttributeAccessIssue",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportAttributeAccessIssue.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Cannot assign to attribute \"age\" for class \"Duck*\"\n  \"age\" is an init-only field",
	"source": "Pylance",
	"startLineNumber": 27,
	"startColumn": 14,
	"endLineNumber": 27,
	"endColumn": 17,
	"modelVersionId": 565,
	"origin": "extHost1"
},{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportUnknownMemberType",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportUnknownMemberType.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Type of \"age\" is unknown",
	"source": "Pylance",
	"startLineNumber": 51,
	"startColumn": 11,
	"endLineNumber": 51,
	"endColumn": 19,
	"modelVersionId": 565,
	"origin": "extHost1"
},{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportUnknownArgumentType",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportUnknownArgumentType.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Argument type is unknown\n  Argument corresponds to parameter \"values\" in function \"print\"",
	"source": "Pylance",
	"startLineNumber": 51,
	"startColumn": 11,
	"endLineNumber": 51,
	"endColumn": 19,
	"modelVersionId": 565,
	"origin": "extHost1"
},{
	"resource": "/d:/dev/python_oop/src/python_oop/1_4_simple_inherritance_init_dataclass.py",
	"owner": "Pylance5",
	"code": {
		"value": "reportAttributeAccessIssue",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pylance-release/blob/main/docs/diagnostics/reportAttributeAccessIssue.md",
			"scheme": "https",
			"authority": "github.com"
		}
	},
	"severity": 8,
	"message": "Cannot access attribute \"age\" for class \"Duck\"\n  \"age\" is an init-only field",
	"source": "Pylance",
	"startLineNumber": 51,
	"startColumn": 16,
	"endLineNumber": 51,
	"endColumn": 19,
	"modelVersionId": 565,
	"origin": "extHost1"
}]

This pattern should be recognized and have no type errors.
Thanks!

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions