Prepare exception for reraise in except* block. Implements _PyExc_PrepReraiseStar
(orig: PyObjectRef, excs: PyObjectRef, vm: &VirtualMachine)
| 2821 | /// Prepare exception for reraise in except* block. |
| 2822 | /// Implements _PyExc_PrepReraiseStar |
| 2823 | pub fn prep_reraise_star(orig: PyObjectRef, excs: PyObjectRef, vm: &VirtualMachine) -> PyResult { |
| 2824 | use crate::builtins::PyList; |
| 2825 | |
| 2826 | let excs_list = excs |
| 2827 | .downcast::<PyList>() |
| 2828 | .map_err(|_| vm.new_type_error("expected list for prep_reraise_star"))?; |
| 2829 | |
| 2830 | let excs_vec: Vec<PyObjectRef> = excs_list.borrow_vec().to_vec(); |
| 2831 | |
| 2832 | // If no exceptions to process, return None |
| 2833 | if excs_vec.is_empty() { |
| 2834 | return Ok(vm.ctx.none()); |
| 2835 | } |
| 2836 | |
| 2837 | // Special case: naked exception (not an ExceptionGroup) |
| 2838 | // Only one except* clause could have executed, so there's at most one exception to raise |
| 2839 | if !orig.fast_isinstance(vm.ctx.exceptions.base_exception_group) { |
| 2840 | // Find first non-None exception |
| 2841 | let first = excs_vec.into_iter().find(|e| !vm.is_none(e)); |
| 2842 | return Ok(first.unwrap_or_else(|| vm.ctx.none())); |
| 2843 | } |
| 2844 | |
| 2845 | // Split excs into raised (new) and reraised (from original) by comparing metadata |
| 2846 | let mut raised: Vec<PyObjectRef> = Vec::new(); |
| 2847 | let mut reraised: Vec<PyObjectRef> = Vec::new(); |
| 2848 | |
| 2849 | for exc in excs_vec { |
| 2850 | if vm.is_none(&exc) { |
| 2851 | continue; |
| 2852 | } |
| 2853 | // Check if this exception came from the original group |
| 2854 | if is_exception_from_orig(&exc, &orig, vm) { |
| 2855 | reraised.push(exc); |
| 2856 | } else { |
| 2857 | raised.push(exc); |
| 2858 | } |
| 2859 | } |
| 2860 | |
| 2861 | // If no exceptions to reraise, return None |
| 2862 | if raised.is_empty() && reraised.is_empty() { |
| 2863 | return Ok(vm.ctx.none()); |
| 2864 | } |
| 2865 | |
| 2866 | // Project reraised exceptions onto original structure to preserve nesting |
| 2867 | let reraised_eg = exception_group_projection(&orig, &reraised, vm)?; |
| 2868 | |
| 2869 | // If no new raised exceptions, just return the reraised projection |
| 2870 | if raised.is_empty() { |
| 2871 | return Ok(reraised_eg); |
| 2872 | } |
| 2873 | |
| 2874 | // Combine raised with reraised_eg |
| 2875 | if !vm.is_none(&reraised_eg) { |
| 2876 | raised.push(reraised_eg); |
| 2877 | } |
| 2878 | |
| 2879 | // If only one exception, return it directly |
| 2880 | if raised.len() == 1 { |
no test coverage detected