Merge branch 'master' into dev3

This commit is contained in:
Steve Shi authored and GitHub committed 2020-08-31 19:28:09 +02:00
commit ff05200faf
6 files changed
+203 -26

No files matched your search

+4 -7
View File
@@ -25,7 +25,10 @@ class ArraySubclassWithKwargs(array.array):
def __init__(self, typecode, newarg=None):
array.array.__init__(self)
typecodes = 'ubBhHiIlLfdqQ'
# TODO: RUSTPYTHON
# We did not support typecode u for unicode yet
# typecodes = 'ubBhHiIlLfdqQ'
typecodes = 'bBhHiIlLfdqQ'
class MiscTest(unittest.TestCase):
@@ -497,8 +500,6 @@ class BaseTest:
b = array.array(self.typecode, a)
self.assertEqual(a, b)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_repr(self):
a = array.array(self.typecode, 2*self.example)
self.assertEqual(a, eval(repr(a), {"array": array.array}))
@@ -801,8 +802,6 @@ class BaseTest:
self.assertEqual(list(a[start:stop:step]),
list(a)[start:stop:step])
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_setslice(self):
a = array.array(self.typecode, self.example)
a[:1] = a
@@ -1235,8 +1234,6 @@ class NumberTest(BaseTest):
a = array.array(self.typecode, range(10))
del a[9::1<<333]
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_assignment(self):
a = array.array(self.typecode, range(10))
a[::2] = array.array(self.typecode, [42]*5)
+14
View File
@@ -32,3 +32,17 @@ def test_float_with_integer_input():
assert f == array("f", [-2, 0, 2, 3, 4])
test_float_with_integer_input()
# slice assignment step overflow behaviour test
T = 'I'
a = array(T, range(10))
b = array(T, [100])
a[::9999999999] = b
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 9])
a[::-9999999999] = b
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
c = array(T)
a[0:0:9999999999] = c
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
a[0:0:-9999999999] = c
assert a == array(T, [100, 1, 2, 3, 4, 5, 6, 7, 8, 100])
+1 -3
View File
@@ -252,13 +252,11 @@ impl PyBytesInner {
let mut res = String::with_capacity(self.elements.len());
for i in self.elements.iter() {
match i {
0..=8 => res.push_str(&format!("\\x0{}", i)),
9 => res.push_str("\\t"),
10 => res.push_str("\\n"),
11 => res.push_str(&format!("\\x0{:x}", i)),
13 => res.push_str("\\r"),
32..=126 => res.push(*(i) as char),
_ => res.push_str(&format!("\\x{:x}", i)),
_ => res.push_str(&format!("\\x{:02x}", i)),
}
}
res
+158 -16
View File
@@ -5,18 +5,21 @@ use crate::common::cell::{
use crate::function::OptionalArg;
use crate::obj::objbytes::PyBytesRef;
use crate::obj::objfloat::try_float;
use crate::obj::objsequence::PySliceableSequence;
use crate::obj::objsequence::{get_slice_range, PySliceableSequence};
use crate::obj::objslice::PySliceRef;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::obj::{objbool, objiter};
use crate::pyobject::{
BorrowValue, Either, IntoPyObject, PyArithmaticValue, PyClassImpl, PyComparisonValue,
PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
BorrowValue, Either, IdProtocol, IntoPyObject, PyArithmaticValue, PyClassImpl,
PyComparisonValue, PyIterable, PyObject, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
TypeProtocol,
};
use crate::VirtualMachine;
use crossbeam_utils::atomic::AtomicCell;
use itertools::Itertools;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
use std::fmt;
struct ArrayTypeSpecifierError {
@@ -34,7 +37,7 @@ impl fmt::Display for ArrayTypeSpecifierError {
macro_rules! def_array_enum {
($(($n:ident, $t:ident, $c:literal)),*$(,)?) => {
#[derive(Debug)]
#[derive(Debug, Clone)]
enum ArrayContentType {
$($n(Vec<$t>),)*
}
@@ -230,18 +233,128 @@ macro_rules! def_array_enum {
Either::B(slice) => self.getitem_by_slice(slice, vm),
}
}
fn setitem_by_slice(&mut self, slice: PySliceRef, items: &ArrayContentType, 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);
fn setitem(&mut self, needle: Either<isize, PySliceRef>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
match needle {
Either::A(i) => {
let i = self.idx(i, "array assignment", vm)?;
match self {
$(ArrayContentType::$n(v) => { v[i] = $t::try_into_from_object(vm, value)? },)*
}
Ok(())
}
Either::B(_slice) => Err(vm.new_not_implemented_error("array slice is not implemented".to_owned())),
if step.is_zero() {
return Err(vm.new_value_error("slice step cannot be zero".to_owned()));
}
match self {
$(ArrayContentType::$n(elements) => if let ArrayContentType::$n(items) = items {
if step == BigInt::one() {
let range = get_slice_range(&start, &stop, elements.len());
let range = if range.end < range.start {
range.start..range.start
} else {
range
};
elements.splice(range, items.iter().cloned());
return Ok(());
}
let (start, stop, step, is_negative_step) = if step.is_negative() {
(
stop.map(|x| if x == -BigInt::one() {
elements.len() + BigInt::one()
} else {
x + 1
}),
start.map(|x| if x == -BigInt::one() {
BigInt::from(elements.len())
} else {
x + 1
}),
-step,
true
)
} else {
(start, stop, step, false)
};
let range = get_slice_range(&start, &stop, elements.len());
let range = if range.end < range.start {
range.start..range.start
} else {
range
};
// step is not negative here
if let Some(step) = step.to_usize() {
let slicelen = if range.end > range.start {
(range.end - range.start - 1) / step + 1
} else {
0
};
if slicelen == items.len() {
if is_negative_step {
for (i, &item) in range.rev().step_by(step).zip(items) {
elements[i] = item;
}
} else {
for (i, &item) in range.step_by(step).zip(items) {
elements[i] = item;
}
}
Ok(())
} else {
Err(vm.new_value_error(format!(
"attempt to assign sequence of size {} to extended slice of size {}",
items.len(), slicelen
)))
}
} else {
// edge case, step is too big for usize
// same behaviour as CPython
let slicelen = if range.start < range.end { 1 } else { 0 };
if match items.len() {
0 => slicelen == 0,
1 => {
elements[
if is_negative_step { range.end - 1 } else { range.start }
] = items[0];
true
},
_ => false,
} {
Ok(())
} else {
Err(vm.new_value_error(format!(
"attempt to assign sequence of size {} to extended slice of size {}",
items.len(), slicelen
)))
}
}
} else {
Err(vm.new_type_error("bad argument type for built-in operation".to_owned()))
},)*
}
}
fn setitem_by_idx(&mut self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let i = self.idx(i, "array assignment", vm)?;
match self {
$(ArrayContentType::$n(v) => { v[i] = TryFromObject::try_from_object(vm, value)? },)*
}
Ok(())
}
fn repr(&self, _vm: &VirtualMachine) -> PyResult<String> {
// we don't need ReprGuard here
let s = match self {
$(ArrayContentType::$n(v) => {
if v.is_empty() {
format!("array('{}')", $c)
} else {
format!("array('{}', [{}])", $c, v.iter().format(", "))
}
})*
};
Ok(s)
}
fn iter<'a>(&'a self, vm: &'a VirtualMachine) -> impl Iterator<Item = PyObjectRef> + 'a {
@@ -479,12 +592,41 @@ impl PyArray {
#[pymethod(magic)]
fn setitem(
&self,
zelf: PyRef<Self>,
needle: Either<isize, PySliceRef>,
obj: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
self.borrow_value_mut().setitem(needle, obj, vm)
match needle {
Either::A(i) => zelf.borrow_value_mut().setitem_by_idx(i, obj, vm),
Either::B(slice) => {
let cloned;
let guard;
let items = if zelf.is(&obj) {
cloned = zelf.borrow_value().clone();
&cloned
} else {
match obj.payload::<PyArray>() {
Some(array) => {
guard = array.borrow_value();
&*guard
}
None => {
return Err(vm.new_type_error(format!(
"can only assign array (not \"{}\") to array slice",
obj.class().name
)));
}
}
};
zelf.borrow_value_mut().setitem_by_slice(slice, items, vm)
}
}
}
#[pymethod(name = "__repr__")]
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
zelf.borrow_value().repr(vm)
}
#[pymethod(name = "__eq__")]
+8
View File
@@ -719,6 +719,14 @@ mod _os {
std::process::exit(code)
}
#[pyfunction]
fn abort() {
extern "C" {
fn abort();
}
unsafe { abort() }
}
#[pyfunction]
fn urandom(size: usize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
let mut buf = vec![0u8; size];
+18
View File
@@ -579,6 +579,23 @@ fn socket_gethostbyaddr(
))
}
#[cfg(not(target_os = "redox"))]
fn socket_gethostbyname(name: PyStringRef, vm: &VirtualMachine) -> PyResult<String> {
match socket_gethostbyaddr(name, vm) {
Ok((_, _, hosts)) => {
let lst = vm.extract_elements::<PyStringRef>(&hosts)?;
Ok(lst.get(0).unwrap().to_string())
}
Err(_) => {
let error_type = vm.class("_socket", "gaierror");
Err(vm.new_exception_msg(
error_type,
"nodename nor servname provided, or not known".to_owned(),
))
}
}
}
fn get_addr<T, I>(vm: &VirtualMachine, addr: T) -> PyResult<socket2::SockAddr>
where
T: ToSocketAddrs<Iter = I>,
@@ -707,6 +724,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
extend_module!(vm, module, {
"getaddrinfo" => ctx.new_function(socket_getaddrinfo),
"gethostbyaddr" => ctx.new_function(socket_gethostbyaddr),
"gethostbyname" => ctx.new_function(socket_gethostbyname),
});
extend_module_platform_specific(vm, &module);