-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
gh-106246: Allow the use of unions as match patterns #118525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
import dataclasses | ||
import enum | ||
import inspect | ||
from re import I | ||
import sys | ||
import unittest | ||
|
||
|
@@ -2886,6 +2887,14 @@ class B(A): ... | |
h = 1 | ||
self.assertEqual(h, 1) | ||
|
||
def test_patma_union_type(self): | ||
IntOrStr = int | str | ||
x = 0 | ||
match x: | ||
case IntOrStr(): | ||
x = 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a test that involves a union that does not match. |
||
self.assertEqual(x, 1) | ||
|
||
|
||
class TestSyntaxErrors(unittest.TestCase): | ||
|
||
|
@@ -3361,6 +3370,31 @@ class A: | |
w = 0 | ||
self.assertIsNone(w) | ||
|
||
def test_union_type_postional_subpattern(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. english is not my mother tongue, but |
||
IntOrStr = int | str | ||
x = 1 | ||
w = None | ||
with self.assertRaises(TypeError): | ||
match x: | ||
case IntOrStr(x): | ||
w = 0 | ||
self.assertEqual(x, 1) | ||
self.assertIsNone(w) | ||
|
||
def test_union_type_keyword_subpattern(self): | ||
@dataclasses.dataclass | ||
class Point2: | ||
x: int | ||
y: int | ||
EitherPoint = Point | Point2 | ||
x = Point(x=1, y=2) | ||
w = None | ||
with self.assertRaises(TypeError): | ||
match x: | ||
case EitherPoint(x=1, y=2): | ||
w = 0 | ||
self.assertIsNone(w) | ||
|
||
|
||
class TestValueErrors(unittest.TestCase): | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Since Python 3.10, it was possible to use unions as the second argument to ``isinstance``. Now, unions can also be used as match patterns. However, no sub-patterns can be used for unions; only the basic ``isinstance`` function is available. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ | |
#include "pycore_sysmodule.h" // _PySys_Audit() | ||
#include "pycore_tuple.h" // _PyTuple_ITEMS() | ||
#include "pycore_typeobject.h" // _PySuper_Lookup() | ||
#include "pycore_unionobject.h" // _PyUnion_Check() | ||
#include "pycore_uop_ids.h" // Uops | ||
#include "pycore_pyerrors.h" | ||
|
||
|
@@ -460,8 +461,8 @@ PyObject* | |
_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, | ||
Py_ssize_t nargs, PyObject *kwargs) | ||
{ | ||
if (!PyType_Check(type)) { | ||
const char *e = "called match pattern must be a class"; | ||
if (!PyType_Check(type) && !_PyUnion_Check(type)) { | ||
const char *e = "called match pattern must be a class or a union"; | ||
_PyErr_Format(tstate, PyExc_TypeError, e); | ||
return NULL; | ||
} | ||
|
@@ -470,6 +471,16 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, | |
if (PyObject_IsInstance(subject, type) <= 0) { | ||
return NULL; | ||
} | ||
// Subpatterns are not supported for union types: | ||
if (_PyUnion_Check(type)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't like the fact that we call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we save the result in a variable? Or would it cleaner to handle unions first? |
||
// Return error if any positional or keyword arguments are given: | ||
if (nargs || PyTuple_GET_SIZE(kwargs)) { | ||
const char *e = "union types do not support sub-patterns"; | ||
_PyErr_Format(tstate, PyExc_TypeError, e); | ||
return NULL; | ||
} | ||
return PyTuple_New(0); | ||
} | ||
// So far so good: | ||
PyObject *seen = PySet_New(NULL); | ||
if (seen == NULL) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accidental?