Skip to content

Commit c150a43

Browse files
authored
Merge pull request RustPython#1778 from youknowone/int-indexable-base
non-int indexable base for int()
2 parents a6c84c2 + 4be3a36 commit c150a43

File tree

4 files changed

+42
-24
lines changed

4 files changed

+42
-24
lines changed

Lib/test/test_int.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,6 @@ def test_int_base_bad_types(self):
280280
with self.assertRaises(TypeError):
281281
int('0', 5.0)
282282

283-
@unittest.skip("TODO: RUSTPYTHON")
284283
def test_int_base_indexable(self):
285284
class MyIndexable(object):
286285
def __init__(self, value):

vm/src/obj/objint.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -659,12 +659,13 @@ struct IntOptions {
659659
#[pyarg(positional_only, optional = true)]
660660
val_options: OptionalArg<PyObjectRef>,
661661
#[pyarg(positional_or_keyword, optional = true)]
662-
base: OptionalArg<PyIntRef>,
662+
base: OptionalArg<PyObjectRef>,
663663
}
664664

665665
impl IntOptions {
666666
fn get_int_value(self, vm: &VirtualMachine) -> PyResult<BigInt> {
667667
if let OptionalArg::Present(val) = self.val_options {
668+
// FIXME: unnessessary bigint clone/creation
668669
let base = if let OptionalArg::Present(base) = self.base {
669670
if !(objtype::isinstance(&val, &vm.ctx.str_type())
670671
|| objtype::isinstance(&val, &vm.ctx.bytes_type()))
@@ -673,11 +674,17 @@ impl IntOptions {
673674
"int() can't convert non-string with explicit base".to_owned(),
674675
));
675676
}
676-
base
677+
let base = vm.to_index(&base).unwrap_or_else(|| {
678+
Err(vm.new_type_error(format!(
679+
"'{}' object cannot be interpreted as an integer missing string argument",
680+
base.class().name
681+
)))
682+
})?;
683+
base.as_bigint().clone()
677684
} else {
678-
PyInt::new(10).into_ref(vm)
685+
BigInt::from(10)
679686
};
680-
to_int(vm, &val, base.as_bigint())
687+
to_int(vm, &val, &base)
681688
} else if let OptionalArg::Present(_) = self.base {
682689
Err(vm.new_type_error("int() missing string argument".to_owned()))
683690
} else {

vm/src/obj/objslice.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use super::objtype::PyClassRef;
33
use crate::function::{OptionalArg, PyFuncArgs};
44
use crate::pyobject::{
55
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryIntoRef,
6-
TypeProtocol,
76
};
87
use crate::vm::VirtualMachine;
98
use num_bigint::{BigInt, ToBigInt};
@@ -323,23 +322,12 @@ fn to_index_value(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Option<Big
323322
return Ok(None);
324323
}
325324

326-
if let Some(val) = obj.payload::<PyInt>() {
327-
Ok(Some(val.as_bigint().clone()))
328-
} else {
329-
let cls = obj.class();
330-
if cls.has_attr("__index__") {
331-
let index_result = vm.call_method(obj, "__index__", vec![])?;
332-
if let Some(val) = index_result.payload::<PyInt>() {
333-
Ok(Some(val.as_bigint().clone()))
334-
} else {
335-
Err(vm.new_type_error("__index__ method returned non integer".to_owned()))
336-
}
337-
} else {
338-
Err(vm.new_type_error(
339-
"slice indices must be integers or None or have an __index__ method".to_owned(),
340-
))
341-
}
342-
}
325+
let result = vm.to_index(obj).unwrap_or_else(|| {
326+
Err(vm.new_type_error(
327+
"slice indices must be integers or None or have an __index__ method".to_owned(),
328+
))
329+
})?;
330+
Ok(Some(result.as_bigint().clone()))
343331
}
344332

345333
pub fn init(context: &PyContext) {

vm/src/vm.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::import;
2929
use crate::obj::objbool;
3030
use crate::obj::objcode::{PyCode, PyCodeRef};
3131
use crate::obj::objdict::PyDictRef;
32-
use crate::obj::objint::PyInt;
32+
use crate::obj::objint::{PyInt, PyIntRef};
3333
use crate::obj::objiter;
3434
use crate::obj::objlist::PyList;
3535
use crate::obj::objmodule::{self, PyModule};
@@ -601,6 +601,30 @@ impl VirtualMachine {
601601
Ok(self.new_str(ascii))
602602
}
603603

604+
pub fn to_index(&self, obj: &PyObjectRef) -> Option<PyResult<PyIntRef>> {
605+
Some(
606+
if let Ok(val) = TryFromObject::try_from_object(self, obj.clone()) {
607+
Ok(val)
608+
} else {
609+
let cls = obj.class();
610+
if cls.has_attr("__index__") {
611+
self.call_method(obj, "__index__", vec![]).and_then(|r| {
612+
if let Ok(val) = TryFromObject::try_from_object(self, r) {
613+
Ok(val)
614+
} else {
615+
Err(self.new_type_error(format!(
616+
"__index__ returned non-int (type {})",
617+
cls.name
618+
)))
619+
}
620+
})
621+
} else {
622+
return None;
623+
}
624+
},
625+
)
626+
}
627+
604628
pub fn import(&self, module: &str, from_list: &[String], level: usize) -> PyResult {
605629
// if the import inputs seem weird, e.g a package import or something, rather than just
606630
// a straight `import ident`

0 commit comments

Comments
 (0)