forked from Rust-related/RustPython
21
tests/snippets/builtin_round.py
Normal file
21
tests/snippets/builtin_round.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from testutils import assertRaises
|
||||
|
||||
assert round(0) == 0
|
||||
assert isinstance(round(0), int)
|
||||
assert round(0.0) == 0
|
||||
assert isinstance(round(0.0), int)
|
||||
|
||||
assert round(0, None) == 0
|
||||
assert isinstance(round(0, None), int)
|
||||
assert round(0.0, None) == 0
|
||||
assert isinstance(round(0, None), int)
|
||||
|
||||
assert round(0, 0) == 0
|
||||
assert isinstance(round(0, 0), int)
|
||||
assert round(0.0, 0) == 0.0 # Cannot check the type
|
||||
assert isinstance(round(0.0, 0), float)
|
||||
|
||||
with assertRaises(TypeError):
|
||||
round(0, 0.0)
|
||||
with assertRaises(TypeError):
|
||||
round(0.0, 0.0)
|
||||
@@ -151,12 +151,20 @@ assert float(1.2) == 1.2
|
||||
assert math.trunc(1.2) == 1
|
||||
assert_raises(OverflowError, float('inf').__trunc__)
|
||||
assert_raises(ValueError, float('nan').__trunc__)
|
||||
assert 0.5.__round__() == 0.0
|
||||
assert 1.5.__round__() == 2.0
|
||||
assert isinstance(0.5.__round__(), int)
|
||||
assert isinstance(1.5.__round__(), int)
|
||||
assert 0.5.__round__() == 0
|
||||
assert 1.5.__round__() == 2
|
||||
assert isinstance(0.5.__round__(0), float)
|
||||
assert isinstance(1.5.__round__(0), float)
|
||||
assert 0.5.__round__(0) == 0.0
|
||||
assert 1.5.__round__(0) == 2.0
|
||||
assert 0.5.__round__(None) == 0.0
|
||||
assert 1.5.__round__(None) == 2.0
|
||||
assert isinstance(0.5.__round__(None), int)
|
||||
assert isinstance(1.5.__round__(None), int)
|
||||
assert 0.5.__round__(None) == 0
|
||||
assert 1.5.__round__(None) == 2
|
||||
assert_raises(TypeError, lambda: 0.5.__round__(0.0))
|
||||
assert_raises(TypeError, lambda: 1.5.__round__(0.0))
|
||||
assert_raises(OverflowError, float('inf').__round__)
|
||||
assert_raises(ValueError, float('nan').__round__)
|
||||
|
||||
|
||||
@@ -167,3 +167,16 @@ class F(float):
|
||||
return 3
|
||||
|
||||
assert int(F(1.2)) == 3
|
||||
|
||||
assert isinstance((0).__round__(), int)
|
||||
assert isinstance((1).__round__(), int)
|
||||
assert (0).__round__() == 0
|
||||
assert (1).__round__() == 1
|
||||
assert isinstance((0).__round__(0), int)
|
||||
assert isinstance((1).__round__(0), int)
|
||||
assert (0).__round__(0) == 0
|
||||
assert (1).__round__(0) == 1
|
||||
assert_raises(TypeError, lambda: (0).__round__(None))
|
||||
assert_raises(TypeError, lambda: (1).__round__(None))
|
||||
assert_raises(TypeError, lambda: (0).__round__(0.0))
|
||||
assert_raises(TypeError, lambda: (1).__round__(0.0))
|
||||
@@ -734,9 +734,19 @@ fn builtin_round(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
optional = [(ndigits, None)]
|
||||
);
|
||||
if let Some(ndigits) = ndigits {
|
||||
let ndigits = vm.call_method(ndigits, "__int__", vec![])?;
|
||||
let rounded = vm.call_method(number, "__round__", vec![ndigits])?;
|
||||
Ok(rounded)
|
||||
if objtype::isinstance(ndigits, &vm.ctx.int_type()) {
|
||||
let ndigits = vm.call_method(ndigits, "__int__", vec![])?;
|
||||
let rounded = vm.call_method(number, "__round__", vec![ndigits])?;
|
||||
Ok(rounded)
|
||||
} else if vm.ctx.none().is(ndigits) {
|
||||
let rounded = &vm.call_method(number, "__round__", vec![])?;
|
||||
Ok(vm.ctx.new_int(objint::get_value(rounded).clone()))
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
ndigits.class().name
|
||||
)))
|
||||
}
|
||||
} else {
|
||||
// without a parameter, the result type is coerced to int
|
||||
let rounded = &vm.call_method(number, "__round__", vec![])?;
|
||||
|
||||
@@ -440,25 +440,38 @@ impl PyFloat {
|
||||
OptionalArg::Missing => None,
|
||||
OptionalArg::Present(ref value) => {
|
||||
if !vm.get_none().is(value) {
|
||||
let ndigits = if objtype::isinstance(value, &vm.ctx.int_type()) {
|
||||
objint::get_value(value)
|
||||
} else {
|
||||
if !objtype::isinstance(value, &vm.ctx.int_type()) {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"TypeError: '{}' object cannot be interpreted as an integer",
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
value.class().name
|
||||
)));
|
||||
};
|
||||
if ndigits.is_zero() {
|
||||
None
|
||||
} else {
|
||||
Some(ndigits)
|
||||
}
|
||||
// Only accept int type ndigits
|
||||
let ndigits = objint::get_value(value);
|
||||
Some(ndigits)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
if ndigits.is_none() {
|
||||
|
||||
if let Some(ndigits) = ndigits {
|
||||
if ndigits.is_zero() {
|
||||
let fract = self.value.fract();
|
||||
let value = if (fract.abs() - 0.5).abs() < std::f64::EPSILON {
|
||||
if self.value.trunc() % 2.0 == 0.0 {
|
||||
self.value - fract
|
||||
} else {
|
||||
self.value + fract
|
||||
}
|
||||
} else {
|
||||
self.value.round()
|
||||
};
|
||||
Ok(vm.ctx.new_float(value))
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
} else {
|
||||
let fract = self.value.fract();
|
||||
let value = if (fract.abs() - 0.5).abs() < std::f64::EPSILON {
|
||||
if self.value.trunc() % 2.0 == 0.0 {
|
||||
@@ -471,8 +484,6 @@ impl PyFloat {
|
||||
};
|
||||
let int = try_to_bigint(value, vm)?;
|
||||
Ok(vm.ctx.new_int(int))
|
||||
} else {
|
||||
Ok(vm.ctx.not_implemented())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ use crate::function::{KwArgs, OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objtype::PyClassRef;
|
||||
use crate::pyhash;
|
||||
use crate::pyobject::{
|
||||
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
TypeProtocol,
|
||||
IdProtocol, IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
|
||||
TryFromObject, TypeProtocol,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
use super::objbyteinner::PyByteInner;
|
||||
use super::objbytes::PyBytes;
|
||||
use super::objint;
|
||||
use super::objstr::{PyString, PyStringRef};
|
||||
use super::objtype;
|
||||
|
||||
@@ -468,8 +469,29 @@ impl PyInt {
|
||||
zelf: PyRef<Self>,
|
||||
_precision: OptionalArg<PyObjectRef>,
|
||||
_vm: &VirtualMachine,
|
||||
) -> PyIntRef {
|
||||
zelf
|
||||
) -> PyResult<PyIntRef> {
|
||||
let _ndigits = match _precision {
|
||||
OptionalArg::Missing => None,
|
||||
OptionalArg::Present(ref value) => {
|
||||
if !_vm.get_none().is(value) {
|
||||
if !objtype::isinstance(value, &_vm.ctx.int_type()) {
|
||||
return Err(_vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
value.class().name
|
||||
)));
|
||||
};
|
||||
// Only accept int type _ndigits
|
||||
let _ndigits = objint::get_value(value);
|
||||
Some(_ndigits)
|
||||
} else {
|
||||
return Err(_vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
value.class().name
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(zelf)
|
||||
}
|
||||
|
||||
#[pymethod(name = "__int__")]
|
||||
|
||||
Reference in New Issue
Block a user