Skip to content

Incorrect union narrowing in chained conditionals #12208

Closed

Description

@JaviFuentes94

Bug Report
Hey there!

I have recently encountered this case:

class Animal:
    name: Literal["animal"]
    n_legs: int

class Plant:
    name: Literal["plant"]

def get_n_legs(item: Union[Animal, Plant]):
    if item.name == "animal" and item.n_legs > 6:    # This fails mypy with union-attr for n_legs in Plant
        return "Many" 

Expected Behavior

Mypy should be able to narrow down chained conditionals as presented. It seems that pylance has no problems with it, for example.

Activity

  1. erictraut commented on Feb 19, 2022

    @erictraut

    Which version of mypy are you using? I'm not able to repro this error with the latest published version.

  2. JelleZijlstra commented on Mar 19, 2022

    @JelleZijlstra
    Member
  3. JaviFuentes94 commented on Mar 22, 2022

    @JaviFuentes94
    Author

    Hello again, sorry I made a mistake while testing my minimal example. The problem comes with a Literal that is an enum field:

    from typing_extensions import Literal
    from typing import Union, Dict
    import enum
    
    class Types(str, enum.Enum):
        animal = "animal"
        plant = "plant"
    
    
    class Animal:
        name: Literal[Types.animal]
        n_legs: int
    
    class Plant:
        name: Literal[Types.plant]
    
    def get_n_legs(item: Union[Animal, Plant]):
        if item.name == Types.animal and item.n_legs > 6:   
            return "Many" 
    

    Here you can reproduce it: https://mypy-play.net/?mypy=latest&python=3.10&gist=dfcdd1d12e53c80d0e58ba5ed8750ccf

  4. mikaelarguedas commented on Mar 4, 2023

    @mikaelarguedas

    Hey there,

    I believe I ran into another occurrence of this. It looks like the type has not been narrowed by the first if statement.
    Happens with latest mypy on Python3.8.
    Trying it on https://mypy-play.net looks to happen on more recent versions of Python as well.

    Reproducible example: https://mypy-play.net/?mypy=latest&python=3.11&flags=verbose&gist=07d004a22a748059c834ff42d690c2ed

    from typing import Optional, Union
    
    
    class RangeVals:
        """Hold a parameter value range."""
    
        def __init__(
            self,
            min_val: Union[int, float],
            max_val: Union[int, float],
        ) -> None:
            self.min_val = min_val
            self.max_val = max_val
    
    
    def functionn(default_val: Union[str, float, int], rangeval: RangeVals):
        if type(default_val) != type(rangeval.min_val):
            raise TypeError("foo")
        if default_val < rangeval.min_val:
            raise ValueError("bar")
    
    
    functionn("abc", RangeVals(min_val=3, max_val=10))
  5. erictraut commented on Aug 13, 2023

    @erictraut

    The original bug in this issue appears to have been fixed in mypy 1.4.

    @mikaelarguedas, your issue is unrelated to OP's bug. The behavior in your sample is expected behavior in mypy.

  6. hauntsaninja commented on Aug 13, 2023

    @hauntsaninja
    Collaborator

    I fixed this in #11521

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-type-narrowingConditional type narrowing / binder

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions