mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Type alias type (#6011)
* Constructor for TypeAliasType * Fix PyBaseObject::py_new * Representable for TypeAliasType
This commit is contained in:
2
Lib/test/test_ast/test_ast.py
vendored
2
Lib/test/test_ast/test_ast.py
vendored
@@ -706,6 +706,8 @@ class AST_Tests(unittest.TestCase):
|
||||
with assertNumDeprecated():
|
||||
self.assertNotIsInstance(Constant(S("42")), Num)
|
||||
|
||||
# TODO: RUSTPYTHON; will be removed in Python 3.14
|
||||
@unittest.expectedFailure
|
||||
def test_constant_subclasses_deprecated(self):
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", "", DeprecationWarning)
|
||||
|
||||
12
Lib/test/test_collections.py
vendored
12
Lib/test/test_collections.py
vendored
@@ -952,8 +952,6 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||
self.validate_abstract_methods(AsyncIterable, '__aiter__')
|
||||
self.validate_isinstance(AsyncIterable, '__aiter__')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_AsyncIterator(self):
|
||||
class AI:
|
||||
def __aiter__(self):
|
||||
@@ -1152,8 +1150,6 @@ class TestOneTrickPonyABCs(ABCTestCase):
|
||||
self.assertFalse(issubclass(NonCol, Collection))
|
||||
self.assertFalse(isinstance(NonCol(), Collection))
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_Iterator(self):
|
||||
non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
|
||||
for x in non_samples:
|
||||
@@ -1850,8 +1846,6 @@ class TestCollectionABCs(ABCTestCase):
|
||||
fs = frozenset(s)
|
||||
self.assertEqual(hash(fs), Set._hash(fs), msg=s)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_Mapping(self):
|
||||
for sample in [dict]:
|
||||
self.assertIsInstance(sample(), Mapping)
|
||||
@@ -1868,8 +1862,6 @@ class TestCollectionABCs(ABCTestCase):
|
||||
self.validate_comparison(MyMapping())
|
||||
self.assertRaises(TypeError, reversed, MyMapping())
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_MutableMapping(self):
|
||||
for sample in [dict]:
|
||||
self.assertIsInstance(sample(), MutableMapping)
|
||||
@@ -1904,8 +1896,6 @@ class TestCollectionABCs(ABCTestCase):
|
||||
mymap['blue'] = 7 # Shouldn't affect 'z'
|
||||
self.assertEqual(z, {('orange', 3), ('red', 5)})
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_Sequence(self):
|
||||
for sample in [tuple, list, bytes, str]:
|
||||
self.assertIsInstance(sample(), Sequence)
|
||||
@@ -1988,8 +1978,6 @@ class TestCollectionABCs(ABCTestCase):
|
||||
self.assertFalse(issubclass(sample, Buffer))
|
||||
self.validate_abstract_methods(Buffer, '__buffer__')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_MutableSequence(self):
|
||||
for sample in [tuple, str, bytes]:
|
||||
self.assertNotIsInstance(sample(), MutableSequence)
|
||||
|
||||
2
Lib/test/test_exception_group.py
vendored
2
Lib/test/test_exception_group.py
vendored
@@ -315,8 +315,6 @@ class ExceptionGroupSubgroupTests(ExceptionGroupTestBase):
|
||||
self.eg = create_simple_eg()
|
||||
self.eg_template = [ValueError(1), TypeError(int), ValueError(2)]
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_basics_subgroup_split__bad_arg_type(self):
|
||||
class C:
|
||||
pass
|
||||
|
||||
4
Lib/test/test_typing.py
vendored
4
Lib/test/test_typing.py
vendored
@@ -2948,8 +2948,6 @@ class ProtocolTests(BaseTestCase):
|
||||
self.assertNotIsInstance(D(), E)
|
||||
self.assertNotIsInstance(E(), D)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_no_instantiation(self):
|
||||
class P(Protocol): pass
|
||||
|
||||
@@ -4500,8 +4498,6 @@ class GenericTests(BaseTestCase):
|
||||
self.assertEqual(c.from_a, 'foo')
|
||||
self.assertEqual(c.from_c, 'foo')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_new_no_args(self):
|
||||
|
||||
class A(Generic[T]):
|
||||
|
||||
@@ -31,7 +31,42 @@ impl PyPayload for PyBaseObject {
|
||||
impl Constructor for PyBaseObject {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
// = object_new
|
||||
fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
if !args.args.is_empty() || !args.kwargs.is_empty() {
|
||||
// Check if type's __new__ != object.__new__
|
||||
let tp_new = cls.get_attr(identifier!(vm, __new__));
|
||||
let object_new = vm.ctx.types.object_type.get_attr(identifier!(vm, __new__));
|
||||
|
||||
if let (Some(tp_new), Some(object_new)) = (tp_new, object_new) {
|
||||
if !tp_new.is(&object_new) {
|
||||
// Type has its own __new__, so object.__new__ is being called
|
||||
// with excess args. This is the first error case in CPython
|
||||
return Err(vm.new_type_error(
|
||||
"object.__new__() takes exactly one argument (the type to instantiate)"
|
||||
.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
// If we reach here, tp_new == object_new
|
||||
// Now check if type's __init__ == object.__init__
|
||||
let tp_init = cls.get_attr(identifier!(vm, __init__));
|
||||
let object_init = vm.ctx.types.object_type.get_attr(identifier!(vm, __init__));
|
||||
|
||||
if let (Some(tp_init), Some(object_init)) = (tp_init, object_init) {
|
||||
if tp_init.is(&object_init) {
|
||||
// Both __new__ and __init__ are object's versions,
|
||||
// so the type accepts no arguments
|
||||
return Err(
|
||||
vm.new_type_error(format!("{}() takes no arguments", cls.name()))
|
||||
);
|
||||
}
|
||||
}
|
||||
// If tp_init != object_init, then the type has custom __init__
|
||||
// which might accept arguments, so we allow it
|
||||
}
|
||||
}
|
||||
|
||||
// more or less __new__ operator
|
||||
let dict = if cls.is(vm.ctx.types.object_type) {
|
||||
None
|
||||
|
||||
@@ -4,15 +4,16 @@ use super::{PY_CF_OPTIMIZED_AST, PY_CF_TYPE_COMMENTS, PY_COMPILE_FLAG_AST_ONLY};
|
||||
pub(crate) mod _ast {
|
||||
use crate::{
|
||||
AsObject, Context, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyStrRef, PyTupleRef},
|
||||
builtins::{PyStrRef, PyTupleRef, PyTypeRef},
|
||||
function::FuncArgs,
|
||||
types::Constructor,
|
||||
};
|
||||
#[pyattr]
|
||||
#[pyclass(module = "_ast", name = "AST")]
|
||||
#[derive(Debug, PyPayload)]
|
||||
pub(crate) struct NodeAst;
|
||||
|
||||
#[pyclass(flags(BASETYPE, HAS_DICT))]
|
||||
#[pyclass(with(Constructor), flags(BASETYPE, HAS_DICT))]
|
||||
impl NodeAst {
|
||||
#[pyslot]
|
||||
#[pymethod]
|
||||
@@ -52,6 +53,34 @@ pub(crate) mod _ast {
|
||||
}
|
||||
}
|
||||
|
||||
impl Constructor for NodeAst {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
// AST nodes accept extra arguments (unlike object.__new__)
|
||||
// This matches CPython's behavior where AST has its own tp_new
|
||||
let dict = if cls
|
||||
.slots
|
||||
.flags
|
||||
.contains(crate::types::PyTypeFlags::HAS_DICT)
|
||||
{
|
||||
Some(vm.ctx.new_dict())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let zelf = vm.ctx.new_base_object(cls, dict);
|
||||
|
||||
// Initialize the instance with the provided arguments
|
||||
NodeAst::__init__(zelf.clone(), args, vm)?;
|
||||
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
fn py_new(_cls: PyTypeRef, _args: Self::Args, _vm: &VirtualMachine) -> PyResult {
|
||||
unreachable!("slow_new is implemented");
|
||||
}
|
||||
}
|
||||
|
||||
#[pyattr(name = "PyCF_ONLY_AST")]
|
||||
use super::PY_COMPILE_FLAG_AST_ONLY;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
|
||||
#[pymodule(name = "_typing")]
|
||||
pub(crate) mod decl {
|
||||
use crate::{
|
||||
PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyTupleRef, PyTypeRef, pystr::AsPyStr},
|
||||
function::{FuncArgs, IntoFuncArgs},
|
||||
types::{Constructor, Representable},
|
||||
@@ -88,7 +88,7 @@ pub(crate) mod decl {
|
||||
|
||||
impl Representable for NoDefault {
|
||||
#[inline(always)]
|
||||
fn repr_str(_zelf: &crate::Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
|
||||
fn repr_str(_zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
|
||||
Ok("typing.NoDefault".to_owned())
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ pub(crate) mod decl {
|
||||
// compute_value: PyObjectRef,
|
||||
// module: PyObjectRef,
|
||||
}
|
||||
#[pyclass(flags(BASETYPE))]
|
||||
#[pyclass(with(Constructor, Representable), flags(BASETYPE))]
|
||||
impl TypeAliasType {
|
||||
pub const fn new(name: PyObjectRef, type_params: PyTupleRef, value: PyObjectRef) -> Self {
|
||||
Self {
|
||||
@@ -128,10 +128,51 @@ pub(crate) mod decl {
|
||||
fn __type_params__(&self) -> PyTupleRef {
|
||||
self.type_params.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethod(name = "__repr__")]
|
||||
fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let name = self.name.str(vm)?;
|
||||
impl Constructor for TypeAliasType {
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
// TypeAliasType(name, value, *, type_params=None)
|
||||
if args.args.len() < 2 {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"TypeAliasType() missing {} required positional argument{}: {}",
|
||||
2 - args.args.len(),
|
||||
if 2 - args.args.len() == 1 { "" } else { "s" },
|
||||
if args.args.is_empty() {
|
||||
"'name' and 'value'"
|
||||
} else {
|
||||
"'value'"
|
||||
}
|
||||
)));
|
||||
}
|
||||
if args.args.len() > 2 {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"TypeAliasType() takes 2 positional arguments but {} were given",
|
||||
args.args.len()
|
||||
)));
|
||||
}
|
||||
|
||||
let name = args.args[0].clone();
|
||||
let value = args.args[1].clone();
|
||||
|
||||
let type_params = if let Some(tp) = args.kwargs.get("type_params") {
|
||||
tp.clone()
|
||||
.downcast::<crate::builtins::PyTuple>()
|
||||
.map_err(|_| vm.new_type_error("type_params must be a tuple".to_owned()))?
|
||||
} else {
|
||||
vm.ctx.empty_tuple.clone()
|
||||
};
|
||||
|
||||
let ta = TypeAliasType::new(name, type_params, value);
|
||||
ta.into_ref_with_type(vm, cls).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
impl Representable for TypeAliasType {
|
||||
fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
|
||||
let name = zelf.name.str(vm)?;
|
||||
Ok(name.as_str().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user