mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-08 12:48:07 +00:00
[ty] Reduce false positives for TypedDict
types (#19354)
This commit is contained in:
parent
f3a27406c9
commit
002f9057db
8 changed files with 34 additions and 11 deletions
|
@ -245,7 +245,7 @@ class D(TypedDict):
|
|||
td = D(x=1, label="a")
|
||||
td["x"] = 0
|
||||
# TODO: should be Literal[0]
|
||||
reveal_type(td["x"]) # revealed: @Todo(TypedDict)
|
||||
reveal_type(td["x"]) # revealed: @Todo(Support for `TypedDict`)
|
||||
|
||||
# error: [unresolved-reference]
|
||||
does["not"]["exist"] = 0
|
||||
|
|
|
@ -10,8 +10,6 @@ class Person(TypedDict):
|
|||
name: str
|
||||
age: int | None
|
||||
|
||||
# TODO: This should not be an error:
|
||||
# error: [invalid-assignment]
|
||||
alice: Person = {"name": "Alice", "age": 30}
|
||||
|
||||
# Alternative syntax
|
||||
|
@ -22,6 +20,6 @@ msg = Message(id=1, content="Hello")
|
|||
# No errors for yet-unsupported features (`closed`):
|
||||
OtherMessage = TypedDict("OtherMessage", {"id": int, "content": str}, closed=True)
|
||||
|
||||
reveal_type(Person.__required_keys__) # revealed: @Todo(TypedDict)
|
||||
reveal_type(Message.__required_keys__) # revealed: @Todo(TypedDict)
|
||||
reveal_type(Person.__required_keys__) # revealed: @Todo(Support for `TypedDict`)
|
||||
reveal_type(Message.__required_keys__) # revealed: @Todo(Support for `TypedDict`)
|
||||
```
|
||||
|
|
|
@ -5880,6 +5880,9 @@ pub enum DynamicType {
|
|||
/// A special Todo-variant for type aliases declared using `typing.TypeAlias`.
|
||||
/// A temporary variant to detect and special-case the handling of these aliases in autocomplete suggestions.
|
||||
TodoTypeAlias,
|
||||
/// A special Todo-variant for classes inheriting from `TypedDict`.
|
||||
/// A temporary variant to avoid false positives while we wait for full support.
|
||||
TodoTypedDict,
|
||||
}
|
||||
|
||||
impl DynamicType {
|
||||
|
@ -5911,6 +5914,13 @@ impl std::fmt::Display for DynamicType {
|
|||
f.write_str("@Todo")
|
||||
}
|
||||
}
|
||||
DynamicType::TodoTypedDict => {
|
||||
if cfg!(debug_assertions) {
|
||||
f.write_str("@Todo(Support for `TypedDict`)")
|
||||
} else {
|
||||
f.write_str("@Todo")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -985,7 +985,7 @@ impl<'db> Bindings<'db> {
|
|||
},
|
||||
|
||||
Type::SpecialForm(SpecialFormType::TypedDict) => {
|
||||
overload.set_return_type(todo_type!("TypedDict"));
|
||||
overload.set_return_type(todo_type!("Support for `TypedDict`"));
|
||||
}
|
||||
|
||||
// Not a special case
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signatu
|
|||
use crate::types::tuple::TupleType;
|
||||
use crate::types::{
|
||||
BareTypeAliasType, Binding, BoundSuperError, BoundSuperType, CallableType, DataclassParams,
|
||||
KnownInstanceType, TypeAliasType, TypeMapping, TypeRelation, TypeTransformer,
|
||||
DynamicType, KnownInstanceType, TypeAliasType, TypeMapping, TypeRelation, TypeTransformer,
|
||||
TypeVarBoundOrConstraints, TypeVarInstance, TypeVarKind, infer_definition_types,
|
||||
};
|
||||
use crate::{
|
||||
|
@ -415,6 +415,15 @@ impl<'db> ClassType<'db> {
|
|||
other: Self,
|
||||
relation: TypeRelation,
|
||||
) -> bool {
|
||||
// TODO: remove this branch once we have proper support for TypedDicts.
|
||||
if self.is_known(db, KnownClass::Dict)
|
||||
&& other
|
||||
.iter_mro(db)
|
||||
.any(|b| matches!(b, ClassBase::Dynamic(DynamicType::TodoTypedDict)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
self.iter_mro(db).any(|base| {
|
||||
match base {
|
||||
ClassBase::Dynamic(_) => match relation {
|
||||
|
|
|
@ -51,7 +51,8 @@ impl<'db> ClassBase<'db> {
|
|||
ClassBase::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoTypeAlias,
|
||||
| DynamicType::TodoTypeAlias
|
||||
| DynamicType::TodoTypedDict,
|
||||
) => "@Todo",
|
||||
ClassBase::Protocol => "Protocol",
|
||||
ClassBase::Generic => "Generic",
|
||||
|
@ -229,7 +230,7 @@ impl<'db> ClassBase<'db> {
|
|||
SpecialFormType::OrderedDict => {
|
||||
Self::try_from_type(db, KnownClass::OrderedDict.to_class_literal(db))
|
||||
}
|
||||
SpecialFormType::TypedDict => Self::try_from_type(db, todo_type!("TypedDict")),
|
||||
SpecialFormType::TypedDict => Some(Self::Dynamic(DynamicType::TodoTypedDict)),
|
||||
SpecialFormType::Callable => {
|
||||
Self::try_from_type(db, todo_type!("Support for Callable as a base class"))
|
||||
}
|
||||
|
|
|
@ -6508,7 +6508,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoTypeAlias,
|
||||
| DynamicType::TodoTypeAlias
|
||||
| DynamicType::TodoTypedDict,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
|
@ -6518,7 +6519,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
todo @ Type::Dynamic(
|
||||
DynamicType::Todo(_)
|
||||
| DynamicType::TodoPEP695ParamSpec
|
||||
| DynamicType::TodoTypeAlias,
|
||||
| DynamicType::TodoTypeAlias
|
||||
| DynamicType::TodoTypedDict,
|
||||
),
|
||||
_,
|
||||
) => Some(todo),
|
||||
|
|
|
@ -253,6 +253,9 @@ fn dynamic_elements_ordering(left: DynamicType, right: DynamicType) -> Ordering
|
|||
|
||||
(DynamicType::TodoTypeAlias, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoTypeAlias) => Ordering::Greater,
|
||||
|
||||
(DynamicType::TodoTypedDict, _) => Ordering::Less,
|
||||
(_, DynamicType::TodoTypedDict) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue