mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:50:38 +00:00
[ty] NamedTuple 'fallback' attributes (#18127)
## Summary Add various attributes to `NamedTuple` classes/instances that are available at runtime. closes https://github.com/astral-sh/ty/issues/417 ## Test Plan New Markdown tests
This commit is contained in:
parent
8644c9da43
commit
e67b35743a
3 changed files with 53 additions and 5 deletions
|
@ -139,6 +139,33 @@ class Property[T](NamedTuple):
|
||||||
reveal_type(Property("height", 3.4)) # revealed: Property[Unknown]
|
reveal_type(Property("height", 3.4)) # revealed: Property[Unknown]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Attributes on `NamedTuple`
|
||||||
|
|
||||||
|
The following attributes are available on `NamedTuple` classes / instances:
|
||||||
|
|
||||||
|
```py
|
||||||
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
class Person(NamedTuple):
|
||||||
|
name: str
|
||||||
|
age: int | None = None
|
||||||
|
|
||||||
|
reveal_type(Person._field_defaults) # revealed: dict[str, Any]
|
||||||
|
reveal_type(Person._fields) # revealed: tuple[str, ...]
|
||||||
|
reveal_type(Person._make) # revealed: bound method <class 'Person'>._make(iterable: Iterable[Any]) -> Self
|
||||||
|
reveal_type(Person._asdict) # revealed: def _asdict(self) -> dict[str, Any]
|
||||||
|
reveal_type(Person._replace) # revealed: def _replace(self, **kwargs: Any) -> Self
|
||||||
|
|
||||||
|
# TODO: should be `Person` once we support `Self`
|
||||||
|
reveal_type(Person._make(("Alice", 42))) # revealed: Unknown
|
||||||
|
|
||||||
|
person = Person("Alice", 42)
|
||||||
|
|
||||||
|
reveal_type(person._asdict()) # revealed: dict[str, Any]
|
||||||
|
# TODO: should be `Person` once we support `Self`
|
||||||
|
reveal_type(person._replace(name="Bob")) # revealed: Unknown
|
||||||
|
```
|
||||||
|
|
||||||
## `collections.namedtuple`
|
## `collections.namedtuple`
|
||||||
|
|
||||||
```py
|
```py
|
||||||
|
|
|
@ -118,6 +118,8 @@ pub enum KnownModule {
|
||||||
Dataclasses,
|
Dataclasses,
|
||||||
Collections,
|
Collections,
|
||||||
Inspect,
|
Inspect,
|
||||||
|
#[strum(serialize = "_typeshed._type_checker_internals")]
|
||||||
|
TypeCheckerInternals,
|
||||||
TyExtensions,
|
TyExtensions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +137,7 @@ impl KnownModule {
|
||||||
Self::Dataclasses => "dataclasses",
|
Self::Dataclasses => "dataclasses",
|
||||||
Self::Collections => "collections",
|
Self::Collections => "collections",
|
||||||
Self::Inspect => "inspect",
|
Self::Inspect => "inspect",
|
||||||
|
Self::TypeCheckerInternals => "_typeshed._type_checker_internals",
|
||||||
Self::TyExtensions => "ty_extensions",
|
Self::TyExtensions => "ty_extensions",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1289,6 +1289,14 @@ impl<'db> ClassLiteral<'db> {
|
||||||
|
|
||||||
Some(Type::Callable(CallableType::single(db, signature)))
|
Some(Type::Callable(CallableType::single(db, signature)))
|
||||||
}
|
}
|
||||||
|
(CodeGeneratorKind::NamedTuple, name) if name != "__init__" => {
|
||||||
|
KnownClass::NamedTupleFallback
|
||||||
|
.to_class_literal(db)
|
||||||
|
.into_class_literal()?
|
||||||
|
.own_class_member(db, None, name)
|
||||||
|
.symbol
|
||||||
|
.ignore_possibly_unbound()
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1985,6 +1993,8 @@ pub enum KnownClass {
|
||||||
NotImplementedType,
|
NotImplementedType,
|
||||||
// dataclasses
|
// dataclasses
|
||||||
Field,
|
Field,
|
||||||
|
// _typeshed._type_checker_internals
|
||||||
|
NamedTupleFallback,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> KnownClass {
|
impl<'db> KnownClass {
|
||||||
|
@ -2067,7 +2077,8 @@ impl<'db> KnownClass {
|
||||||
// (see https://docs.python.org/3/library/constants.html#NotImplemented)
|
// (see https://docs.python.org/3/library/constants.html#NotImplemented)
|
||||||
| Self::NotImplementedType
|
| Self::NotImplementedType
|
||||||
| Self::Classmethod
|
| Self::Classmethod
|
||||||
| Self::Field => Truthiness::Ambiguous,
|
| Self::Field
|
||||||
|
| Self::NamedTupleFallback => Truthiness::Ambiguous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2141,7 +2152,8 @@ impl<'db> KnownClass {
|
||||||
| Self::EllipsisType
|
| Self::EllipsisType
|
||||||
| Self::NotImplementedType
|
| Self::NotImplementedType
|
||||||
| Self::UnionType
|
| Self::UnionType
|
||||||
| Self::Field => false,
|
| Self::Field
|
||||||
|
| Self::NamedTupleFallback => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2217,6 +2229,7 @@ impl<'db> KnownClass {
|
||||||
}
|
}
|
||||||
Self::NotImplementedType => "_NotImplementedType",
|
Self::NotImplementedType => "_NotImplementedType",
|
||||||
Self::Field => "Field",
|
Self::Field => "Field",
|
||||||
|
Self::NamedTupleFallback => "NamedTupleFallback",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2446,6 +2459,7 @@ impl<'db> KnownClass {
|
||||||
| Self::Deque
|
| Self::Deque
|
||||||
| Self::OrderedDict => KnownModule::Collections,
|
| Self::OrderedDict => KnownModule::Collections,
|
||||||
Self::Field => KnownModule::Dataclasses,
|
Self::Field => KnownModule::Dataclasses,
|
||||||
|
Self::NamedTupleFallback => KnownModule::TypeCheckerInternals,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2508,7 +2522,8 @@ impl<'db> KnownClass {
|
||||||
| Self::Super
|
| Self::Super
|
||||||
| Self::NamedTuple
|
| Self::NamedTuple
|
||||||
| Self::NewType
|
| Self::NewType
|
||||||
| Self::Field => false,
|
| Self::Field
|
||||||
|
| Self::NamedTupleFallback => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2573,7 +2588,8 @@ impl<'db> KnownClass {
|
||||||
| Self::UnionType
|
| Self::UnionType
|
||||||
| Self::NamedTuple
|
| Self::NamedTuple
|
||||||
| Self::NewType
|
| Self::NewType
|
||||||
| Self::Field => false,
|
| Self::Field
|
||||||
|
| Self::NamedTupleFallback => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2646,6 +2662,7 @@ impl<'db> KnownClass {
|
||||||
}
|
}
|
||||||
"_NotImplementedType" => Self::NotImplementedType,
|
"_NotImplementedType" => Self::NotImplementedType,
|
||||||
"Field" => Self::Field,
|
"Field" => Self::Field,
|
||||||
|
"NamedTupleFallback" => Self::NamedTupleFallback,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2700,7 +2717,8 @@ impl<'db> KnownClass {
|
||||||
| Self::GeneratorType
|
| Self::GeneratorType
|
||||||
| Self::AsyncGeneratorType
|
| Self::AsyncGeneratorType
|
||||||
| Self::WrapperDescriptorType
|
| Self::WrapperDescriptorType
|
||||||
| Self::Field => module == self.canonical_module(db),
|
| Self::Field
|
||||||
|
| Self::NamedTupleFallback => module == self.canonical_module(db),
|
||||||
Self::NoneType => matches!(module, KnownModule::Typeshed | KnownModule::Types),
|
Self::NoneType => matches!(module, KnownModule::Typeshed | KnownModule::Types),
|
||||||
Self::SpecialForm
|
Self::SpecialForm
|
||||||
| Self::TypeVar
|
| Self::TypeVar
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue