google / pytype

A static type analyzer for Python code

Home Page:https://google.github.io/pytype

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[PY3.11 | Pytype 2024.02.13] Pattern matching fail when not specifying all enum values

albertocalderari opened this issue · comments

Pattern matching fail when not specifying all enum values:

The match is missing the following cases: Environment.UAT, tenant_api.models.Environment.TEST, tenant_api.models.Environment.PROD, tenant_api.models.Environment.DEV [incomplete-match]

See my simplified code below:

class Environment(Enum):
    DEV = "DEV"
    UAT = "UAT"
    TEST = "TEST"
    PROD = "PROD"

def list_items(
        usecase_id: Optional[str] = Query(default=None),
        environment: Optional[Environment] = Query(default=None),
        asset_id: Optional[str] = Query(default=None)
) -> ListOut:
        match (usecase_id, environment, asset_id):
                    case (None, None, None):
                        out = ...
                    case (uc, None, None):
                        out = ...
                    case (None, e, None) if e:
                        out = ...
                    case (None, None, a) if a:
                        out = ...
                    case (None, e, a) if e and a:
                        out =  ...
                    case (u, e, None) if u and 
                        out = ...
                    case (u, None, a) if u and a:
                        out = ...
                    case (uc, e, a):
                        out = ...
                return out

It clearly can't figure out that all cases of the enum are handled by the variable e.
even adding a "catch all" case doesn't seem to cut it.

            case _:
                raise IncompleteMatchError("One of more case statements are not being handled!")

Thanks for the report. Self-contained repro:

from enum import Enum
from typing import Optional

def Query(default):
  return __any_object__

class Environment(Enum):
    DEV = "DEV"
    UAT = "UAT"
    TEST = "TEST"
    PROD = "PROD"

class ListOut:
  pass

def list_items(
        usecase_id: Optional[str] = Query(default=None),
        environment: Optional[Environment] = Query(default=None),
        asset_id: Optional[str] = Query(default=None)
) -> ListOut:
        match (usecase_id, environment, asset_id):
                    case (None, None, None):
                        out = ListOut()
                    case (uc, None, None):
                        out = ListOut()
                    case (None, e, None) if e:
                        out = ListOut()
                    case (None, None, a) if a:
                        out = ListOut()
                    case (None, e, a) if e and a:
                        out = ListOut()
                    case (u, e, None) if u and e:
                        out = ListOut()
                    case (u, None, a) if u and a:
                        out = ListOut()
                    case (uc, e, a):
                        out = ListOut()
        return out

The issue with the catch-all case is a bug that was fixed in the latest release (version 2024.02.27).

Oh wow, fantastic, lemme give it a go :)