Files
astral-ruff/crates
Charlie Marsh 3ef310100a [ty] Detect invalid attribute overrides (#24767)
## Summary

We now detect Liskov violations when a parent-child pair have attributes
with a differing `ClassVar` status.

In general, we interpret an attribute without a `ClassVar` annotation as
an instance attribute, with the exception of cases like the following,
where we "allow" the child to "inherit" the annotation to adhere to the
conformance suite:

```python
class ProtoB(Protocol):
    z: ClassVar[int]

class ProtoBImpl(ProtoB):
    z = 0
```

There are a few other tricky cases to consider.

### Methods

Like Mypy and Pyright, we don't flag the following:

```py
from typing import Any, Callable, ClassVar

class Base:
    f: ClassVar[Callable[..., Any]]

class Sub(Base):
    def f(self) -> int:
        return 1
```

### Descriptors

Like Mypy and Pyright, we don't flag the following:

```python
class Descriptor:
    def __get__(self, obj: object, owner: type[object]) -> int:
        return 1

class Base:
    attr = Descriptor()

class Sub(Base):
    attr: int
```

### Properties

Like Mypy and Pyright, we _do_ flag the following, since it changes the
class-vs.-instance contract:

```python
from typing import ClassVar

class Base:
    attr: ClassVar[int]

class Sub(Base):
    @property
    def attr(self) -> int:  # error: [invalid-attribute-override]
        return 1
```

#### Final

We don't flag the following, because it already has a dedicated
diagnostic:

```python
from typing import Final

class Base:
    attr: Final[int] = 1

class Sub(Base):
    attr = 2  # error: [override-of-final-variable]
```

Closes https://github.com/astral-sh/ty/issues/3093.
2026-04-27 14:24:23 -04:00
..
2026-04-24 12:36:40 -05:00
2026-04-24 12:36:40 -05:00
2026-04-24 12:36:40 -05:00