mirror of https://github.com/astral-sh/ruff
[ty] Support field_specifiers for metaclass based transformers
This commit is contained in:
parent
23543194fc
commit
ea56e2415f
|
|
@ -461,7 +461,7 @@ The [`typing.dataclass_transform`] specification also allows classes (such as `d
|
||||||
to be listed in `field_specifiers`, but it is currently unclear how this should work, and other type
|
to be listed in `field_specifiers`, but it is currently unclear how this should work, and other type
|
||||||
checkers do not seem to support this either.
|
checkers do not seem to support this either.
|
||||||
|
|
||||||
### Basic example
|
### For function-based transformers
|
||||||
|
|
||||||
```py
|
```py
|
||||||
from typing_extensions import dataclass_transform, Any
|
from typing_extensions import dataclass_transform, Any
|
||||||
|
|
@ -487,6 +487,34 @@ reveal_type(alice.name) # revealed: str
|
||||||
reveal_type(alice.age) # revealed: int | None
|
reveal_type(alice.age) # revealed: int | None
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### For metaclass-based transformers
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing_extensions import dataclass_transform, Any
|
||||||
|
|
||||||
|
def fancy_field(*, init: bool = True, kw_only: bool = False) -> Any: ...
|
||||||
|
@dataclass_transform(field_specifiers=(fancy_field,))
|
||||||
|
class FancyMeta(type):
|
||||||
|
def __new__(cls, name, bases, namespace):
|
||||||
|
...
|
||||||
|
return super().__new__(cls, name, bases, namespace)
|
||||||
|
|
||||||
|
class FancyBase(metaclass=FancyMeta): ...
|
||||||
|
|
||||||
|
class Person(FancyBase):
|
||||||
|
id: int = fancy_field(init=False)
|
||||||
|
name: str = fancy_field()
|
||||||
|
age: int | None = fancy_field(kw_only=True)
|
||||||
|
|
||||||
|
reveal_type(Person.__init__) # revealed: (self: Person, name: str = Unknown, *, age: int | None = Unknown) -> None
|
||||||
|
|
||||||
|
alice = Person("Alice", age=30)
|
||||||
|
|
||||||
|
reveal_type(alice.id) # revealed: int
|
||||||
|
reveal_type(alice.name) # revealed: str
|
||||||
|
reveal_type(alice.age) # revealed: int | None
|
||||||
|
```
|
||||||
|
|
||||||
## Overloaded dataclass-like decorators
|
## Overloaded dataclass-like decorators
|
||||||
|
|
||||||
In the case of an overloaded decorator, the `dataclass_transform` decorator can be applied to the
|
In the case of an overloaded decorator, the `dataclass_transform` decorator can be applied to the
|
||||||
|
|
|
||||||
|
|
@ -4532,12 +4532,21 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||||
let class_node = enclosing_scope.node().as_class()?;
|
let class_node = enclosing_scope.node().as_class()?;
|
||||||
|
|
||||||
let class_definition = index.expect_single_definition(class_node);
|
let class_definition = index.expect_single_definition(class_node);
|
||||||
infer_definition_types(db, class_definition)
|
let class_literal = infer_definition_types(db, class_definition)
|
||||||
.declaration_type(class_definition)
|
.declaration_type(class_definition)
|
||||||
.inner_type()
|
.inner_type()
|
||||||
.as_class_literal()?
|
.as_class_literal()?;
|
||||||
|
|
||||||
|
class_literal
|
||||||
.dataclass_params(db)
|
.dataclass_params(db)
|
||||||
.map(|params| SmallVec::from(params.field_specifiers(db)))
|
.map(|params| SmallVec::from(params.field_specifiers(db)))
|
||||||
|
.or_else(|| {
|
||||||
|
class_literal
|
||||||
|
.try_metaclass(db)
|
||||||
|
.ok()
|
||||||
|
.and_then(|(_, params)| params)
|
||||||
|
.map(|params| SmallVec::from(params.field_specifiers(db)))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(specifiers) = field_specifiers(self.db(), self.index, self.scope()) {
|
if let Some(specifiers) = field_specifiers(self.db(), self.index, self.scope()) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue