Match exception against except* handler type. Returns (rest, match) tuple.
(
exc_value: &PyObjectRef,
match_type: &PyObjectRef,
vm: &VirtualMachine,
)
| 2754 | /// Match exception against except* handler type. |
| 2755 | /// Returns (rest, match) tuple. |
| 2756 | pub fn exception_group_match( |
| 2757 | exc_value: &PyObjectRef, |
| 2758 | match_type: &PyObjectRef, |
| 2759 | vm: &VirtualMachine, |
| 2760 | ) -> PyResult<(PyObjectRef, PyObjectRef)> { |
| 2761 | // Implements _PyEval_ExceptionGroupMatch |
| 2762 | |
| 2763 | // If exc_value is None, return (None, None) |
| 2764 | if vm.is_none(exc_value) { |
| 2765 | return Ok((vm.ctx.none(), vm.ctx.none())); |
| 2766 | } |
| 2767 | |
| 2768 | // Validate match_type and reject ExceptionGroup/BaseExceptionGroup |
| 2769 | check_except_star_type_valid(match_type, vm)?; |
| 2770 | |
| 2771 | // Check if exc_value matches match_type |
| 2772 | if exc_value.is_instance(match_type, vm)? { |
| 2773 | // Full match of exc itself |
| 2774 | let is_eg = exc_value.fast_isinstance(vm.ctx.exceptions.base_exception_group); |
| 2775 | let matched = if is_eg { |
| 2776 | exc_value.clone() |
| 2777 | } else { |
| 2778 | // Naked exception - wrap it in ExceptionGroup |
| 2779 | let excs = vm.ctx.new_tuple(vec![exc_value.clone()]); |
| 2780 | let eg_type: PyObjectRef = crate::exception_group::exception_group().to_owned().into(); |
| 2781 | let wrapped = eg_type.call((vm.ctx.new_str(""), excs), vm)?; |
| 2782 | // Copy traceback from original exception |
| 2783 | if let Ok(exc) = exc_value.clone().downcast::<types::PyBaseException>() |
| 2784 | && let Some(tb) = exc.__traceback__() |
| 2785 | && let Ok(wrapped_exc) = wrapped.clone().downcast::<types::PyBaseException>() |
| 2786 | { |
| 2787 | let _ = wrapped_exc.set___traceback__(tb.into(), vm); |
| 2788 | } |
| 2789 | wrapped |
| 2790 | }; |
| 2791 | return Ok((vm.ctx.none(), matched)); |
| 2792 | } |
| 2793 | |
| 2794 | // Check for partial match if it's an exception group |
| 2795 | if exc_value.fast_isinstance(vm.ctx.exceptions.base_exception_group) { |
| 2796 | let pair = vm.call_method(exc_value, "split", (match_type.clone(),))?; |
| 2797 | if !pair.class().is(vm.ctx.types.tuple_type) { |
| 2798 | return Err(vm.new_type_error(format!( |
| 2799 | "{}.split must return a tuple, not {}", |
| 2800 | exc_value.class().name(), |
| 2801 | pair.class().name() |
| 2802 | ))); |
| 2803 | } |
| 2804 | let pair_tuple: PyTupleRef = pair.try_into_value(vm)?; |
| 2805 | if pair_tuple.len() < 2 { |
| 2806 | return Err(vm.new_type_error(format!( |
| 2807 | "{}.split must return a 2-tuple, got tuple of size {}", |
| 2808 | exc_value.class().name(), |
| 2809 | pair_tuple.len() |
| 2810 | ))); |
| 2811 | } |
| 2812 | let matched = pair_tuple[0].clone(); |
| 2813 | let rest = pair_tuple[1].clone(); |
no test coverage detected