Skip to content

Type narrowing on object attribute with match statement doesn't apply #14911

Open

Description

@AiroPi

The bug
It seems that doing a "type checking" with the object UI in pattern matching seems to not work properly.
Attribute match is not considered.

Code

class Test:
    def __init__(self, a: int | str):
        self.a: int | str = a

test = Test(5)

match test:
    case Test(a = int()):
        print(test.a + 3)
    case Test(a = str()):
        print(test.a + "3")

Expected behavior
By doing a match with Test(a = int()), python will check test is of type Test AND test.a is of type int.
But mypy "only assert" that test if of type Test. It keep the type int | str for test.a.

Reproduce :
On mypy-playground :
https://mypy-play.net/?mypy=latest&python=3.11&gist=6f05124abd1ef68032d59651a7d5c6c3

Activity

  1. erictraut commented on Mar 16, 2023

    @erictraut

    For reference: microsoft/pyright#4775

  2. added and removed
    bugmypy got something wrong
    on Mar 16, 2023
  3. cdce8p commented on Aug 27, 2025

    @cdce8p
    Collaborator

    This should be fixed with #19736.

  4. tjkuson commented on Sep 24, 2025

    @tjkuson

    Would it be possible to support narrowing across cases like this as part of this issue, or would it be a separate issue/not possible? I searched the issue tracker and this issue seemed to be the closest to what I'm looking for.

    class Test:
        def __init__(self, a: int | str):
            self.a: int | str = a
    
    
    test = Test(5)
    
    match test:
        case Test(a=int()):
            print(test.a + 3)
        case Test(a=str()):
            print(test.a + "3")
        case Test(a=a):
            assert_never(test.a)

    This works if I go back to using isinstance with ordinary if statements, but that would mean being unable to use pattern matching features.

  5. cdce8p commented on Sep 24, 2025

    @cdce8p
    Collaborator

    Would it be possible to support narrowing across cases like this as part of this issue, or would it be a separate issue/not possible? I searched the issue tracker and this issue seemed to be the closest to what I'm looking for.

    @tjkuson With #19736 it would almost work. Just assert_never would still throw an error as I haven't implemented the "else" narrowing. Similarly to how it isn't implemented for just the bound variable yet.

        ...
        case Test(a=a):
            reveal_type(a)  # int | str
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions