mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
typing upgrade to 3.13.2 (#5590)
This commit is contained in:
6
Lib/_py_abc.py
vendored
6
Lib/_py_abc.py
vendored
@@ -33,6 +33,8 @@ class ABCMeta(type):
|
||||
_abc_invalidation_counter = 0
|
||||
|
||||
def __new__(mcls, name, bases, namespace, /, **kwargs):
|
||||
# TODO: RUSTPYTHON remove this line (prevents duplicate bases)
|
||||
bases = tuple(dict.fromkeys(bases))
|
||||
cls = super().__new__(mcls, name, bases, namespace, **kwargs)
|
||||
# Compute set of abstract method names
|
||||
abstracts = {name
|
||||
@@ -98,8 +100,8 @@ class ABCMeta(type):
|
||||
subtype = type(instance)
|
||||
if subtype is subclass:
|
||||
if (cls._abc_negative_cache_version ==
|
||||
ABCMeta._abc_invalidation_counter and
|
||||
subclass in cls._abc_negative_cache):
|
||||
ABCMeta._abc_invalidation_counter and
|
||||
subclass in cls._abc_negative_cache):
|
||||
return False
|
||||
# Fall back to the subclass check.
|
||||
return cls.__subclasscheck__(subclass)
|
||||
|
||||
57
Lib/test/support/testcase.py
vendored
57
Lib/test/support/testcase.py
vendored
@@ -1,6 +1,63 @@
|
||||
from math import copysign, isnan
|
||||
|
||||
|
||||
class ExtraAssertions:
|
||||
|
||||
def assertIsSubclass(self, cls, superclass, msg=None):
|
||||
if issubclass(cls, superclass):
|
||||
return
|
||||
standardMsg = f'{cls!r} is not a subclass of {superclass!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotIsSubclass(self, cls, superclass, msg=None):
|
||||
if not issubclass(cls, superclass):
|
||||
return
|
||||
standardMsg = f'{cls!r} is a subclass of {superclass!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertHasAttr(self, obj, name, msg=None):
|
||||
if not hasattr(obj, name):
|
||||
if isinstance(obj, types.ModuleType):
|
||||
standardMsg = f'module {obj.__name__!r} has no attribute {name!r}'
|
||||
elif isinstance(obj, type):
|
||||
standardMsg = f'type object {obj.__name__!r} has no attribute {name!r}'
|
||||
else:
|
||||
standardMsg = f'{type(obj).__name__!r} object has no attribute {name!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotHasAttr(self, obj, name, msg=None):
|
||||
if hasattr(obj, name):
|
||||
if isinstance(obj, types.ModuleType):
|
||||
standardMsg = f'module {obj.__name__!r} has unexpected attribute {name!r}'
|
||||
elif isinstance(obj, type):
|
||||
standardMsg = f'type object {obj.__name__!r} has unexpected attribute {name!r}'
|
||||
else:
|
||||
standardMsg = f'{type(obj).__name__!r} object has unexpected attribute {name!r}'
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertStartsWith(self, s, prefix, msg=None):
|
||||
if s.startswith(prefix):
|
||||
return
|
||||
standardMsg = f"{s!r} doesn't start with {prefix!r}"
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotStartsWith(self, s, prefix, msg=None):
|
||||
if not s.startswith(prefix):
|
||||
return
|
||||
self.fail(self._formatMessage(msg, f"{s!r} starts with {prefix!r}"))
|
||||
|
||||
def assertEndsWith(self, s, suffix, msg=None):
|
||||
if s.endswith(suffix):
|
||||
return
|
||||
standardMsg = f"{s!r} doesn't end with {suffix!r}"
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertNotEndsWith(self, s, suffix, msg=None):
|
||||
if not s.endswith(suffix):
|
||||
return
|
||||
self.fail(self._formatMessage(msg, f"{s!r} ends with {suffix!r}"))
|
||||
|
||||
|
||||
class ExceptionIsLikeMixin:
|
||||
def assertExceptionIsLike(self, exc, template):
|
||||
"""
|
||||
|
||||
4
Lib/test/test_dataclasses.py
vendored
4
Lib/test/test_dataclasses.py
vendored
@@ -1906,6 +1906,8 @@ class TestCase(unittest.TestCase):
|
||||
c = Alias(10, 1.0)
|
||||
self.assertEqual(c.new_method(), 1.0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_generic_dynamic(self):
|
||||
T = TypeVar('T')
|
||||
|
||||
@@ -3250,6 +3252,8 @@ class TestStringAnnotations(unittest.TestCase):
|
||||
# won't exist on the instance.
|
||||
self.assertNotIn('not_iv4', c.__dict__)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_text_annotations(self):
|
||||
from test import dataclass_textanno
|
||||
|
||||
|
||||
2
Lib/test/test_exception_group.py
vendored
2
Lib/test/test_exception_group.py
vendored
@@ -15,8 +15,6 @@ class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
||||
with self.assertRaisesRegex(TypeError, 'Exception'):
|
||||
Exception[OSError]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_exception_group_is_generic_type(self):
|
||||
E = OSError
|
||||
self.assertIsInstance(ExceptionGroup[E], types.GenericAlias)
|
||||
|
||||
2
Lib/test/test_future_stmt/test_future.py
vendored
2
Lib/test/test_future_stmt/test_future.py
vendored
@@ -442,8 +442,6 @@ class AnnotationsFutureTestCase(unittest.TestCase):
|
||||
def bar(arg: (yield)): pass
|
||||
"""))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_get_type_hints_on_func_with_variadic_arg(self):
|
||||
# `typing.get_type_hints` might break on a function with a variadic
|
||||
# annotation (e.g. `f(*args: *Ts)`) if `from __future__ import
|
||||
|
||||
10
Lib/test/test_genericalias.py
vendored
10
Lib/test/test_genericalias.py
vendored
@@ -173,6 +173,8 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(a.__args__, (int,))
|
||||
self.assertEqual(a.__parameters__, ())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_parameters(self):
|
||||
from typing import List, Dict, Callable
|
||||
D0 = dict[str, int]
|
||||
@@ -212,6 +214,8 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(L5.__args__, (Callable[[K, V], K],))
|
||||
self.assertEqual(L5.__parameters__, (K, V))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_parameter_chaining(self):
|
||||
from typing import List, Dict, Union, Callable
|
||||
self.assertEqual(list[T][int], list[int])
|
||||
@@ -271,6 +275,8 @@ class BaseTest(unittest.TestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
MyType[int]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pickle(self):
|
||||
alias = GenericAlias(list, T)
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
@@ -280,6 +286,8 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(loaded.__args__, alias.__args__)
|
||||
self.assertEqual(loaded.__parameters__, alias.__parameters__)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_copy(self):
|
||||
class X(list):
|
||||
def __copy__(self):
|
||||
@@ -303,6 +311,8 @@ class BaseTest(unittest.TestCase):
|
||||
self.assertEqual(a.__args__, (list[int], list[str]))
|
||||
self.assertEqual(a.__parameters__, ())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_generic(self):
|
||||
a = typing.Union[list[T], tuple[T, ...]]
|
||||
self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
|
||||
|
||||
16
Lib/test/test_types.py
vendored
16
Lib/test/test_types.py
vendored
@@ -742,6 +742,8 @@ class UnionTests(unittest.TestCase):
|
||||
self.assertTrue(issubclass(dict, x))
|
||||
self.assertFalse(issubclass(list, x))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_instancecheck_and_subclasscheck_order(self):
|
||||
T = typing.TypeVar('T')
|
||||
|
||||
@@ -788,6 +790,8 @@ class UnionTests(unittest.TestCase):
|
||||
self.assertTrue(issubclass(int, x))
|
||||
self.assertRaises(ZeroDivisionError, issubclass, list, x)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_or_type_operator_with_TypeVar(self):
|
||||
TV = typing.TypeVar('T')
|
||||
assert TV | str == typing.Union[TV, str]
|
||||
@@ -795,6 +799,8 @@ class UnionTests(unittest.TestCase):
|
||||
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()
|
||||
@@ -825,6 +831,8 @@ class UnionTests(unittest.TestCase):
|
||||
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")
|
||||
@@ -869,6 +877,8 @@ class UnionTests(unittest.TestCase):
|
||||
eq(x[NT], int | NT | bytes)
|
||||
eq(x[S], int | S | bytes)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_pickle(self):
|
||||
orig = list[T] | int
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
@@ -878,6 +888,8 @@ class UnionTests(unittest.TestCase):
|
||||
self.assertEqual(loaded.__args__, orig.__args__)
|
||||
self.assertEqual(loaded.__parameters__, orig.__parameters__)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_copy(self):
|
||||
orig = list[T] | int
|
||||
for copied in (copy.copy(orig), copy.deepcopy(orig)):
|
||||
@@ -885,12 +897,16 @@ class UnionTests(unittest.TestCase):
|
||||
self.assertEqual(copied.__args__, orig.__args__)
|
||||
self.assertEqual(copied.__parameters__, orig.__parameters__)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_union_parameter_substitution_errors(self):
|
||||
T = typing.TypeVar("T")
|
||||
x = int | T
|
||||
with self.assertRaises(TypeError):
|
||||
x[int, str]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_or_type_operator_with_forward(self):
|
||||
T = typing.TypeVar('T')
|
||||
ForwardAfter = T | 'Forward'
|
||||
|
||||
6479
Lib/test/test_typing.py
vendored
6479
Lib/test/test_typing.py
vendored
File diff suppressed because it is too large
Load Diff
30
Lib/test/typinganndata/_typed_dict_helper.py
vendored
Normal file
30
Lib/test/typinganndata/_typed_dict_helper.py
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
"""Used to test `get_type_hints()` on a cross-module inherited `TypedDict` class
|
||||
|
||||
This script uses future annotations to postpone a type that won't be available
|
||||
on the module inheriting from to `Foo`. The subclass in the other module should
|
||||
look something like this:
|
||||
|
||||
class Bar(_typed_dict_helper.Foo, total=False):
|
||||
b: int
|
||||
|
||||
In addition, it uses multiple levels of Annotated to test the interaction
|
||||
between the __future__ import, Annotated, and Required.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Annotated, Generic, Optional, Required, TypedDict, TypeVar
|
||||
|
||||
|
||||
OptionalIntType = Optional[int]
|
||||
|
||||
class Foo(TypedDict):
|
||||
a: OptionalIntType
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class FooGeneric(TypedDict, Generic[T]):
|
||||
a: Optional[T]
|
||||
|
||||
class VeryAnnotated(TypedDict, total=False):
|
||||
a: Annotated[Annotated[Annotated[Required[int], "a"], "b"], "c"]
|
||||
72
Lib/test/typinganndata/ann_module695.py
vendored
Normal file
72
Lib/test/typinganndata/ann_module695.py
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
from __future__ import annotations
|
||||
from typing import Callable
|
||||
|
||||
|
||||
class A[T, *Ts, **P]:
|
||||
x: T
|
||||
y: tuple[*Ts]
|
||||
z: Callable[P, str]
|
||||
|
||||
|
||||
class B[T, *Ts, **P]:
|
||||
T = int
|
||||
Ts = str
|
||||
P = bytes
|
||||
x: T
|
||||
y: Ts
|
||||
z: P
|
||||
|
||||
|
||||
Eggs = int
|
||||
Spam = str
|
||||
|
||||
|
||||
class C[Eggs, **Spam]:
|
||||
x: Eggs
|
||||
y: Spam
|
||||
|
||||
|
||||
def generic_function[T, *Ts, **P](
|
||||
x: T, *y: *Ts, z: P.args, zz: P.kwargs
|
||||
) -> None: ...
|
||||
|
||||
|
||||
def generic_function_2[Eggs, **Spam](x: Eggs, y: Spam): pass
|
||||
|
||||
|
||||
class D:
|
||||
Foo = int
|
||||
Bar = str
|
||||
|
||||
def generic_method[Foo, **Bar](
|
||||
self, x: Foo, y: Bar
|
||||
) -> None: ...
|
||||
|
||||
def generic_method_2[Eggs, **Spam](self, x: Eggs, y: Spam): pass
|
||||
|
||||
|
||||
def nested():
|
||||
from types import SimpleNamespace
|
||||
from typing import get_type_hints
|
||||
|
||||
Eggs = bytes
|
||||
Spam = memoryview
|
||||
|
||||
|
||||
class E[Eggs, **Spam]:
|
||||
x: Eggs
|
||||
y: Spam
|
||||
|
||||
def generic_method[Eggs, **Spam](self, x: Eggs, y: Spam): pass
|
||||
|
||||
|
||||
def generic_function[Eggs, **Spam](x: Eggs, y: Spam): pass
|
||||
|
||||
|
||||
return SimpleNamespace(
|
||||
E=E,
|
||||
hints_for_E=get_type_hints(E),
|
||||
hints_for_E_meth=get_type_hints(E.generic_method),
|
||||
generic_func=generic_function,
|
||||
hints_for_generic_func=get_type_hints(generic_function)
|
||||
)
|
||||
26
Lib/test/typinganndata/mod_generics_cache.py
vendored
Normal file
26
Lib/test/typinganndata/mod_generics_cache.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Module for testing the behavior of generics across different modules."""
|
||||
|
||||
from typing import TypeVar, Generic, Optional, TypeAliasType
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
|
||||
# default_a: Optional['A'] = None
|
||||
# default_b: Optional['B'] = None
|
||||
|
||||
# T = TypeVar('T')
|
||||
|
||||
|
||||
# class A(Generic[T]):
|
||||
# some_b: 'B'
|
||||
|
||||
|
||||
# class B(Generic[T]):
|
||||
# class A(Generic[T]):
|
||||
# pass
|
||||
|
||||
# my_inner_a1: 'B.A'
|
||||
# my_inner_a2: A
|
||||
# my_outer_a: 'A' # unless somebody calls get_type_hints with localns=B.__dict__
|
||||
|
||||
# type Alias = int
|
||||
# OldStyle = TypeAliasType("OldStyle", int)
|
||||
2826
Lib/typing.py
vendored
2826
Lib/typing.py
vendored
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ pub(crate) mod _typing {
|
||||
use crate::{
|
||||
PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyGenericAlias, PyTupleRef, PyTypeRef, pystr::AsPyStr},
|
||||
function::IntoFuncArgs,
|
||||
function::{FuncArgs, IntoFuncArgs},
|
||||
};
|
||||
|
||||
pub(crate) fn _call_typing_func_object<'a>(
|
||||
@@ -20,8 +20,10 @@ pub(crate) mod _typing {
|
||||
// func.call(args, vm)
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
pub(crate) fn _idfunc(_vm: &VirtualMachine) {}
|
||||
#[pyfunction]
|
||||
pub(crate) fn _idfunc(args: FuncArgs, _vm: &VirtualMachine) -> PyObjectRef {
|
||||
args.args[0].clone()
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "TypeVar")]
|
||||
@@ -51,6 +53,11 @@ pub(crate) mod _typing {
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn name(&self) -> PyObjectRef {
|
||||
self.name.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_typevar(
|
||||
@@ -77,15 +84,102 @@ pub(crate) mod _typing {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct ParamSpec {
|
||||
name: PyObjectRef,
|
||||
bound: Option<PyObjectRef>,
|
||||
default_value: Option<PyObjectRef>,
|
||||
evaluate_default: Option<PyObjectRef>,
|
||||
covariant: bool,
|
||||
contravariant: bool,
|
||||
infer_variance: bool,
|
||||
}
|
||||
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
impl ParamSpec {}
|
||||
impl ParamSpec {
|
||||
#[pygetset(magic)]
|
||||
fn name(&self) -> PyObjectRef {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn bound(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
if let Some(bound) = self.bound.clone() {
|
||||
return bound;
|
||||
}
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn covariant(&self) -> bool {
|
||||
self.covariant
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn contravariant(&self) -> bool {
|
||||
self.contravariant
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn infer_variance(&self) -> bool {
|
||||
self.infer_variance
|
||||
}
|
||||
|
||||
#[pygetset(magic)]
|
||||
fn default(&self, vm: &VirtualMachine) -> PyResult {
|
||||
if let Some(default_value) = self.default_value.clone() {
|
||||
return Ok(default_value);
|
||||
}
|
||||
// handle evaluate_default
|
||||
if let Some(evaluate_default) = self.evaluate_default.clone() {
|
||||
let default_value = vm.call_method(evaluate_default.as_ref(), "__call__", ())?;
|
||||
return Ok(default_value);
|
||||
}
|
||||
// TODO: this isn't up to spec
|
||||
Ok(vm.ctx.none())
|
||||
}
|
||||
|
||||
#[pygetset]
|
||||
fn evaluate_default(&self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
if let Some(evaluate_default) = self.evaluate_default.clone() {
|
||||
return evaluate_default;
|
||||
}
|
||||
// TODO: default_value case
|
||||
vm.ctx.none()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn reduce(&self) -> PyResult {
|
||||
Ok(self.name.clone())
|
||||
}
|
||||
|
||||
#[pymethod]
|
||||
fn has_default(&self) -> PyResult<bool> {
|
||||
// TODO: fix
|
||||
Ok(self.evaluate_default.is_some() || self.default_value.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_paramspec(name: PyObjectRef) -> ParamSpec {
|
||||
ParamSpec { name }
|
||||
ParamSpec {
|
||||
name,
|
||||
bound: None,
|
||||
default_value: None,
|
||||
evaluate_default: None,
|
||||
covariant: false,
|
||||
contravariant: false,
|
||||
infer_variance: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "NoDefault")]
|
||||
#[derive(Debug, PyPayload)]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct NoDefault {
|
||||
name: PyObjectRef,
|
||||
}
|
||||
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
impl NoDefault {}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "TypeVarTuple")]
|
||||
#[derive(Debug, PyPayload)]
|
||||
@@ -161,7 +255,6 @@ pub(crate) mod _typing {
|
||||
// fn as_mapping() -> &'static PyMappingMethods {
|
||||
// static AS_MAPPING: Lazy<PyMappingMethods> = Lazy::new(|| PyMappingMethods {
|
||||
// subscript: atomic_func!(|mapping, needle, vm| {
|
||||
// println!("gigity");
|
||||
// call_typing_func_object(vm, "_GenericAlias", (mapping.obj, needle))
|
||||
// }),
|
||||
// ..PyMappingMethods::NOT_IMPLEMENTED
|
||||
|
||||
Reference in New Issue
Block a user