forked from Rust-related/RustPython
Merge pull request #3291 from DimitrisJim/unconstructible
Add Unconstructible trait
This commit is contained in:
18
extra_tests/snippets/forbidden_instantiation.py
Normal file
18
extra_tests/snippets/forbidden_instantiation.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from typing import Type
|
||||
from testutils import assert_raises
|
||||
|
||||
def check_forbidden_instantiation(typ, reverse=False):
|
||||
f = reversed if reverse else iter
|
||||
with assert_raises(TypeError):
|
||||
type(f(typ()))()
|
||||
|
||||
dict_values, dict_items = lambda: {}.values(), lambda: {}.items()
|
||||
# types with custom forward iterators
|
||||
iter_types = [list, set, str, bytearray, bytes, dict, tuple, lambda: range(0), dict_items, dict_values]
|
||||
# types with custom backwards iterators
|
||||
reviter_types = [list, dict, lambda: range(0), dict_values, dict_items]
|
||||
|
||||
for typ in iter_types:
|
||||
check_forbidden_instantiation(typ)
|
||||
for typ in reviter_types:
|
||||
check_forbidden_instantiation(typ, reverse=True)
|
||||
@@ -24,7 +24,7 @@ use crate::{
|
||||
sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex},
|
||||
slots::{
|
||||
AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable,
|
||||
PyComparisonOp, SlotIterator, Unhashable,
|
||||
PyComparisonOp, SlotConstructor, SlotIterator, Unconstructible, Unhashable,
|
||||
},
|
||||
utils::Either,
|
||||
IdProtocol, PyClassDef, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef,
|
||||
@@ -816,7 +816,7 @@ impl PyValue for PyByteArrayIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyByteArrayIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -836,6 +836,8 @@ impl PyByteArrayIterator {
|
||||
.set_state(state, |obj, pos| pos.min(obj.len()), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyByteArrayIterator {}
|
||||
|
||||
impl IteratorIterable for PyByteArrayIterator {}
|
||||
impl SlotIterator for PyByteArrayIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
protocol::{BufferInternal, BufferOptions, PyBuffer, PyIterReturn, PyMappingMethods},
|
||||
slots::{
|
||||
AsBuffer, AsMapping, Callable, Comparable, Hashable, Iterable, IteratorIterable,
|
||||
PyComparisonOp, SlotConstructor, SlotIterator,
|
||||
PyComparisonOp, SlotConstructor, SlotIterator, Unconstructible,
|
||||
},
|
||||
utils::Either,
|
||||
IdProtocol, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
@@ -649,7 +649,7 @@ impl PyValue for PyBytesIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyBytesIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -670,6 +670,8 @@ impl PyBytesIterator {
|
||||
.set_state(state, |obj, pos| pos.min(obj.len()), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyBytesIterator {}
|
||||
|
||||
impl IteratorIterable for PyBytesIterator {}
|
||||
impl SlotIterator for PyBytesIterator {
|
||||
fn next(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
|
||||
|
||||
@@ -9,8 +9,8 @@ use crate::{
|
||||
function::{ArgIterable, FuncArgs, IntoPyObject, KwArgs, OptionalArg},
|
||||
protocol::{PyIterIter, PyIterReturn, PyMappingMethods},
|
||||
slots::{
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
|
||||
Unhashable,
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
|
||||
SlotConstructor, SlotIterator, Unconstructible, Unhashable,
|
||||
},
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
IdProtocol, ItemProtocol,
|
||||
@@ -762,7 +762,7 @@ macro_rules! dict_view {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl $iter_name {
|
||||
fn new(dict: PyDictRef) -> Self {
|
||||
$iter_name {
|
||||
@@ -776,6 +776,7 @@ macro_rules! dict_view {
|
||||
self.internal.lock().length_hint(|_| self.size.entries_size)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for $iter_name {}
|
||||
|
||||
impl IteratorIterable for $iter_name {}
|
||||
impl SlotIterator for $iter_name {
|
||||
@@ -818,7 +819,7 @@ macro_rules! dict_view {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl $reverse_iter_name {
|
||||
fn new(dict: PyDictRef) -> Self {
|
||||
let size = dict.size();
|
||||
@@ -836,6 +837,7 @@ macro_rules! dict_view {
|
||||
.rev_length_hint(|_| self.size.entries_size)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for $reverse_iter_name {}
|
||||
|
||||
impl IteratorIterable for $reverse_iter_name {}
|
||||
impl SlotIterator for $reverse_iter_name {
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::{
|
||||
sequence::{self, SimpleSeq},
|
||||
sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex},
|
||||
slots::{
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
|
||||
Unhashable,
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
|
||||
SlotConstructor, SlotIterator, Unconstructible, Unhashable,
|
||||
},
|
||||
stdlib::sys,
|
||||
utils::Either,
|
||||
@@ -517,7 +517,7 @@ impl PyValue for PyListIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyListIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -538,6 +538,7 @@ impl PyListIterator {
|
||||
.builtins_iter_reduce(|x| x.clone().into(), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyListIterator {}
|
||||
|
||||
impl IteratorIterable for PyListIterator {}
|
||||
impl SlotIterator for PyListIterator {
|
||||
@@ -564,7 +565,7 @@ impl PyValue for PyListReverseIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyListReverseIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -585,6 +586,7 @@ impl PyListReverseIterator {
|
||||
.builtins_reversed_reduce(|x| x.clone().into(), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyListReverseIterator {}
|
||||
|
||||
impl IteratorIterable for PyListReverseIterator {}
|
||||
impl SlotIterator for PyListReverseIterator {
|
||||
|
||||
@@ -11,7 +11,7 @@ use crate::{
|
||||
sliceable::PySliceableSequence,
|
||||
slots::{
|
||||
Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor,
|
||||
SlotIterator,
|
||||
SlotIterator, Unconstructible,
|
||||
},
|
||||
stdlib::sys,
|
||||
utils::Either,
|
||||
@@ -220,7 +220,7 @@ impl PyValue for PyStrIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyStrIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -244,6 +244,7 @@ impl PyStrIterator {
|
||||
.builtins_iter_reduce(|x| x.clone().into(), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyStrIterator {}
|
||||
|
||||
impl IteratorIterable for PyStrIterator {}
|
||||
impl SlotIterator for PyStrIterator {
|
||||
|
||||
@@ -5,7 +5,8 @@ use crate::{
|
||||
function::{FuncArgs, OptionalArg},
|
||||
protocol::{PyIterReturn, PyMappingMethods},
|
||||
slots::{
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotIterator,
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
|
||||
SlotConstructor, SlotIterator, Unconstructible,
|
||||
},
|
||||
IdProtocol, IntoPyRef, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol, VirtualMachine,
|
||||
@@ -511,7 +512,7 @@ impl PyValue for PyLongRangeIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyLongRangeIterator {
|
||||
#[pyslot]
|
||||
fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -545,6 +546,7 @@ impl PyLongRangeIterator {
|
||||
)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyLongRangeIterator {}
|
||||
|
||||
impl IteratorIterable for PyLongRangeIterator {}
|
||||
impl SlotIterator for PyLongRangeIterator {
|
||||
@@ -580,13 +582,8 @@ impl PyValue for PyRangeIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyRangeIterator {
|
||||
#[pyslot]
|
||||
fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_type_error("cannot create 'range_iterator' instances".to_owned()))
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
let index = self.index.load();
|
||||
@@ -615,6 +612,7 @@ impl PyRangeIterator {
|
||||
)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyRangeIterator {}
|
||||
|
||||
impl IteratorIterable for PyRangeIterator {}
|
||||
impl SlotIterator for PyRangeIterator {
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
protocol::PyIterReturn,
|
||||
slots::{
|
||||
Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp, SlotConstructor,
|
||||
SlotIterator, Unhashable,
|
||||
SlotIterator, Unconstructible, Unhashable,
|
||||
},
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
IdProtocol, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
@@ -884,7 +884,7 @@ impl PyValue for PySetIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PySetIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -907,6 +907,7 @@ impl PySetIterator {
|
||||
))
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PySetIterator {}
|
||||
|
||||
impl IteratorIterable for PySetIterator {}
|
||||
impl SlotIterator for PySetIterator {
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
sliceable::PySliceableSequence,
|
||||
slots::{
|
||||
AsMapping, Comparable, Hashable, Iterable, IteratorIterable, PyComparisonOp,
|
||||
SlotConstructor, SlotIterator,
|
||||
SlotConstructor, SlotIterator, Unconstructible,
|
||||
},
|
||||
stdlib::sys,
|
||||
utils::Either,
|
||||
@@ -379,7 +379,7 @@ impl PyValue for PyTupleIterator {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(with(SlotIterator))]
|
||||
#[pyimpl(with(SlotConstructor, SlotIterator))]
|
||||
impl PyTupleIterator {
|
||||
#[pymethod(magic)]
|
||||
fn length_hint(&self) -> usize {
|
||||
@@ -400,6 +400,7 @@ impl PyTupleIterator {
|
||||
.builtins_iter_reduce(|x| x.clone().into(), vm)
|
||||
}
|
||||
}
|
||||
impl Unconstructible for PyTupleIterator {}
|
||||
|
||||
impl IteratorIterable for PyTupleIterator {}
|
||||
impl SlotIterator for PyTupleIterator {
|
||||
|
||||
@@ -157,6 +157,20 @@ pub trait SlotConstructor: PyValue {
|
||||
fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
/// For types that cannot be instantiated through Python code.
|
||||
pub trait Unconstructible: PyValue {}
|
||||
|
||||
impl<T> SlotConstructor for T
|
||||
where
|
||||
T: Unconstructible,
|
||||
{
|
||||
type Args = FuncArgs;
|
||||
|
||||
fn py_new(cls: PyTypeRef, _args: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
Err(vm.new_type_error(format!("cannot create {} instances", cls.slot_name())))
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait SlotDestructor: PyValue {
|
||||
#[inline] // for __del__
|
||||
|
||||
Reference in New Issue
Block a user