Skip to content

Attribute of type A | B | None becomes object after narrowing checks #12009

Description

@bluetech

Bug Report

When doing narrowing of a class attribute with a particular type shape A | B | None, the type of the attribute becomes object after the narrowing condition chain.

To Reproduce

The following is the most minimal reproduction I was able to create.

class A: pass
class B: pass
class C:
    attr: A | B | None

c = C()
if c.attr is None: pass
elif isinstance(c.attr, A): pass
elif isinstance(c.attr, B): pass  # Optional line - no difference if removed
reveal_type(c.attr)

Expected Behavior

Revealed type is A | B | None.

Actual Behavior

Revealed type is object.

I made some additional tests:

  • pyright gives A | B | None (good).
  • Doing x = c.x and then doing the narrowing and reveal_type on attr gives A | B | None (good).
  • Replacing the None with A | B | D gives A | B | D (good). Also if I replace if isinstance(c.attr, D) with if type(c.attr) is D (good). So the None seems essential.
  • With just attr: A | None, gives A | None (good). So more than one type besides the None seems essential.
  • Changing the elif -> if gives A | B | None (good). So the elif seems essential.

Your Environment

  • Mypy version used: master, 0.931, 0.900 (didn't try earlier versions).
  • Mypy command-line flags: --strict.
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.9, 3.10
  • Operating system and version: Arch Linux

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-join-v-unionUsing join vs. using unions

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions