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

  1. Inspect the environment: run with verbose logging and check the resolved search paths; remove any vendored/partial stub override of builtins or object
  2. Retry with a different --python-version to see whether that version's stubs resolve `type` correctly
  3. 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

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


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20). Data as JSON: /api/errors/d4f72c76c98106b9. Report an issue: GitHub.