Repository navigation
Restrictions on class patterns (match statement) are too strict / (possible cause: too eager to alias types) #17133
Description
Bug Report
Considering the following piece of code:
NestedLines = tuple
def print_lines(ls: NestedLines, indent: int = 0) -> None:
for line in ls:
match line:
case NestedLines():
print_lines(line, indent+4)
case _:
print(" "*indent + str(line))
print_lines((1, [2,3,4], (5, [6,7]), 8))mypy --strict complains at the case NestedLines() saying "Class pattern class must not be a type alias with type parameters". However, given that a class pattern has to be a type object (and not a genericalias object), there's no way to resolve this that makes both the runtime and the typechecker happy.
For example, if you define
from typing import TypeAlias
NestedLines: TypeAlias = tuple["NestedLines | object"]Running this will result in a TypeError: called match pattern must be a class.
Expected Behavior
Program should both typecheck AND print the following when run:
1
[2, 3, 4]
5
[6, 7]
8
Not sure what's the best solution... pyright is happy about this example, so perhaps some checks need to be removed/relaxed. In the (more complicated real usecase) code where I came accross this, the x = tuple was not intended as an alias, but there's no way to tell mypy "this is just an assignment", which I think would cmake more explicit that its usage in the match statement is not related to aliases.
The documentation says "Because the distinction between an unannotated variable and a type alias is implicit, ambiguous or incorrect type alias declarations default to defining a normal variable instead of a type alias."; I would say this case is ambiguous/incorrect as a typealias, so it should be considered a regular variable definition. But I even tried NestedLines: type = tuple, and it is still taken as an alias.
A possible desired behaviour would be: if the value used in a match statement is an "ambiguous" typealias (not defined with a TypeAlias/TypeStatement), and has actually been set to a type object (not a generic alias like tuple[Any]), do not emit an error
Actual Behavior
$ python3.12 -m mypy --strict example.py
example.py:1: error: Missing type parameters for generic type "tuple" [type-arg]
example.py:6: error: Class pattern class must not be a type alias with type parameters [misc]
Found 2 errors in 1 file (checked 1 source file)
If I change it to a typealias
$ python3.12 example.py
Traceback (most recent call last):
File "/home/dmoissetdees/training-materials/unix/labs/whale/template/example.py", line 12, in <module>
print_lines((1, [2,3,4], (5, [6,7]), 8))
File "/home/dmoissetdees/training-materials/unix/labs/whale/template/example.py", line 7, in print_lines
case NestedLines():
^^^^^^^^^^^^^
TypeError: called match pattern must be a class
And mypy still complains (in this case I think correctly):
example.py:7: error: Class pattern class must not be a type alias with type parameters [misc]
Your Environment
- Mypy version used: mypy 1.8.0 (compiled: yes)
- Mypy command-line flags: --strict
- Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.12.2
Activity
dmoisset commentedon Apr 17, 2024
As an aditional examples where the check on match statements is overly strict:
Result:
That looks like something that would clearly be allowed (even the error message "expected a type, found a type instead", sounds confusing). pyright accepts this one too.
Better match narrowing for type objects (#20872)
Model tuple type aliases better (#20967)