Skip to content

False positive when using mypy and assuming PEP 724 is covered #20097

@SMoraisAnsys

Description

@SMoraisAnsys

Hey guys, first of all thanks for this wonderful tool !

My report might not be considered a bug if you consider that PEP 724 isn't handled by mypy. If that's the case, let me know and I can open a new ticket dedicated to adding PEP 724. This being said, I assumed that PEP 724 was covered by mypy but it doesn't seem to be the case. Here is a dummy reproducer

from dataclasses import dataclass
from typing import TypeGuard, Union

@dataclass
class ThermalModel:
    conductivity: float

@dataclass
class MechanicalModel:
    stiffness: float

Model = Union[ThermalModel, MechanicalModel]

def is_valid_thermal_model(obj: Model) -> TypeGuard[ThermalModel]:
    return hasattr(obj, "conductivity") and obj.conductivity >= 0

def run_simulation(model: Model):
    if is_valid_thermal_model(model):
        model.conductivity *= 2.0
    else:
        model.stiffness *= 1.1

Since is_valid_thermal_model is False, I would expect the type to be narrowed to MechanicalModel when working in the else statement. However, I get the following error error: Item "ThermalModel" of "ThermalModel | MechanicalModel" has no attribute "stiffness" [union-attr]. My understanding here is that PEP 647 is covered but not PEP 724.

Note that if I apply another if statement with TypeGuard instead of the else statement, it works fine. Here would be the changes

def is_valid_mechanical_model(obj: Model) -> TypeGuard[MechanicalModel]:
    return hasattr(obj, "stiffness") and obj.stiffness >= 0

def run_simulation(model: Model):
    if is_valid_thermal_model(model):
        model.conductivity *= 2.0
    elif is_valid_mechanical_model(model):
        model.stiffness *= 1.1

Expected Behavior

I wouldn't expect any error with the previous snippet.

Actual Behavior

The error obtained is error: Item "ThermalModel" of "ThermalModel | MechanicalModel" has no attribute "stiffness" [union-attr].

Your Environment

  • Mypy version used: mypy 1.18.2 (compiled: yes)
  • Mypy command-line flags: mypy myfile_.py
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.10

Note that the version used is the latest version available on PyPI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions