astral-sh/ruff · error
`find_name_in_mro` should return `Some` for a class literal
Error message
`find_name_in_mro` should return `Some` for a class literal
What it means
For `type[Any]`-style SubclassOf-dynamic values, attribute lookup first checks `type`'s own class-level members so data descriptors like `__mro__` and `__bases__` resolve to their real types instead of collapsing to Any. find_name_in_mro on a class literal is guaranteed to return Some (a place, possibly undefined) because the MRO terminates in object; the expect enforces that guarantee for the class literal of KnownClass::Type.
Source
Thrown at crates/ty_python_semantic/src/types.rs:3647
// ```pycon
// >>> class Foo:
// ... def bar(self): pass
// >>> f = Foo()
// >>> f.bar is f.bar
// False
// ```
false
}
Type::KnownBoundMethod(_) => {
// Just a special case of `BoundMethod` really
// (this variant represents `f.__get__`, where `f` is any function)
false
}
Type::DataclassDecorator(_) | Type::DataclassTransformer(_) => false,
Type::NominalInstance(instance) => instance.is_singleton(db),
Type::PropertyInstance(_) | Type::SlotDescriptor(_) => false,
Type::Union(..) => {
// A single-element union, where the sole element was a singleton, would itself
// be a singleton type. However, unions with length < 2 should never appear in
// our model due to [`UnionBuilder::build`].
false
}
Type::Intersection(intersection) => intersection
.enum_complement(db, env)
.is_some_and(|complement| complement.is_singleton(db)),
Type::EnumComplement(complement) => complement.is_singleton(db),
Type::AlwaysTruthy | Type::AlwaysFalsy => false,
Type::TypeIs(type_is) => type_is.is_bound(db),
Type::TypeGuard(type_guard) => type_guard.is_bound(db),
Type::TypeForm(_) => false,
Type::TypedDict(_) => false,
Type::TypeAlias(alias) => alias.value_type(db).is_singleton(db, env),
Type::NewTypeInstance(newtype) => newtype.concrete_base_type(db).is_singleton(db, env),
}
}
View on GitHub (pinned to 15f3fe6b15)
Solutions
- Inspect the environment: run with verbose logging and check the resolved search paths; remove any vendored/partial stub override of builtins or object
- Retry with a different --python-version to see whether that version's stubs resolve `type` correctly
- If the environment looks standard, file a ty issue with the search-path setup and the member name being looked up
Defensive patterns
Strategy: validation
Validate before calling
// Before checking, confirm the standard environment resolves builtins: // (shell) ty check --verbose my_file.py 2>&1 | grep -i 'search path' // Ensure `builtins`/`object` resolve from the real typeshed before trusting type[Any] member access.
Prevention
- Do not vendor partial stubs over builtins/object in python search paths
- Verify search-path configuration (`ty check --verbose`) when results look nonsensical
- Pin a supported --python-version whose stub set is complete
When it happens
Trigger: Member access on a `type[Any]`/`type[Unknown]` value (e.g., `t.__mro__` where `t: type[Any]`) when lookup on the `type` class literal returns None - i.e., the `type`/`object` MRO could not be walked in the current environment.
Common situations: Broken, partial, or hidden typeshed: custom search paths or vendored stubs that override builtins and drop `object` from the MRO; unsupported Python versions whose stub set fails to resolve `type`.
Related errors
- The meta-type of an instance-like type should always have an
- Will return Some() when called on class literal
- Calling `find_name_in_mro` on dynamic type should return `So
- Expected a Type::Dynamic variant
- matched `Type::Divergent` above
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20).
Data as JSON: /api/errors/d4f72c76c98106b9.
Report an issue: GitHub.