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.
classA: passclassB: passclassC:
attr: A|B|Nonec=C()
ifc.attrisNone: passelifisinstance(c.attr, A): passelifisinstance(c.attr, B): pass# Optional line - no difference if removedreveal_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
Bug Report
When doing narrowing of a class attribute with a particular type shape
A | B | None, the type of the attribute becomesobjectafter the narrowing condition chain.To Reproduce
The following is the most minimal reproduction I was able to create.
Expected Behavior
Revealed type is
A | B | None.Actual Behavior
Revealed type is
object.I made some additional tests:
pyrightgivesA | B | None(good).x = c.xand then doing the narrowing andreveal_typeonattrgivesA | B | None(good).NonewithA | B | DgivesA | B | D(good). Also if I replaceif isinstance(c.attr, D)withif type(c.attr) is D(good). So theNoneseems essential.attr: A | None, givesA | None(good). So more than one type besides theNoneseems essential.elif->ifgivesA | B | None(good). So theelifseems essential.Your Environment
--strict.mypy.ini(and other config files):