Update types module to CPython 3.10.0

This commit is contained in:
Moreal committed 2021-12-05 17:06:56 +09:00
1 parent 1b227f8f89
commit 7da94d878c
2 files changed
+398 -6

No files matched your search

+385 -1
View File
@@ -1,7 +1,10 @@
# Python test set -- part 6, built-in types
from test.support import run_with_locale
from test.support import run_with_locale, cpython_only
import collections.abc
from collections import namedtuple
import copy
import gc
import inspect
import pickle
import locale
@@ -9,6 +12,20 @@ import sys
import types
import unittest.mock
import weakref
import typing
T = typing.TypeVar("T")
class Example:
pass
class Forward: ...
def clear_typing_caches():
for f in typing._cleanups:
f()
class TypesTests(unittest.TestCase):
@@ -608,6 +625,355 @@ class TypesTests(unittest.TestCase):
self.assertIsInstance(int.from_bytes, types.BuiltinMethodType)
self.assertIsInstance(int.__new__, types.BuiltinMethodType)
def test_ellipsis_type(self):
self.assertIsInstance(Ellipsis, types.EllipsisType)
def test_notimplemented_type(self):
self.assertIsInstance(NotImplemented, types.NotImplementedType)
def test_none_type(self):
self.assertIsInstance(None, types.NoneType)
class UnionTests(unittest.TestCase):
# TODO: RUSTPYTHON
@unittest.expectedFailure
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 | type(None), int | None)
self.assertEqual(type(None) | int, None | int)
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.assertIs(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
x = int | str
self.assertEqual(x, int | str)
self.assertEqual(x, str | int)
self.assertNotEqual(x, {}) # should not raise exception
with self.assertRaises(TypeError):
x < x
with self.assertRaises(TypeError):
x <= x
y = typing.Union[str, int]
with self.assertRaises(TypeError):
x < y
y = int | bool
with self.assertRaises(TypeError):
x < y
# Check that we don't crash if typing.Union does not have a tuple in __args__
y = typing.Union[str, int]
y.__args__ = [str, int]
self.assertEqual(x, y)
def test_hash(self):
self.assertEqual(hash(int | str), hash(str | int))
self.assertEqual(hash(int | str), hash(typing.Union[int, str]))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_instancecheck(self):
x = int | str
self.assertIsInstance(1, x)
self.assertIsInstance(True, x)
self.assertIsInstance('a', x)
self.assertNotIsInstance(None, x)
self.assertTrue(issubclass(int, x))
self.assertTrue(issubclass(bool, x))
self.assertTrue(issubclass(str, x))
self.assertFalse(issubclass(type(None), x))
x = int | None
self.assertIsInstance(None, x)
self.assertTrue(issubclass(type(None), x))
x = int | collections.abc.Mapping
self.assertIsInstance({}, x)
self.assertTrue(issubclass(dict, x))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_bad_instancecheck(self):
class BadMeta(type):
def __instancecheck__(cls, inst):
1/0
x = int | BadMeta('A', (), {})
self.assertTrue(isinstance(1, x))
self.assertRaises(ZeroDivisionError, isinstance, [], x)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_bad_subclasscheck(self):
class BadMeta(type):
def __subclasscheck__(cls, sub):
1/0
x = int | BadMeta('A', (), {})
self.assertTrue(issubclass(int, x))
self.assertRaises(ZeroDivisionError, issubclass, list, 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]
self.assertIs((int | TV)[int], int)
self.assertIs((TV | int)[int], int)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_union_args(self):
def check(arg, expected):
clear_typing_caches()
self.assertEqual(arg.__args__, expected)
check(int | str, (int, str))
check((int | str) | list, (int, str, list))
check(int | (str | list), (int, str, list))
check((int | str) | int, (int, str))
check(int | (str | int), (int, str))
check((int | str) | (str | int), (int, str))
check(typing.Union[int, str] | list, (int, str, list))
check(int | typing.Union[str, list], (int, str, list))
check((int | str) | (list | int), (int, str, list))
check((int | str) | typing.Union[list, int], (int, str, list))
check(typing.Union[int, str] | (list | int), (int, str, list))
check((str | int) | (int | list), (str, int, list))
check((str | int) | typing.Union[int, list], (str, int, list))
check(typing.Union[str, int] | (int | list), (str, int, list))
check(int | type(None), (int, type(None)))
check(type(None) | int, (type(None), int))
args = (int, list[int], typing.List[int],
typing.Tuple[int, int], typing.Callable[[int], int],
typing.Hashable, typing.TypeVar('T'))
for x in args:
with self.subTest(x):
check(x | None, (x, type(None)))
check(None | x, (type(None), x))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_union_parameter_chaining(self):
T = typing.TypeVar("T")
S = typing.TypeVar("S")
self.assertEqual((float | list[T])[int], float | list[int])
self.assertEqual(list[int | list[T]].__parameters__, (T,))
self.assertEqual(list[int | list[T]][str], list[int | list[str]])
self.assertEqual((list[T] | list[S]).__parameters__, (T, S))
self.assertEqual((list[T] | list[S])[int, T], list[int] | list[T])
self.assertEqual((list[T] | list[S])[int, int], list[int])
def test_union_parameter_substitution(self):
def eq(actual, expected, typed=True):
self.assertEqual(actual, expected)
if typed:
self.assertIs(type(actual), type(expected))
T = typing.TypeVar('T')
S = typing.TypeVar('S')
NT = typing.NewType('NT', str)
x = int | T | bytes
eq(x[str], int | str | bytes, typed=False)
eq(x[list[int]], int | list[int] | bytes, typed=False)
eq(x[typing.List], int | typing.List | bytes)
eq(x[typing.List[int]], int | typing.List[int] | bytes)
eq(x[typing.Hashable], int | typing.Hashable | bytes)
eq(x[collections.abc.Hashable],
int | collections.abc.Hashable | bytes, typed=False)
eq(x[typing.Callable[[int], str]],
int | typing.Callable[[int], str] | bytes)
eq(x[collections.abc.Callable[[int], str]],
int | collections.abc.Callable[[int], str] | bytes, typed=False)
eq(x[typing.Tuple[int, str]], int | typing.Tuple[int, str] | bytes)
eq(x[typing.Literal['none']], int | typing.Literal['none'] | bytes)
eq(x[str | list], int | str | list | bytes, typed=False)
eq(x[typing.Union[str, list]], typing.Union[int, str, list, bytes])
eq(x[str | int], int | str | bytes, typed=False)
eq(x[typing.Union[str, int]], typing.Union[int, str, bytes])
eq(x[NT], int | NT | bytes)
eq(x[S], int | S | bytes)
def test_union_pickle(self):
orig = list[T] | int
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(orig, proto)
loaded = pickle.loads(s)
self.assertEqual(loaded, orig)
self.assertEqual(loaded.__args__, orig.__args__)
self.assertEqual(loaded.__parameters__, orig.__parameters__)
def test_union_copy(self):
orig = list[T] | int
for copied in (copy.copy(orig), copy.deepcopy(orig)):
self.assertEqual(copied, orig)
self.assertEqual(copied.__args__, orig.__args__)
self.assertEqual(copied.__parameters__, orig.__parameters__)
def test_union_parameter_substitution_errors(self):
T = typing.TypeVar("T")
x = int | T
with self.assertRaises(TypeError):
x[42]
# TODO: RUSTPYTHON
@unittest.expectedFailure
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]
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_or_type_repr(self):
assert repr(int | str) == "int | str"
assert repr((int | str) | list) == "int | str | list"
assert repr(int | (str | list)) == "int | str | list"
assert repr(int | None) == "int | None"
assert repr(int | type(None)) == "int | None"
assert repr(int | typing.GenericAlias(list, int)) == "int | list[int]"
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_or_type_operator_with_genericalias(self):
a = list[int]
b = list[str]
c = dict[float, str]
class SubClass(types.GenericAlias): ...
d = SubClass(list, float)
# equivalence with typing.Union
self.assertEqual(a | b | c | d, typing.Union[a, b, c, d])
# de-duplicate
self.assertEqual(a | c | b | b | a | c | d | d, a | b | c | d)
# order shouldn't matter
self.assertEqual(a | b | d, b | a | d)
self.assertEqual(repr(a | b | c | d),
"list[int] | list[str] | dict[float, str] | list[float]")
class BadType(type):
def __eq__(self, other):
return 1 / 0
bt = BadType('bt', (), {})
# Comparison should fail and errors should propagate out for bad types.
with self.assertRaises(ZeroDivisionError):
list[int] | list[bt]
union_ga = (int | list[str], int | collections.abc.Callable[..., str],
int | d)
# Raise error when isinstance(type, type | genericalias)
for type_ in union_ga:
with self.subTest(f"check isinstance/issubclass is invalid for {type_}"):
with self.assertRaises(TypeError):
isinstance(1, type_)
with self.assertRaises(TypeError):
issubclass(int, type_)
def test_or_type_operator_with_bad_module(self):
class BadMeta(type):
__qualname__ = 'TypeVar'
@property
def __module__(self):
1 / 0
TypeVar = BadMeta('TypeVar', (), {})
_SpecialForm = BadMeta('_SpecialForm', (), {})
# Crashes in Issue44483
with self.assertRaises((TypeError, ZeroDivisionError)):
str | TypeVar()
with self.assertRaises((TypeError, ZeroDivisionError)):
str | _SpecialForm()
@cpython_only
def test_or_type_operator_reference_cycle(self):
if not hasattr(sys, 'gettotalrefcount'):
self.skipTest('Cannot get total reference count.')
gc.collect()
before = sys.gettotalrefcount()
for _ in range(30):
T = typing.TypeVar('T')
U = int | list[T]
T.blah = U
del T
del U
gc.collect()
leeway = 15
self.assertLessEqual(sys.gettotalrefcount() - before, leeway,
msg='Check for union reference leak.')
class MappingProxyTests(unittest.TestCase):
mappingproxy = types.MappingProxyType
@@ -1202,6 +1568,24 @@ class ClassCreationTests(unittest.TestCase):
N(5)
self.assertEqual(str(cm.exception), expected_message)
def test_metaclass_new_error(self):
# bpo-44232: The C function type_new() must properly report the
# exception when a metaclass constructor raises an exception and the
# winner class is not the metaclass.
class ModelBase(type):
def __new__(cls, name, bases, attrs):
super_new = super().__new__
new_class = super_new(cls, name, bases, {})
if name != "Model":
raise RuntimeWarning(f"{name=}")
return new_class
class Model(metaclass=ModelBase):
pass
with self.assertRaises(RuntimeWarning):
type("SouthPonies", (Model,), {})
class SimpleNamespaceTests(unittest.TestCase):
+13 -5
View File
@@ -155,7 +155,12 @@ class DynamicClassAttribute:
class's __getattr__ method; this is done by raising AttributeError.
This allows one to have properties active on an instance, and have virtual
attributes on the class with the same name (see Enum for an example).
attributes on the class with the same name. (Enum used this between Python
versions 3.4 - 3.9 .)
Subclass from this to use a different method of accessing virtual atributes
and still be treated properly by the inspect module. (Enum uses this since
Python 3.10 .)
"""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
@@ -277,9 +282,9 @@ def coroutine(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
coro = func(*args, **kwargs)
if (coro.__class__ is CoroutineType or
# XXX RUSTPYTHON TODO: iterable coroutine
False and
if (# XXX RUSTPYTHON TODO: iterable coroutine
False and
coro.__class__ is CoroutineType or
coro.__class__ is GeneratorType and coro.gi_code.co_flags & 0x100):
# 'coro' is a native coroutine object or an iterable coroutine
return coro
@@ -295,8 +300,11 @@ def coroutine(func):
return wrapped
GenericAlias = type(list[int])
# UnionType = type(int | str)
EllipsisType = type(Ellipsis)
NoneType = type(None)
NotImplementedType = type(NotImplemented)
__all__ = [n for n in globals() if n[:1] != '_']