diff --git a/vm/src/byteslike.rs b/vm/src/byteslike.rs index 19b5887dd..0d48ebf3c 100644 --- a/vm/src/byteslike.rs +++ b/vm/src/byteslike.rs @@ -47,6 +47,12 @@ impl PyRwBytesLike { } } +impl PyBytesLike { + pub fn into_buffer(self) -> BufferRef { + self.0 + } +} + impl TryFromObject for PyBytesLike { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { let buffer = try_buffer_from_object(vm, &obj)?; @@ -88,8 +94,8 @@ pub fn try_rw_bytes_like( .ok_or_else(|| vm.new_type_error("buffer is not a read-write bytes-like object".to_owned())) } -impl TryFromObject for PyRwBytesLike { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { +impl PyRwBytesLike { + pub fn new(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult { let buffer = try_buffer_from_object(vm, &obj)?; if !buffer.get_options().contiguous { Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned())) @@ -99,6 +105,16 @@ impl TryFromObject for PyRwBytesLike { Ok(Self(buffer)) } } + + pub fn into_buffer(self) -> BufferRef { + self.0 + } +} + +impl TryFromObject for PyRwBytesLike { + fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + Self::new(vm, &obj) + } } impl<'a> BorrowValue<'a> for PyRwBytesLike { diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 667edd429..069c2b8b1 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -152,6 +152,17 @@ impl PyBaseException { } } +pub fn chain(e1: PyResult<()>, e2: PyResult) -> PyResult { + match (e1, e2) { + (Err(e1), Err(e)) => { + e.set_context(Some(e1)); + Err(e) + } + (Err(e), Ok(_)) | (Ok(()), Err(e)) => Err(e), + (Ok(()), Ok(close_res)) => Ok(close_res), + } +} + /// Print exception chain by calling sys.excepthook pub fn print_exception(vm: &VirtualMachine, exc: PyBaseExceptionRef) { let write_fallback = |exc, errstr| { diff --git a/vm/src/frame.rs b/vm/src/frame.rs index a2168333f..a229e190b 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -865,7 +865,15 @@ impl ExecutingFrame<'_> { return Ok(None); } } - BlockType::FinallyHandler { .. } => { + BlockType::FinallyHandler { + reason: finally_reason, + } => { + if let Some(UnwindReason::Raising { exception }) = finally_reason { + let finally_exc = exception; + if let UnwindReason::Raising { exception } = &reason { + exception.set_context(Some(finally_exc)) + } + } self.pop_block(); } BlockType::ExceptHandler => { diff --git a/vm/src/function.rs b/vm/src/function.rs index aff0f6523..8153d182f 100644 --- a/vm/src/function.rs +++ b/vm/src/function.rs @@ -187,25 +187,8 @@ impl FuncArgs { /// during the conversion will halt the binding and return the error. pub fn bind(mut self, vm: &VirtualMachine) -> PyResult { let given_args = self.args.len(); - let bound = T::from_args(vm, &mut self).map_err(|e| match e { - ArgumentError::TooFewArgs => vm.new_type_error(format!( - "Expected at least {} arguments ({} given)", - T::arity().start(), - given_args, - )), - ArgumentError::TooManyArgs => vm.new_type_error(format!( - "Expected at most {} arguments ({} given)", - T::arity().end(), - given_args, - )), - ArgumentError::InvalidKeywordArgument(name) => { - vm.new_type_error(format!("{} is an invalid keyword argument", name)) - } - ArgumentError::RequiredKeywordArgument(name) => { - vm.new_type_error(format!("Required keyqord only argument {}", name)) - } - ArgumentError::Exception(ex) => ex, - })?; + let bound = T::from_args(vm, &mut self) + .map_err(|e| e.into_exception(T::arity(), given_args, vm))?; if !self.args.is_empty() { Err(vm.new_type_error(format!( @@ -243,6 +226,35 @@ impl From for ArgumentError { } } +impl ArgumentError { + fn into_exception( + self, + arity: RangeInclusive, + num_given: usize, + vm: &VirtualMachine, + ) -> PyBaseExceptionRef { + match self { + ArgumentError::TooFewArgs => vm.new_type_error(format!( + "Expected at least {} arguments ({} given)", + arity.start(), + num_given + )), + ArgumentError::TooManyArgs => vm.new_type_error(format!( + "Expected at most {} arguments ({} given)", + arity.end(), + num_given + )), + ArgumentError::InvalidKeywordArgument(name) => { + vm.new_type_error(format!("{} is an invalid keyword argument", name)) + } + ArgumentError::RequiredKeywordArgument(name) => { + vm.new_type_error(format!("Required keyqord only argument {}", name)) + } + ArgumentError::Exception(ex) => ex, + } + } +} + /// Implemented by any type that can be accepted as a parameter to a built-in /// function. /// @@ -439,7 +451,7 @@ impl OptionalArg { } } -pub type OptionalOption = OptionalArg>; +pub type OptionalOption = OptionalArg>; impl OptionalOption { #[inline]