Merge pull request #1618 from RustPython/coolreader18/misc-changes

Some miscellaneous changes (print fix, bytes/bytearray fixes, mappingproxy iter)
This commit is contained in:
Windel Bouwman
2019-12-04 16:06:58 +01:00
committed by GitHub
20 changed files with 378 additions and 100 deletions

14
Lib/_sre.py vendored
View File

@@ -70,6 +70,16 @@ class SRE_Pattern(object):
else:
return None
def fullmatch(self, string):
"""If the whole string matches the regular expression pattern, return a
corresponding match object. Return None if the string does not match the
pattern; note that this is different from a zero-length match."""
match = self.match(string)
if match and match.start() == 0 and match.end() == len(string):
return match
else:
return None
def search(self, string, pos=0, endpos=sys.maxsize):
"""Scan through string looking for a location where this regular
expression produces a match, and return a corresponding MatchObject
@@ -123,7 +133,7 @@ class SRE_Pattern(object):
last_pos == state.string_position and n > 0):
# the above ignores empty matches on latest position
if callable(filter):
sublist.append(list(filter(SRE_Match(self, state))))
sublist.extend(filter(SRE_Match(self, state)))
else:
sublist.append(filter)
last_pos = state.string_position
@@ -334,6 +344,8 @@ class SRE_Match(object):
class _State(object):
def __init__(self, string, start, end, flags):
if isinstance(string, bytes):
string = string.decode()
self.string = string
if start < 0:
start = 0

View File

@@ -279,7 +279,7 @@ fn get_paths(env_variable_name: &str) -> Vec<String> {
#[cfg(feature = "flame-it")]
fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
use std::fs::File;
use std::{fs, io};
enum ProfileFormat {
Html,
@@ -306,12 +306,14 @@ fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>>
ProfileFormat::Speedscope => "flamescope.json".as_ref(),
});
let profile_output: Box<dyn std::io::Write> = if profile_output == "-" {
Box::new(std::io::stdout())
let profile_output: Box<dyn io::Write> = if profile_output == "-" {
Box::new(io::stdout())
} else {
Box::new(File::create(profile_output)?)
Box::new(fs::File::create(profile_output)?)
};
let profile_output = io::BufWriter::new(profile_output);
match profile_format {
ProfileFormat::Html => flame::dump_html(profile_output)?,
ProfileFormat::Text => flame::dump_text_to_writer(profile_output)?,

View File

@@ -271,6 +271,9 @@ assert bytearray(b"").join(
) == bytearray(b"jiljlkmoomkaaaa")
with assert_raises(TypeError):
bytearray(b"").join((b"km", "kl"))
assert bytearray(b"abc").join((
bytearray(b"123"), bytearray(b"xyz")
)) == bytearray(b"123abcxyz")
# endswith startswith

View File

@@ -270,6 +270,8 @@ assert (
with assert_raises(TypeError):
b"".join((b"km", "kl"))
assert b"abc".join((b"123", b"xyz")) == b"123abcxyz"
# endswith startswith
assert b"abcde".endswith(b"de")
@@ -612,3 +614,9 @@ assert b'\xe4\xb8\xad\xe6\x96\x87\xe5\xad\x97'.decode('utf-8') == '中文字'
# mod
assert b'rust%bpython%b' % (b' ', b'!') == b'rust python!'
assert b'x=%i y=%f' % (1, 2.5) == b'x=1 y=2.500000'
class A:
def __bytes__(self):
return b"bytess"
assert bytes(A()) == b"bytess"

View File

@@ -131,3 +131,13 @@ for i in [0, 1, 2, 'spam', 4]:
wrap.send(i)
assert l == ['>> 0', '>> 1', '>> 2', '***', '>> 4']
def a():
yield
g = a()
next(g)
assert_raises(TypeError, g.throw, TypeError)
assert_raises(StopIteration, next, g)
assert_raises(TypeError, g.throw, TypeError)

View File

@@ -52,3 +52,5 @@ class ReturnInt(metaclass=MCReturnInt):
assert isinstance("a", ReturnInt) is True
assert isinstance(1, ((int, float,), str))

View File

@@ -25,8 +25,8 @@ use crate::obj::objstr::{PyString, PyStringRef};
use crate::obj::objtype::{self, PyClassRef};
use crate::pyhash;
use crate::pyobject::{
Either, IdProtocol, IntoPyObject, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue,
TryFromObject, TypeProtocol,
Either, IdProtocol, ItemProtocol, PyIterable, PyObjectRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
};
use crate::scope::Scope;
use crate::stdlib::ast;
@@ -598,13 +598,13 @@ pub struct PrintOptions {
}
trait Printer {
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()>;
fn write(&mut self, vm: &VirtualMachine, obj: PyStringRef) -> PyResult<()>;
fn flush(&mut self, vm: &VirtualMachine) -> PyResult<()>;
}
impl Printer for &'_ PyObjectRef {
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()> {
vm.call_method(self, "write", vec![obj])?;
fn write(&mut self, vm: &VirtualMachine, obj: PyStringRef) -> PyResult<()> {
vm.call_method(self, "write", vec![obj.into_object()])?;
Ok(())
}
@@ -615,14 +615,13 @@ impl Printer for &'_ PyObjectRef {
}
impl Printer for std::io::StdoutLock<'_> {
fn write(&mut self, vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<()> {
let s = vm.to_str(&obj)?;
write!(self, "{}", s.as_str()).unwrap();
fn write(&mut self, _vm: &VirtualMachine, s: PyStringRef) -> PyResult<()> {
write!(self, "{}", s).unwrap();
Ok(())
}
fn flush(&mut self, _vm: &VirtualMachine) -> PyResult<()> {
<Self as std::io::Write>::flush(self).unwrap();
<Self as io::Write>::flush(self).unwrap();
Ok(())
}
}
@@ -643,10 +642,7 @@ pub fn builtin_print(objects: Args, options: PrintOptions, vm: &VirtualMachine)
let sep = options
.sep
.as_ref()
.map_or(" ", |sep| sep.as_str())
.into_pyobject(vm)
.unwrap();
.unwrap_or_else(|| PyString::from(" ").into_ref(vm));
let mut first = true;
for object in objects {
@@ -656,15 +652,12 @@ pub fn builtin_print(objects: Args, options: PrintOptions, vm: &VirtualMachine)
printer.write(vm, sep.clone())?;
}
printer.write(vm, object)?;
printer.write(vm, vm.to_str(&object)?)?;
}
let end = options
.end
.as_ref()
.map_or("\n", |end| end.as_str())
.into_pyobject(vm)
.unwrap();
.unwrap_or_else(|| PyString::from("\n").into_ref(vm));
printer.write(vm, end)?;
if options.flush.to_bool() {

View File

@@ -390,9 +390,9 @@ impl ExceptionZoo {
let assertion_error = create_type("AssertionError", &type_type, &exception_type);
let attribute_error = create_type("AttributeError", &type_type, &exception_type);
let import_error = create_type("ImportError", &type_type, &exception_type);
let index_error = create_type("IndexError", &type_type, &exception_type);
let key_error = create_type("KeyError", &type_type, &exception_type);
let lookup_error = create_type("LookupError", &type_type, &exception_type);
let index_error = create_type("IndexError", &type_type, &lookup_error);
let key_error = create_type("KeyError", &type_type, &lookup_error);
let name_error = create_type("NameError", &type_type, &exception_type);
let runtime_error = create_type("RuntimeError", &type_type, &exception_type);
let reference_error = create_type("ReferenceError", &type_type, &exception_type);

View File

@@ -569,17 +569,35 @@ pub fn single_or_tuple_any<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>>(
message: fn(&PyObjectRef) -> String,
vm: &VirtualMachine,
) -> PyResult<bool> {
match_class!(match obj {
obj @ T => predicate(obj),
tuple @ PyTuple => {
for obj in tuple.elements.iter() {
let inner_val = PyRef::<T>::try_from_object(vm, obj.clone())?;
if predicate(inner_val)? {
return Ok(true);
// TODO: figure out some way to have recursive calls without... this
use std::marker::PhantomData;
struct Checker<'vm, T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> {
predicate: F,
message: fn(&PyObjectRef) -> String,
vm: &'vm VirtualMachine,
t: PhantomData<T>,
}
impl<T: PyValue, F: Fn(PyRef<T>) -> PyResult<bool>> Checker<'_, T, F> {
fn check(&self, obj: PyObjectRef) -> PyResult<bool> {
match_class!(match obj {
obj @ T => (self.predicate)(obj),
tuple @ PyTuple => {
for obj in tuple.elements.iter() {
if self.check(obj.clone())? {
return Ok(true);
}
}
Ok(false)
}
}
Ok(false)
obj => Err(self.vm.new_type_error((self.message)(&obj))),
})
}
obj => Err(vm.new_type_error(message(&obj))),
})
}
let checker = Checker {
predicate,
message,
vm,
t: PhantomData,
};
checker.check(obj)
}

View File

@@ -3,7 +3,7 @@ use num_traits::Zero;
use crate::function::PyFuncArgs;
use crate::pyobject::{
IntoPyObject, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
IdProtocol, IntoPyObject, PyContext, PyObjectRef, PyResult, TryFromObject, TypeProtocol,
};
use crate::vm::VirtualMachine;
@@ -29,6 +29,12 @@ impl TryFromObject for bool {
/// Convert Python bool into Rust bool.
pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
if obj.is(&vm.ctx.true_value) {
return Ok(true);
}
if obj.is(&vm.ctx.false_value) {
return Ok(false);
}
let rs_bool = match vm.get_method(obj.clone(), "__bool__") {
Some(method_or_err) => {
// If descriptor returns Error, propagate it further

View File

@@ -187,6 +187,11 @@ impl PyByteArrayRef {
self.inner.borrow_mut().setitem(needle, value, vm)
}
#[pymethod(name = "__delitem__")]
fn delitem(self, needle: Either<i32, PySliceRef>, vm: &VirtualMachine) -> PyResult<()> {
self.inner.borrow_mut().delitem(needle, vm)
}
#[pymethod(name = "isalnum")]
fn isalnum(self, vm: &VirtualMachine) -> bool {
self.inner.borrow().isalnum(vm)
@@ -285,7 +290,7 @@ impl PyByteArrayRef {
}
#[pymethod(name = "join")]
fn join(self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
fn join(self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
self.inner.borrow().join(iter, vm)
}

View File

@@ -1,9 +1,9 @@
use std::convert::TryFrom;
use std::ops::Range;
use num_bigint::BigInt;
use num_bigint::{BigInt, ToBigInt};
use num_integer::Integer;
use num_traits::ToPrimitive;
use num_traits::{One, Signed, ToPrimitive, Zero};
use super::objbytearray::{PyByteArray, PyByteArrayRef};
use super::objbytes::{PyBytes, PyBytesRef};
@@ -86,15 +86,20 @@ impl ByteInnerNewOptions {
);
}
obj => {
// TODO: only support this method in the bytes() constructor
if let Some(bytes_method) = vm.get_method(obj.clone(), "__bytes__") {
let bytes = vm.invoke(&bytes_method?, vec![])?;
return PyByteInner::try_from_object(vm, bytes);
}
let elements = vm.extract_elements(&obj).or_else(|_| {
Err(vm.new_type_error(format!(
"cannot convert '{}' object to bytes",
obj.class().name
)))
});
})?;
let mut data_bytes = vec![];
for elem in elements? {
for elem in elements {
let v = objint::to_int(vm, &elem, &BigInt::from(10))?;
if let Some(i) = v.to_u8() {
data_bytes.push(i);
@@ -472,6 +477,140 @@ impl PyByteInner {
}
}
pub fn delitem(
&mut self,
needle: Either<i32, PySliceRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
match needle {
Either::A(int) => {
if let Some(idx) = self.elements.get_pos(int) {
self.elements.remove(idx);
Ok(())
} else {
Err(vm.new_index_error("index out of range".to_string()))
}
}
Either::B(slice) => self.delslice(slice, vm),
}
}
// TODO: deduplicate this with the code in objlist
fn delslice(&mut self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
let start = slice.start_index(vm)?;
let stop = slice.stop_index(vm)?;
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
if step.is_zero() {
Err(vm.new_value_error("slice step cannot be zero".to_string()))
} else if step.is_positive() {
let range = self.elements.get_slice_range(&start, &stop);
if range.start < range.end {
#[allow(clippy::range_plus_one)]
match step.to_i32() {
Some(1) => {
self._del_slice(range);
Ok(())
}
Some(num) => {
self._del_stepped_slice(range, num as usize);
Ok(())
}
None => {
self._del_slice(range.start..range.start + 1);
Ok(())
}
}
} else {
// no del to do
Ok(())
}
} else {
// calculate the range for the reverse slice, first the bounds needs to be made
// exclusive around stop, the lower number
let start = start.as_ref().map(|x| {
if *x == (-1).to_bigint().unwrap() {
self.elements.len() + BigInt::one() //.to_bigint().unwrap()
} else {
x + 1
}
});
let stop = stop.as_ref().map(|x| {
if *x == (-1).to_bigint().unwrap() {
self.elements.len().to_bigint().unwrap()
} else {
x + 1
}
});
let range = self.elements.get_slice_range(&stop, &start);
if range.start < range.end {
match (-step).to_i32() {
Some(1) => {
self._del_slice(range);
Ok(())
}
Some(num) => {
self._del_stepped_slice_reverse(range, num as usize);
Ok(())
}
None => {
self._del_slice(range.end - 1..range.end);
Ok(())
}
}
} else {
// no del to do
Ok(())
}
}
}
fn _del_slice(&mut self, range: Range<usize>) {
self.elements.drain(range);
}
fn _del_stepped_slice(&mut self, range: Range<usize>, step: usize) {
// no easy way to delete stepped indexes so here is what we'll do
let mut deleted = 0;
let elements = &mut self.elements;
let mut indexes = range.clone().step_by(step).peekable();
for i in range.clone() {
// is this an index to delete?
if indexes.peek() == Some(&i) {
// record and move on
indexes.next();
deleted += 1;
} else {
// swap towards front
elements.swap(i - deleted, i);
}
}
// then drain (the values to delete should now be contiguous at the end of the range)
elements.drain((range.end - deleted)..range.end);
}
fn _del_stepped_slice_reverse(&mut self, range: Range<usize>, step: usize) {
// no easy way to delete stepped indexes so here is what we'll do
let mut deleted = 0;
let elements = &mut self.elements;
let mut indexes = range.clone().rev().step_by(step).peekable();
for i in range.clone().rev() {
// is this an index to delete?
if indexes.peek() == Some(&i) {
// record and move on
indexes.next();
deleted += 1;
} else {
// swap towards back
elements.swap(i + deleted, i);
}
}
// then drain (the values to delete should now be contiguous at teh start of the range)
elements.drain(range.start..(range.start + deleted));
}
pub fn isalnum(&self, _vm: &VirtualMachine) -> bool {
!self.elements.is_empty()
&& self
@@ -692,11 +831,14 @@ impl PyByteInner {
Ok(total)
}
pub fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
pub fn join(&self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
let mut refs = vec![];
for v in iter.iter(vm)? {
let v = v?;
refs.extend(PyByteInner::try_from_object(vm, v)?.elements)
if !refs.is_empty() {
refs.extend(&self.elements);
}
refs.extend(v.elements);
}
Ok(vm.ctx.new_bytes(refs))

View File

@@ -263,7 +263,7 @@ impl PyBytesRef {
}
#[pymethod(name = "join")]
fn join(self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
fn join(self, iter: PyIterable<PyByteInner>, vm: &VirtualMachine) -> PyResult {
self.inner.join(iter, vm)
}

View File

@@ -1,15 +1,19 @@
use super::objiter::new_stop_iteration;
use super::objtype::{isinstance, issubclass, PyClassRef};
use crate::frame::{ExecutionResult, FrameRef};
use crate::function::OptionalArg;
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
use std::cell::Cell;
pub type PyCoroutineRef = PyRef<PyCoroutine>;
#[pyclass(name = "coroutine")]
#[derive(Debug)]
pub struct PyCoroutine {
frame: FrameRef,
closed: Cell<bool>,
}
impl PyValue for PyCoroutine {
@@ -21,14 +25,32 @@ impl PyValue for PyCoroutine {
#[pyimpl]
impl PyCoroutine {
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyCoroutineRef {
PyCoroutine { frame }.into_ref(vm)
PyCoroutine {
frame,
closed: Cell::new(false),
}
.into_ref(vm)
}
// TODO: deduplicate this code with objgenerator
fn maybe_close(&self, res: &PyResult<ExecutionResult>) {
match res {
Ok(ExecutionResult::Return(_)) | Err(_) => self.closed.set(true),
Ok(ExecutionResult::Yield(_)) => {}
}
}
#[pymethod]
pub(crate) fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if self.closed.get() {
return Err(new_stop_iteration(vm));
}
self.frame.push_value(value.clone());
vm.run_frame(self.frame.clone())?.into_result(vm)
let result = vm.run_frame(self.frame.clone());
self.maybe_close(&result);
result?.into_result(vm)
}
#[pymethod]
@@ -39,27 +61,31 @@ impl PyCoroutine {
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyResult {
if self.closed.get() {
return Err(vm.invoke(exc_type.as_object(), vec![])?);
}
// TODO what should we do with the other parameters? CPython normalises them with
// PyErr_NormalizeException, do we want to do the same.
if !issubclass(&exc_type, &vm.ctx.exceptions.base_exception_type) {
return Err(vm.new_type_error("Can't throw non exception".to_string()));
}
vm.frames.borrow_mut().push(self.frame.clone());
let result = self
.frame
.gen_throw(
vm,
exc_type,
exc_val.unwrap_or(vm.get_none()),
exc_tb.unwrap_or(vm.get_none()),
)
.and_then(|res| res.into_result(vm));
let result = self.frame.gen_throw(
vm,
exc_type,
exc_val.unwrap_or(vm.get_none()),
exc_tb.unwrap_or(vm.get_none()),
);
self.maybe_close(&result);
vm.frames.borrow_mut().pop();
result
result?.into_result(vm)
}
#[pymethod]
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
if self.closed.get() {
return Ok(());
}
vm.frames.borrow_mut().push(self.frame.clone());
let result = self.frame.gen_throw(
vm,
@@ -68,6 +94,7 @@ impl PyCoroutine {
vm.get_none(),
);
vm.frames.borrow_mut().pop();
self.closed.set(true);
match result {
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception(
vm.ctx.exceptions.runtime_error.clone(),

View File

@@ -2,18 +2,22 @@
* The mythical generator.
*/
use super::objiter::new_stop_iteration;
use super::objtype::{isinstance, issubclass, PyClassRef};
use crate::frame::{ExecutionResult, FrameRef};
use crate::function::OptionalArg;
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
use std::cell::Cell;
pub type PyGeneratorRef = PyRef<PyGenerator>;
#[pyclass(name = "generator")]
#[derive(Debug)]
pub struct PyGenerator {
frame: FrameRef,
closed: Cell<bool>,
}
impl PyValue for PyGenerator {
@@ -25,7 +29,18 @@ impl PyValue for PyGenerator {
#[pyimpl]
impl PyGenerator {
pub fn new(frame: FrameRef, vm: &VirtualMachine) -> PyGeneratorRef {
PyGenerator { frame }.into_ref(vm)
PyGenerator {
frame,
closed: Cell::new(false),
}
.into_ref(vm)
}
fn maybe_close(&self, res: &PyResult<ExecutionResult>) {
match res {
Ok(ExecutionResult::Return(_)) | Err(_) => self.closed.set(true),
Ok(ExecutionResult::Yield(_)) => {}
}
}
#[pymethod(name = "__iter__")]
@@ -40,9 +55,15 @@ impl PyGenerator {
#[pymethod]
pub(crate) fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if self.closed.get() {
return Err(new_stop_iteration(vm));
}
self.frame.push_value(value.clone());
vm.run_frame(self.frame.clone())?.into_result(vm)
let result = vm.run_frame(self.frame.clone());
self.maybe_close(&result);
result?.into_result(vm)
}
#[pymethod]
@@ -53,27 +74,31 @@ impl PyGenerator {
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyResult {
if self.closed.get() {
return Err(vm.invoke(exc_type.as_object(), vec![])?);
}
// TODO what should we do with the other parameters? CPython normalises them with
// PyErr_NormalizeException, do we want to do the same.
if !issubclass(&exc_type, &vm.ctx.exceptions.base_exception_type) {
return Err(vm.new_type_error("Can't throw non exception".to_string()));
}
vm.frames.borrow_mut().push(self.frame.clone());
let result = self
.frame
.gen_throw(
vm,
exc_type,
exc_val.unwrap_or(vm.get_none()),
exc_tb.unwrap_or(vm.get_none()),
)
.and_then(|res| res.into_result(vm));
let result = self.frame.gen_throw(
vm,
exc_type,
exc_val.unwrap_or(vm.get_none()),
exc_tb.unwrap_or(vm.get_none()),
);
self.maybe_close(&result);
vm.frames.borrow_mut().pop();
result
result?.into_result(vm)
}
#[pymethod]
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
if self.closed.get() {
return Ok(());
}
vm.frames.borrow_mut().push(self.frame.clone());
let result = self.frame.gen_throw(
vm,
@@ -82,6 +107,7 @@ impl PyGenerator {
vm.get_none(),
);
vm.frames.borrow_mut().pop();
self.closed.set(true);
match result {
Ok(ExecutionResult::Yield(_)) => Err(vm.new_exception(
vm.ctx.exceptions.runtime_error.clone(),

View File

@@ -70,7 +70,7 @@ pub fn get_all<T: TryFromObject>(vm: &VirtualMachine, iter_obj: &PyObjectRef) ->
pub fn new_stop_iteration(vm: &VirtualMachine) -> PyObjectRef {
let stop_iteration_type = vm.ctx.exceptions.stop_iteration.clone();
vm.new_exception(stop_iteration_type, "End of iterator".to_string())
vm.new_empty_exception(stop_iteration_type).unwrap()
}
pub fn stop_iter_value(vm: &VirtualMachine, exc: &PyObjectRef) -> PyResult {

View File

@@ -584,23 +584,23 @@ impl PyListRef {
}
}
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult {
fn delitem(self, subscript: SequenceIndex, vm: &VirtualMachine) -> PyResult<()> {
match subscript {
SequenceIndex::Int(index) => self.delindex(index, vm),
SequenceIndex::Slice(slice) => self.delslice(slice, vm),
}
}
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult {
fn delindex(self, index: i32, vm: &VirtualMachine) -> PyResult<()> {
if let Some(pos_index) = self.get_pos(index) {
self.elements.borrow_mut().remove(pos_index);
Ok(vm.get_none())
Ok(())
} else {
Err(vm.new_index_error("Index out of bounds!".to_string()))
}
}
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult {
fn delslice(self, slice: PySliceRef, vm: &VirtualMachine) -> PyResult<()> {
let start = slice.start_index(vm)?;
let stop = slice.stop_index(vm)?;
let step = slice.step_index(vm)?.unwrap_or_else(BigInt::one);
@@ -614,20 +614,20 @@ impl PyListRef {
match step.to_i32() {
Some(1) => {
self._del_slice(range);
Ok(vm.get_none())
Ok(())
}
Some(num) => {
self._del_stepped_slice(range, num as usize);
Ok(vm.get_none())
Ok(())
}
None => {
self._del_slice(range.start..range.start + 1);
Ok(vm.get_none())
Ok(())
}
}
} else {
// no del to do
Ok(vm.get_none())
Ok(())
}
} else {
// calculate the range for the reverse slice, first the bounds needs to be made
@@ -651,20 +651,20 @@ impl PyListRef {
match (-step).to_i32() {
Some(1) => {
self._del_slice(range);
Ok(vm.get_none())
Ok(())
}
Some(num) => {
self._del_stepped_slice_reverse(range, num as usize);
Ok(vm.get_none())
Ok(())
}
None => {
self._del_slice(range.end - 1..range.end);
Ok(vm.get_none())
Ok(())
}
}
} else {
// no del to do
Ok(vm.get_none())
Ok(())
}
}
}

View File

@@ -1,3 +1,4 @@
use super::objdict::PyDictRef;
use super::objiter;
use super::objstr::PyStringRef;
use super::objtype::{self, PyClassRef};
@@ -82,31 +83,44 @@ impl PyMappingProxy {
#[pymethod(name = "__iter__")]
pub fn iter(&self, vm: &VirtualMachine) -> PyResult {
match &self.mapping {
MappingProxyInner::Dict(d) => objiter::get_iter(vm, d),
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
}
let obj = match &self.mapping {
MappingProxyInner::Dict(d) => d.clone(),
MappingProxyInner::Class(c) => {
// TODO: something that's much more efficient than this
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
}
};
objiter::get_iter(vm, &obj)
}
#[pymethod]
pub fn items(&self, vm: &VirtualMachine) -> PyResult {
match &self.mapping {
MappingProxyInner::Dict(d) => vm.call_method(d, "items", vec![]),
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
}
let obj = match &self.mapping {
MappingProxyInner::Dict(d) => d.clone(),
MappingProxyInner::Class(c) => {
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
}
};
vm.call_method(&obj, "items", vec![])
}
#[pymethod]
pub fn keys(&self, vm: &VirtualMachine) -> PyResult {
match &self.mapping {
MappingProxyInner::Dict(d) => vm.call_method(d, "keys", vec![]),
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
}
let obj = match &self.mapping {
MappingProxyInner::Dict(d) => d.clone(),
MappingProxyInner::Class(c) => {
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
}
};
vm.call_method(&obj, "keys", vec![])
}
#[pymethod]
pub fn values(&self, vm: &VirtualMachine) -> PyResult {
match &self.mapping {
MappingProxyInner::Dict(d) => vm.call_method(d, "values", vec![]),
MappingProxyInner::Class(_c) => Err(vm.new_type_error("Can't get iter".to_string())),
}
let obj = match &self.mapping {
MappingProxyInner::Dict(d) => d.clone(),
MappingProxyInner::Class(c) => {
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
}
};
vm.call_method(&obj, "values", vec![])
}
}

View File

@@ -564,6 +564,12 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"MSG_WAITALL" => ctx.new_int(c::MSG_WAITALL),
"AI_ALL" => ctx.new_int(c::AI_ALL),
"AI_PASSIVE" => ctx.new_int(c::AI_PASSIVE),
"IPPROTO_TCP" => ctx.new_int(c::IPPROTO_TCP),
"IPPROTO_UDP" => ctx.new_int(c::IPPROTO_UDP),
"IPPROTO_IP" => ctx.new_int(c::IPPROTO_IP),
"IPPROTO_IPIP" => ctx.new_int(c::IPPROTO_IP),
"IPPROTO_IPV6" => ctx.new_int(c::IPPROTO_IPV6),
"IPPROTO_NONE" => ctx.new_int(c::IPPROTO_NONE),
"socket" => PySocket::make_class(ctx),
"inet_aton" => ctx.new_rustfunc(socket_inet_aton),
"inet_ntoa" => ctx.new_rustfunc(socket_inet_ntoa),

View File

@@ -449,8 +449,12 @@ impl VirtualMachine {
// Container of the virtual machine state:
pub fn to_str(&self, obj: &PyObjectRef) -> PyResult<PyStringRef> {
let str = self.call_method(&obj, "__str__", vec![])?;
TryFromObject::try_from_object(self, str)
if obj.class().is(&self.ctx.types.str_type) {
Ok(obj.clone().downcast().unwrap())
} else {
let s = self.call_method(&obj, "__str__", vec![])?;
PyStringRef::try_from_object(self, s)
}
}
pub fn to_pystr<'a, T: Into<&'a PyObjectRef>>(&'a self, obj: T) -> PyResult<String> {