Skip to content

Commit b7a11df

Browse files
authored
Merge pull request RustPython#1354 from ChJR/feature/__bool__
Improve __bool__
2 parents c5ce1bb + da02029 commit b7a11df

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

tests/snippets/bools.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,39 @@ def __len__(self):
142142

143143

144144
with assertRaises(TypeError):
145-
bool(TestLenThrowError())
145+
bool(TestLenThrowError())
146+
147+
# Verify that TypeError occurs when bad things are returned
148+
# from __bool__(). This isn't really a bool test, but
149+
# it's related.
150+
def check(o):
151+
with assertRaises(TypeError):
152+
bool(o)
153+
154+
class Foo(object):
155+
def __bool__(self):
156+
return self
157+
check(Foo())
158+
159+
class Bar(object):
160+
def __bool__(self):
161+
return "Yes"
162+
check(Bar())
163+
164+
class Baz(int):
165+
def __bool__(self):
166+
return self
167+
check(Baz())
168+
169+
# __bool__() must return a bool not an int
170+
class Spam(int):
171+
def __bool__(self):
172+
return 1
173+
check(Spam())
174+
175+
class Eggs:
176+
def __len__(self):
177+
return -1
178+
179+
with assertRaises(ValueError):
180+
bool(Eggs())

vm/src/obj/objbool.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use num_bigint::Sign;
12
use num_traits::Zero;
23

34
use crate::function::PyFuncArgs;
@@ -29,22 +30,30 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
2930
// If descriptor returns Error, propagate it further
3031
let method = method_or_err?;
3132
let bool_obj = vm.invoke(&method, PyFuncArgs::default())?;
32-
match bool_obj.payload::<PyInt>() {
33-
Some(int_obj) => !int_obj.as_bigint().is_zero(),
34-
None => {
35-
return Err(vm.new_type_error(format!(
36-
"__bool__ should return bool, returned type {}",
37-
bool_obj.class().name
38-
)))
39-
}
33+
if !objtype::isinstance(&bool_obj, &vm.ctx.bool_type()) {
34+
return Err(vm.new_type_error(format!(
35+
"__bool__ should return bool, returned type {}",
36+
bool_obj.class().name
37+
)));
4038
}
39+
40+
get_value(&bool_obj)
4141
}
4242
None => match vm.get_method(obj.clone(), "__len__") {
4343
Some(method_or_err) => {
4444
let method = method_or_err?;
4545
let bool_obj = vm.invoke(&method, PyFuncArgs::default())?;
4646
match bool_obj.payload::<PyInt>() {
47-
Some(int_obj) => !int_obj.as_bigint().is_zero(),
47+
Some(int_obj) => {
48+
let len_val = int_obj.as_bigint();
49+
if len_val.sign() == Sign::Minus {
50+
return Err(
51+
vm.new_value_error("__len__() should return >= 0".to_string())
52+
);
53+
}
54+
55+
!len_val.is_zero()
56+
}
4857
None => {
4958
return Err(vm.new_type_error(format!(
5059
"{} object cannot be interpreted as integer",

0 commit comments

Comments
 (0)