Skip to content

[1.20 regression] narrowing failure with unrelated boolean #21204

@AA-Turner

Description

@AA-Turner

Bug Report

Mypy 1.20 and master report an incorrect error that seems to be a failure of type narrowing in the following case:

class FancyInteger(int):
    name = 'fancy'

    def __repr__(self):
        return f'{int(self)}!'

    def __str__(self):
        return f'{int(self)}!'


def stringify(value: object) -> str:
    if isinstance(value, (str, int)) or value is None:
        if value.__class__.__str__ == FancyInteger.__str__ and isinstance(value, FancyInteger):
            return f"{value.__class__.__name__}.{value.name}"
    return str(value)

playground link

This passes in MyPy 1.19.1, and is ostensibly correct code -- this is a minimised version, but the original performs similar checks with enum.StrEnum, so not that esoteric.

If the value.__class__.__str__ == FancyInteger.__str__ comparison is removed, or split to a new if statement, the error fails to reproduce.

To Reproduce

https://mypy-play.net/?mypy=latest&python=3.12&gist=a6f8ba95151fa5e0003273b812d8223e

Expected Behavior

No error

Actual Behavior

$ uvx mypy==1.20
bug.py:14: error: Item "str" of "str | int" has no attribute "name"  [union-attr]
bug.py:14: error: Item "int" of "str | int" has no attribute "name"  [union-attr]
Found 2 errors in 1 file (checked 1 source file)
$ uvx mypy==1.19.1
Success: no issues found in 1 source file

Your Environment

  • Mypy version used: 1.20 & 1.19.1
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.12 & 3.14

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-type-narrowingConditional type narrowing / binder

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions