| 1003 | |
| 1004 | #[pyfunction] |
| 1005 | fn _getframemodulename(depth: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult { |
| 1006 | let depth = depth.into_option().unwrap_or(0); |
| 1007 | |
| 1008 | // Get the frame at the specified depth |
| 1009 | let func_obj = { |
| 1010 | let frames = vm.frames.borrow(); |
| 1011 | if depth >= frames.len() { |
| 1012 | return Ok(vm.ctx.none()); |
| 1013 | } |
| 1014 | let idx = frames.len() - depth - 1; |
| 1015 | // SAFETY: the FrameRef is alive on the call stack while it's in the Vec |
| 1016 | let frame: &crate::Py<Frame> = unsafe { frames[idx].as_ref() }; |
| 1017 | frame.func_obj.clone() |
| 1018 | }; |
| 1019 | |
| 1020 | // If the frame has a function object, return its __module__ attribute |
| 1021 | if let Some(func_obj) = func_obj { |
| 1022 | match func_obj.get_attr(identifier!(vm, __module__), vm) { |
| 1023 | Ok(module) => Ok(module), |
| 1024 | Err(_) => { |
| 1025 | // CPython clears the error and returns None |
| 1026 | Ok(vm.ctx.none()) |
| 1027 | } |
| 1028 | } |
| 1029 | } else { |
| 1030 | Ok(vm.ctx.none()) |
| 1031 | } |
| 1032 | } |
| 1033 | |
| 1034 | /// Return a dictionary mapping each thread's identifier to the topmost stack frame |
| 1035 | /// currently active in that thread at the time the function is called. |