Skip to content

Improve diagnostics in cases where we infer object due to possibility of subclassing #2215

@ooopus

Description

@ooopus

Summary

Summary

When using the common guard pattern:

if hasattr(obj, "attr") and obj.attr:
    ...

ty incorrectly infers obj.attr as ~AlwaysFalsy, producing a false-positive

error[unresolved-attribute] when accessing attributes on obj.attr.

This code runs correctly at runtime; the issue appears to be in ty's flow-sensitive narrowing.

Environment

  • OS: Windows 11

  • Python: 3.13.9

  • ty: 0.0.7 (cf82a04 2025-12-24)

Command

ty check test_ty_always_falsy.py

(No special pyproject.toml settings; default config.)

Reproduction

from __future__ import annotations

class Editor:
    def __init__(self) -> None:
        self.note: Note | None = Note()

class Note:
    def __init__(self) -> None:
        self.fields: list[str] = ["field1", "field2"]

class WebView:
    pass

class EditorWebView:
    def __init__(self) -> None:
        self.editor: Editor | None = Editor()

def test(webview: WebView | EditorWebView) -> list[str] | None:
    if hasattr(webview, "editor") and webview.editor:
        reveal_type(webview)
        reveal_type(webview.editor)

        note = webview.editor.note # ty: error[unresolved-attribute]

        if note:
            return note.fields

    return None

Expected Behavior

Inside:

if hasattr(webview, "editor") and webview.editor:

webview.editor should be narrowed to a truthy Editor type, so

webview.editor.note should be valid.

Actual Behavior

ty reports a false positive similar to:

error[unresolved-attribute]: Object of type `~AlwaysFalsy` has no attribute `note`

Workarounds

Both of the following avoid the false positive:

  • isinstance()-based narrowing

  • getattr(webview, "editor", None) + truthiness check

Version

ty 0.0.7 (cf82a04 2025-12-24)

Metadata

Metadata

Assignees

No one assigned

    Labels

    diagnosticsRelated to reporting of diagnostics.narrowingrelated to flow-sensitive type narrowing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions