Fix bytes constructor

This commit is contained in:
Jeong YunWon authored and Jeong, YunWon committed 2025-06-22 17:40:04 +09:00
1 parent 3a54105e2c
commit 44d312419a
2 files changed
+40 -19

No files matched your search

-2
View File
@@ -209,8 +209,6 @@ class BaseBytesTest:
except (OverflowError, MemoryError):
pass
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_constructor_exceptions(self):
# Issue #34974: bytes and bytearray constructors replace unexpected
# exceptions.
+40 -17
View File
@@ -21,6 +21,9 @@ use itertools::Itertools;
use malachite_bigint::BigInt;
use num_traits::ToPrimitive;
const STRING_WITHOUT_ENCODING: &str = "string argument without an encoding";
const ENCODING_WITHOUT_STRING: &str = "encoding without a string argument";
#[derive(Debug, Default, Clone)]
pub struct PyBytesInner {
pub(super) elements: Vec<u8>,
@@ -75,6 +78,18 @@ impl ByteInnerNewOptions {
Ok(vec![0; size].into())
}
fn handle_object_fallback(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyBytesInner> {
match_class!(match obj {
i @ PyInt => {
Self::get_value_from_size(i, vm)
}
_s @ PyStr => Err(vm.new_type_error(STRING_WITHOUT_ENCODING.to_owned())),
obj => {
Self::get_value_from_source(obj, vm)
}
})
}
pub fn get_bytes(self, cls: PyTypeRef, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
let inner = match (&self.source, &self.encoding, &self.errors) {
(OptionalArg::Present(obj), OptionalArg::Missing, OptionalArg::Missing) => {
@@ -113,40 +128,48 @@ impl ByteInnerNewOptions {
}
pub fn get_bytearray_inner(self, vm: &VirtualMachine) -> PyResult<PyBytesInner> {
const STRING_WITHOUT_ENCODING: &str = "string argument without an encoding";
const ENCODING_WITHOUT_STRING: &str = "encoding without a string argument";
match (self.source, self.encoding, self.errors) {
(OptionalArg::Present(obj), OptionalArg::Missing, OptionalArg::Missing) => {
match_class!(match obj {
i @ PyInt => {
Ok(Self::get_value_from_size(i, vm)?)
// Try __index__ first to handle int-like objects that might raise custom exceptions
if let Some(index_result) = obj.try_index_opt(vm) {
match index_result {
Ok(index) => Self::get_value_from_size(index, vm),
Err(e) => {
// Only propagate non-TypeError exceptions
// TypeError means the object doesn't support __index__, so fall back
if e.fast_isinstance(vm.ctx.exceptions.type_error) {
// Fall back to treating as buffer-like object
Self::handle_object_fallback(obj, vm)
} else {
// Propagate other exceptions (e.g., ZeroDivisionError)
Err(e)
}
}
}
_s @ PyStr => Err(STRING_WITHOUT_ENCODING),
obj => {
Ok(Self::get_value_from_source(obj, vm)?)
}
})
} else {
Self::handle_object_fallback(obj, vm)
}
}
(OptionalArg::Present(obj), OptionalArg::Present(encoding), errors) => {
if let Ok(s) = obj.downcast::<PyStr>() {
Ok(Self::get_value_from_string(s, encoding, errors, vm)?)
Self::get_value_from_string(s, encoding, errors, vm)
} else {
Err(ENCODING_WITHOUT_STRING)
Err(vm.new_type_error(ENCODING_WITHOUT_STRING.to_owned()))
}
}
(OptionalArg::Missing, OptionalArg::Missing, OptionalArg::Missing) => {
Ok(PyBytesInner::default())
}
(OptionalArg::Missing, OptionalArg::Present(_), _) => Err(ENCODING_WITHOUT_STRING),
(OptionalArg::Missing, OptionalArg::Present(_), _) => {
Err(vm.new_type_error(ENCODING_WITHOUT_STRING.to_owned()))
}
(OptionalArg::Missing, _, OptionalArg::Present(_)) => {
Err("errors without a string argument")
Err(vm.new_type_error("errors without a string argument".to_owned()))
}
(OptionalArg::Present(_), OptionalArg::Missing, OptionalArg::Present(_)) => {
Err(STRING_WITHOUT_ENCODING)
Err(vm.new_type_error(STRING_WITHOUT_ENCODING.to_owned()))
}
}
.map_err(|e| vm.new_type_error(e.to_owned()))
}
}