Skip to content

Prefer declared attribute on base class over inferred attribute on subclass #1067

@jankatins

Description

@jankatins

Summary

We use some descriptor (like) classes and basically have an attribute set by __set_name__ (https://docs.python.org/3/reference/datamodel.html#object.__set_name__)

This is a boiled down example:

from typing import Any


class Mixin:
    name: str


class Concrete(Mixin):
    def __init__(self) -> None:
        self.name = None  # type: ignore[assignment]

    def __set_name__(self, owner: Any, name: str) -> None:
        self.name = name

class X:
    c = Concrete()

x = X()
# mypy is ok here, but ty chokes on it
print(x.c.name.upper()) # prints "C"

mypy trusts the declaration in the mixin and allows accessing the attribute unconditionally, but ty seems does not see the descriptor protocol (and does not trust the explicit typing info) and assumes the attribute is not set:

λ  python test.py      
C

λ  mypy test.py        
Success: no issues found in 1 source file

λ  uvx ty check test.py
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
Checking ------------------------------------------------------------ 1/1 files                                                                                                                                                                                                                                     warning[possibly-unbound-attribute]: Attribute `upper` on type `Unknown | str | None` is possibly unbound                                                                                                                                                                                                           
  --> test.py:20:7
   |
18 | x = X()
19 | # mypy is ok here, but ty chokes on it
20 | print(x.c.name.upper()) # prints "C"
   |       ^^^^^^^^^^^^^^
   |
info: rule `possibly-unbound-attribute` is enabled by default

Found 1 diagnostic

Given that I do quite a lot of c.name like usages, I would really avoid having to check every place for None... :-)

Version

ty 0.0.1-alpha.19

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions