Skip to content

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

Closed
@bluetech

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

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