mirror of
https://github.com/astral-sh/ruff.git
synced 2026-05-06 08:56:57 -04:00
3ef310100a
## 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.