mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 11:14:38 +08:00
Update types module to CPython 3.10.0
This commit is contained in:
1 parent
1b227f8f89
commit
7da94d878c
2 files changed
+398
-6
No files matched your search
Vendored
+385
-1
@@ -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):
|
||||
|
||||
|
||||
Vendored
+13
-5
@@ -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] != '_']
|
||||
Reference in new issue
Block a user