Recursively split an exception (group) by leaf IDs. Returns the projection containing only matching leaves with preserved structure.
(
exc: &PyObjectRef,
leaf_ids: &HashSet<usize>,
vm: &VirtualMachine,
)
| 2958 | /// Recursively split an exception (group) by leaf IDs. |
| 2959 | /// Returns the projection containing only matching leaves with preserved structure. |
| 2960 | fn split_by_leaf_ids( |
| 2961 | exc: &PyObjectRef, |
| 2962 | leaf_ids: &HashSet<usize>, |
| 2963 | vm: &VirtualMachine, |
| 2964 | ) -> PyResult { |
| 2965 | if vm.is_none(exc) { |
| 2966 | return Ok(vm.ctx.none()); |
| 2967 | } |
| 2968 | |
| 2969 | // If not an exception group, check if it's in our set |
| 2970 | if !exc.fast_isinstance(vm.ctx.exceptions.base_exception_group) { |
| 2971 | if leaf_ids.contains(&exc.get_id()) { |
| 2972 | return Ok(exc.clone()); |
| 2973 | } |
| 2974 | return Ok(vm.ctx.none()); |
| 2975 | } |
| 2976 | |
| 2977 | // Exception group - recurse and reconstruct |
| 2978 | let excs_attr = exc.get_attr("exceptions", vm)?; |
| 2979 | let tuple: PyTupleRef = excs_attr.try_into_value(vm)?; |
| 2980 | |
| 2981 | let mut matched = Vec::new(); |
| 2982 | for e in tuple.iter() { |
| 2983 | let m = split_by_leaf_ids(e, leaf_ids, vm)?; |
| 2984 | if !vm.is_none(&m) { |
| 2985 | matched.push(m); |
| 2986 | } |
| 2987 | } |
| 2988 | |
| 2989 | if matched.is_empty() { |
| 2990 | return Ok(vm.ctx.none()); |
| 2991 | } |
| 2992 | |
| 2993 | // Reconstruct using derive() to preserve the structure (not necessarily the subclass type) |
| 2994 | let matched_tuple = vm.ctx.new_tuple(matched); |
| 2995 | vm.call_method(exc, "derive", (matched_tuple,)) |
| 2996 | } |
no test coverage detected