diff options
author | Maggie Moss <MaggieMoss@users.noreply.github.com> | 2020-09-09 20:23:24 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-09 20:23:24 (GMT) |
commit | 1b4552c5e8e925f24c15f707050f22c977171125 (patch) | |
tree | 15102b9c349e4cde9904a1eb3ec1cf3099b877bc /Lib/test | |
parent | fa8c9e70104b0aef966a518eb3a80a4881906ae0 (diff) | |
download | cpython-1b4552c5e8e925f24c15f707050f22c977171125.zip cpython-1b4552c5e8e925f24c15f707050f22c977171125.tar.gz cpython-1b4552c5e8e925f24c15f707050f22c977171125.tar.bz2 |
bpo-41428: Implementation for PEP 604 (GH-21515)
See https://www.python.org/dev/peps/pep-0604/ for more information.
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_isinstance.py | 32 | ||||
-rw-r--r-- | Lib/test/test_types.py | 114 | ||||
-rw-r--r-- | Lib/test/test_typing.py | 6 |
3 files changed, 146 insertions, 6 deletions
diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index 53639e9..91e79c2 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -4,6 +4,7 @@ import unittest import sys +import typing @@ -208,6 +209,25 @@ class TestIsInstanceIsSubclass(unittest.TestCase): self.assertEqual(False, isinstance(AbstractChild(), Super)) self.assertEqual(False, isinstance(AbstractChild(), Child)) + def test_isinstance_with_or_union(self): + self.assertTrue(isinstance(Super(), Super | int)) + self.assertFalse(isinstance(None, str | int)) + self.assertTrue(isinstance(3, str | int)) + self.assertTrue(isinstance("", str | int)) + self.assertTrue(isinstance([], typing.List | typing.Tuple)) + self.assertTrue(isinstance(2, typing.List | int)) + self.assertFalse(isinstance(2, typing.List | typing.Tuple)) + self.assertTrue(isinstance(None, int | None)) + self.assertFalse(isinstance(3.14, int | str)) + with self.assertRaises(TypeError): + isinstance(2, list[int]) + with self.assertRaises(TypeError): + isinstance(2, list[int] | int) + with self.assertRaises(TypeError): + isinstance(2, int | str | list[int] | float) + + + def test_subclass_normal(self): # normal classes self.assertEqual(True, issubclass(Super, Super)) @@ -217,6 +237,8 @@ class TestIsInstanceIsSubclass(unittest.TestCase): self.assertEqual(True, issubclass(Child, Child)) self.assertEqual(True, issubclass(Child, Super)) self.assertEqual(False, issubclass(Child, AbstractSuper)) + self.assertTrue(issubclass(typing.List, typing.List|typing.Tuple)) + self.assertFalse(issubclass(int, typing.List|typing.Tuple)) def test_subclass_abstract(self): # abstract classes @@ -251,6 +273,16 @@ class TestIsInstanceIsSubclass(unittest.TestCase): # blown self.assertRaises(RecursionError, blowstack, isinstance, '', str) + def test_subclass_with_union(self): + self.assertTrue(issubclass(int, int | float | int)) + self.assertTrue(issubclass(str, str | Child | str)) + self.assertFalse(issubclass(dict, float|str)) + self.assertFalse(issubclass(object, float|str)) + with self.assertRaises(TypeError): + issubclass(2, Child | Super) + with self.assertRaises(TypeError): + issubclass(int, list[int] | Child) + def test_issubclass_refcount_handling(self): # bpo-39382: abstract_issubclass() didn't hold item reference while # peeking in the bases tuple, in the single inheritance case. diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 49dc5bf..f499fb9 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2,6 +2,7 @@ from test.support import run_with_locale import collections.abc +from collections import namedtuple import inspect import pickle import locale @@ -9,6 +10,12 @@ import sys import types import unittest.mock import weakref +import typing + +class Example: + pass + +class Forward: ... class TypesTests(unittest.TestCase): @@ -598,6 +605,113 @@ class TypesTests(unittest.TestCase): self.assertIsInstance(int.from_bytes, types.BuiltinMethodType) self.assertIsInstance(int.__new__, types.BuiltinMethodType) + def test_or_types_operator(self): + self.assertEqual(int | str, typing.Union[int, str]) + self.assertNotEqual(int | list, typing.Union[int, str]) + self.assertEqual(str | int, typing.Union[int, str]) + self.assertEqual(int | None, typing.Union[int, None]) + self.assertEqual(None | int, typing.Union[int, None]) + self.assertEqual(int | str | list, typing.Union[int, str, list]) + self.assertEqual(int | (str | list), typing.Union[int, str, list]) + self.assertEqual(str | (int | list), typing.Union[int, str, list]) + self.assertEqual(typing.List | typing.Tuple, typing.Union[typing.List, typing.Tuple]) + self.assertEqual(typing.List[int] | typing.Tuple[int], typing.Union[typing.List[int], typing.Tuple[int]]) + self.assertEqual(typing.List[int] | None, typing.Union[typing.List[int], None]) + self.assertEqual(None | typing.List[int], typing.Union[None, typing.List[int]]) + self.assertEqual(str | float | int | complex | int, (int | str) | (float | complex)) + self.assertEqual(typing.Union[str, int, typing.List[int]], str | int | typing.List[int]) + self.assertEqual(int | int, int) + self.assertEqual( + BaseException | + bool | + bytes | + complex | + float | + int | + list | + map | + set, + typing.Union[ + BaseException, + bool, + bytes, + complex, + float, + int, + list, + map, + set, + ]) + with self.assertRaises(TypeError): + int | 3 + with self.assertRaises(TypeError): + 3 | int + with self.assertRaises(TypeError): + Example() | int + with self.assertRaises(TypeError): + (int | str) < typing.Union[str, int] + with self.assertRaises(TypeError): + (int | str) < (int | bool) + with self.assertRaises(TypeError): + (int | str) <= (int | str) + with self.assertRaises(TypeError): + # Check that we don't crash if typing.Union does not have a tuple in __args__ + x = typing.Union[str, int] + x.__args__ = [str, int] + (int | str ) == x + + def test_or_type_operator_with_TypeVar(self): + TV = typing.TypeVar('T') + assert TV | str == typing.Union[TV, str] + assert str | TV == typing.Union[str, TV] + + def test_or_type_operator_with_forward(self): + T = typing.TypeVar('T') + ForwardAfter = T | 'Forward' + ForwardBefore = 'Forward' | T + def forward_after(x: ForwardAfter[int]) -> None: ... + def forward_before(x: ForwardBefore[int]) -> None: ... + assert typing.get_args(typing.get_type_hints(forward_after)['x']) == (int, Forward) + assert typing.get_args(typing.get_type_hints(forward_before)['x']) == (int, Forward) + + def test_or_type_operator_with_Protocol(self): + class Proto(typing.Protocol): + def meth(self) -> int: + ... + assert Proto | str == typing.Union[Proto, str] + + def test_or_type_operator_with_Alias(self): + assert list | str == typing.Union[list, str] + assert typing.List | str == typing.Union[typing.List, str] + + def test_or_type_operator_with_NamedTuple(self): + NT=namedtuple('A', ['B', 'C', 'D']) + assert NT | str == typing.Union[NT,str] + + def test_or_type_operator_with_TypedDict(self): + class Point2D(typing.TypedDict): + x: int + y: int + label: str + assert Point2D | str == typing.Union[Point2D, str] + + def test_or_type_operator_with_NewType(self): + UserId = typing.NewType('UserId', int) + assert UserId | str == typing.Union[UserId, str] + + def test_or_type_operator_with_IO(self): + assert typing.IO | str == typing.Union[typing.IO, str] + + def test_or_type_operator_with_SpecialForm(self): + assert typing.Any | str == typing.Union[typing.Any, str] + assert typing.NoReturn | str == typing.Union[typing.NoReturn, str] + assert typing.Optional[int] | str == typing.Union[typing.Optional[int], str] + assert typing.Optional[int] | str == typing.Union[int, str, None] + assert typing.Union[int, bool] | str == typing.Union[int, bool, str] + + def test_or_type_repr(self): + assert repr(int | None) == "int | None" + assert repr(int | typing.GenericAlias(list, int)) == "int | list[int]" class MappingProxyTests(unittest.TestCase): mappingproxy = types.MappingProxyType diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index b3be991..05140fc 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -245,8 +245,6 @@ class UnionTests(BaseTestCase): with self.assertRaises(TypeError): issubclass(Union, int) with self.assertRaises(TypeError): - issubclass(int, Union[int, str]) - with self.assertRaises(TypeError): issubclass(Union[int, str], int) def test_union_any(self): @@ -347,10 +345,6 @@ class UnionTests(BaseTestCase): with self.assertRaises(TypeError): Union[()] - def test_union_instance_type_error(self): - with self.assertRaises(TypeError): - isinstance(42, Union[int, str]) - def test_no_eval_union(self): u = Union[int, str] def f(x: u): ... |