aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_typing.py
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2025-03-04 11:44:19 -0800
committerGitHub <noreply@github.com>2025-03-04 11:44:19 -0800
commitdc6d66f44c0a25b69dfec7e4ffc4a6fa5e4feada (patch)
tree045fed4b7965d56ea45c009dad6dddb42d7be8b0 /Lib/test/test_typing.py
parente091520fdbcfe406e5fdcf66b7864b2b34a6726b (diff)
downloadcpython-dc6d66f44c0a25b69dfec7e4ffc4a6fa5e4feada.tar.gz
cpython-dc6d66f44c0a25b69dfec7e4ffc4a6fa5e4feada.zip
gh-105499: Merge typing.Union and types.UnionType (#105511)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Ken Jin <kenjin@python.org> Co-authored-by: Carl Meyer <carl@oddbird.net>
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r--Lib/test/test_typing.py96
1 files changed, 58 insertions, 38 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 591fb860eee..e88c811bfca 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -502,7 +502,7 @@ class TypeVarTests(BaseTestCase):
def test_bound_errors(self):
with self.assertRaises(TypeError):
- TypeVar('X', bound=Union)
+ TypeVar('X', bound=Optional)
with self.assertRaises(TypeError):
TypeVar('X', str, float, bound=Employee)
with self.assertRaisesRegex(TypeError,
@@ -542,7 +542,7 @@ class TypeVarTests(BaseTestCase):
def test_bad_var_substitution(self):
T = TypeVar('T')
bad_args = (
- (), (int, str), Union,
+ (), (int, str), Optional,
Generic, Generic[T], Protocol, Protocol[T],
Final, Final[int], ClassVar, ClassVar[int],
)
@@ -2044,10 +2044,6 @@ class UnionTests(BaseTestCase):
def test_union_issubclass_type_error(self):
with self.assertRaises(TypeError):
- issubclass(int, Union)
- with self.assertRaises(TypeError):
- issubclass(Union, int)
- with self.assertRaises(TypeError):
issubclass(Union[int, str], int)
with self.assertRaises(TypeError):
issubclass(int, Union[str, list[int]])
@@ -2121,41 +2117,40 @@ class UnionTests(BaseTestCase):
self.assertEqual(Union[A, B].__args__, (A, B))
union1 = Union[A, B]
- with self.assertRaises(TypeError):
+ with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union1)
union2 = Union[int, B]
- with self.assertRaises(TypeError):
+ with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union2)
union3 = Union[A, int]
- with self.assertRaises(TypeError):
+ with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union3)
def test_repr(self):
- self.assertEqual(repr(Union), 'typing.Union')
u = Union[Employee, int]
- self.assertEqual(repr(u), 'typing.Union[%s.Employee, int]' % __name__)
+ self.assertEqual(repr(u), f'{__name__}.Employee | int')
u = Union[int, Employee]
- self.assertEqual(repr(u), 'typing.Union[int, %s.Employee]' % __name__)
+ self.assertEqual(repr(u), f'int | {__name__}.Employee')
T = TypeVar('T')
u = Union[T, int][int]
self.assertEqual(repr(u), repr(int))
u = Union[List[int], int]
- self.assertEqual(repr(u), 'typing.Union[typing.List[int], int]')
+ self.assertEqual(repr(u), 'typing.List[int] | int')
u = Union[list[int], dict[str, float]]
- self.assertEqual(repr(u), 'typing.Union[list[int], dict[str, float]]')
+ self.assertEqual(repr(u), 'list[int] | dict[str, float]')
u = Union[int | float]
- self.assertEqual(repr(u), 'typing.Union[int, float]')
+ self.assertEqual(repr(u), 'int | float')
u = Union[None, str]
- self.assertEqual(repr(u), 'typing.Optional[str]')
+ self.assertEqual(repr(u), 'None | str')
u = Union[str, None]
- self.assertEqual(repr(u), 'typing.Optional[str]')
+ self.assertEqual(repr(u), 'str | None')
u = Union[None, str, int]
- self.assertEqual(repr(u), 'typing.Union[NoneType, str, int]')
+ self.assertEqual(repr(u), 'None | str | int')
u = Optional[str]
- self.assertEqual(repr(u), 'typing.Optional[str]')
+ self.assertEqual(repr(u), 'str | None')
def test_dir(self):
dir_items = set(dir(Union[str, int]))
@@ -2167,14 +2162,11 @@ class UnionTests(BaseTestCase):
def test_cannot_subclass(self):
with self.assertRaisesRegex(TypeError,
- r'Cannot subclass typing\.Union'):
+ r"type 'typing\.Union' is not an acceptable base type"):
class C(Union):
pass
- with self.assertRaisesRegex(TypeError, CANNOT_SUBCLASS_TYPE):
- class D(type(Union)):
- pass
with self.assertRaisesRegex(TypeError,
- r'Cannot subclass typing\.Union\[int, str\]'):
+ r'Cannot subclass int \| str'):
class E(Union[int, str]):
pass
@@ -2220,7 +2212,7 @@ class UnionTests(BaseTestCase):
def test_function_repr_union(self):
def fun() -> int: ...
- self.assertEqual(repr(Union[fun, int]), 'typing.Union[fun, int]')
+ self.assertEqual(repr(Union[fun, int]), f'{__name__}.{fun.__qualname__} | int')
def test_union_str_pattern(self):
# Shouldn't crash; see http://bugs.python.org/issue25390
@@ -4895,11 +4887,11 @@ class GenericTests(BaseTestCase):
def test_extended_generic_rules_repr(self):
T = TypeVar('T')
self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''),
- 'Union[Tuple, Callable]')
+ 'Tuple | Callable')
self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''),
- 'Union[Tuple, Tuple[int]]')
+ 'Tuple | Tuple[int]')
self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''),
- 'Callable[..., Optional[int]]')
+ 'Callable[..., int | None]')
self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''),
'Callable[[], List[int]]')
@@ -5079,9 +5071,9 @@ class GenericTests(BaseTestCase):
with self.assertRaises(TypeError):
issubclass(Tuple[int, ...], typing.Iterable)
- def test_fail_with_bare_union(self):
+ def test_fail_with_special_forms(self):
with self.assertRaises(TypeError):
- List[Union]
+ List[Final]
with self.assertRaises(TypeError):
Tuple[Optional]
with self.assertRaises(TypeError):
@@ -5623,8 +5615,6 @@ class GenericTests(BaseTestCase):
for obj in (
ClassVar[int],
Final[int],
- Union[int, float],
- Optional[int],
Literal[1, 2],
Concatenate[int, ParamSpec("P")],
TypeGuard[int],
@@ -5656,7 +5646,7 @@ class GenericTests(BaseTestCase):
__parameters__ = (T,)
# Bare classes should be skipped
for a in (List, list):
- for b in (A, int, TypeVar, TypeVarTuple, ParamSpec, types.GenericAlias, types.UnionType):
+ for b in (A, int, TypeVar, TypeVarTuple, ParamSpec, types.GenericAlias, Union):
with self.subTest(generic=a, sub=b):
with self.assertRaisesRegex(TypeError, '.* is not a generic class'):
a[b][str]
@@ -5675,7 +5665,7 @@ class GenericTests(BaseTestCase):
for s in (int, G, A, List, list,
TypeVar, TypeVarTuple, ParamSpec,
- types.GenericAlias, types.UnionType):
+ types.GenericAlias, Union):
for t in Tuple, tuple:
with self.subTest(tuple=t, sub=s):
@@ -7176,7 +7166,7 @@ class GetUtilitiesTestCase(TestCase):
self.assertIs(get_origin(Callable), collections.abc.Callable)
self.assertIs(get_origin(list[int]), list)
self.assertIs(get_origin(list), None)
- self.assertIs(get_origin(list | str), types.UnionType)
+ self.assertIs(get_origin(list | str), Union)
self.assertIs(get_origin(P.args), P)
self.assertIs(get_origin(P.kwargs), P)
self.assertIs(get_origin(Required[int]), Required)
@@ -10434,7 +10424,6 @@ class SpecialAttrsTests(BaseTestCase):
typing.TypeGuard: 'TypeGuard',
typing.TypeIs: 'TypeIs',
typing.TypeVar: 'TypeVar',
- typing.Union: 'Union',
typing.Self: 'Self',
# Subscripted special forms
typing.Annotated[Any, "Annotation"]: 'Annotated',
@@ -10445,7 +10434,7 @@ class SpecialAttrsTests(BaseTestCase):
typing.Literal[Any]: 'Literal',
typing.Literal[1, 2]: 'Literal',
typing.Literal[True, 2]: 'Literal',
- typing.Optional[Any]: 'Optional',
+ typing.Optional[Any]: 'Union',
typing.TypeGuard[Any]: 'TypeGuard',
typing.TypeIs[Any]: 'TypeIs',
typing.Union[Any]: 'Any',
@@ -10464,7 +10453,10 @@ class SpecialAttrsTests(BaseTestCase):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(cls, proto)
loaded = pickle.loads(s)
- self.assertIs(cls, loaded)
+ if isinstance(cls, Union):
+ self.assertEqual(cls, loaded)
+ else:
+ self.assertIs(cls, loaded)
TypeName = typing.NewType('SpecialAttrsTests.TypeName', Any)
@@ -10739,6 +10731,34 @@ class TypeIterationTests(BaseTestCase):
self.assertNotIsInstance(type_to_test, collections.abc.Iterable)
+class UnionGenericAliasTests(BaseTestCase):
+ def test_constructor(self):
+ # Used e.g. in typer, pydantic
+ with self.assertWarns(DeprecationWarning):
+ inst = typing._UnionGenericAlias(typing.Union, (int, str))
+ self.assertEqual(inst, int | str)
+ with self.assertWarns(DeprecationWarning):
+ # name is accepted but ignored
+ inst = typing._UnionGenericAlias(typing.Union, (int, None), name="Optional")
+ self.assertEqual(inst, int | None)
+
+ def test_isinstance(self):
+ # Used e.g. in pydantic
+ with self.assertWarns(DeprecationWarning):
+ self.assertTrue(isinstance(Union[int, str], typing._UnionGenericAlias))
+ with self.assertWarns(DeprecationWarning):
+ self.assertFalse(isinstance(int, typing._UnionGenericAlias))
+
+ def test_eq(self):
+ # type(t) == _UnionGenericAlias is used in vyos
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(Union, typing._UnionGenericAlias)
+ with self.assertWarns(DeprecationWarning):
+ self.assertEqual(typing._UnionGenericAlias, typing._UnionGenericAlias)
+ with self.assertWarns(DeprecationWarning):
+ self.assertNotEqual(int, typing._UnionGenericAlias)
+
+
def load_tests(loader, tests, pattern):
import doctest
tests.addTests(doctest.DocTestSuite(typing))