rustpython_vm/stdlib/
imp.rs

1use crate::frozen::FrozenModule;
2use crate::{builtins::PyBaseExceptionRef, VirtualMachine};
3pub(crate) use _imp::make_module;
4
5#[cfg(feature = "threading")]
6#[pymodule(sub)]
7mod lock {
8    use crate::{stdlib::thread::RawRMutex, PyResult, VirtualMachine};
9
10    static IMP_LOCK: RawRMutex = RawRMutex::INIT;
11
12    #[pyfunction]
13    fn acquire_lock(_vm: &VirtualMachine) {
14        IMP_LOCK.lock()
15    }
16
17    #[pyfunction]
18    fn release_lock(vm: &VirtualMachine) -> PyResult<()> {
19        if !IMP_LOCK.is_locked() {
20            Err(vm.new_runtime_error("Global import lock not held".to_owned()))
21        } else {
22            unsafe { IMP_LOCK.unlock() };
23            Ok(())
24        }
25    }
26
27    #[pyfunction]
28    fn lock_held(_vm: &VirtualMachine) -> bool {
29        IMP_LOCK.is_locked()
30    }
31}
32
33#[cfg(not(feature = "threading"))]
34#[pymodule(sub)]
35mod lock {
36    use crate::vm::VirtualMachine;
37    #[pyfunction]
38    pub(super) fn acquire_lock(_vm: &VirtualMachine) {}
39    #[pyfunction]
40    pub(super) fn release_lock(_vm: &VirtualMachine) {}
41    #[pyfunction]
42    pub(super) fn lock_held(_vm: &VirtualMachine) -> bool {
43        false
44    }
45}
46
47#[allow(dead_code)]
48enum FrozenError {
49    BadName,  // The given module name wasn't valid.
50    NotFound, // It wasn't in PyImport_FrozenModules.
51    Disabled, // -X frozen_modules=off (and not essential)
52    Excluded, // The PyImport_FrozenModules entry has NULL "code"
53    //        (module is present but marked as unimportable, stops search).
54    Invalid, // The PyImport_FrozenModules entry is bogus
55             //          (eg. does not contain executable code).
56}
57
58impl FrozenError {
59    fn to_pyexception(&self, mod_name: &str, vm: &VirtualMachine) -> PyBaseExceptionRef {
60        use FrozenError::*;
61        let msg = match self {
62            BadName | NotFound => format!("No such frozen object named {mod_name}"),
63            Disabled => format!("Frozen modules are disabled and the frozen object named {mod_name} is not essential"),
64            Excluded => format!("Excluded frozen object named {mod_name}"),
65            Invalid => format!("Frozen object named {mod_name} is invalid"),
66        };
67        vm.new_import_error(msg, vm.ctx.new_str(mod_name))
68    }
69}
70
71// find_frozen in frozen.c
72fn find_frozen(name: &str, vm: &VirtualMachine) -> Result<FrozenModule, FrozenError> {
73    vm.state
74        .frozen
75        .get(name)
76        .copied()
77        .ok_or(FrozenError::NotFound)
78}
79
80#[pymodule(with(lock))]
81mod _imp {
82    use crate::{
83        builtins::{PyBytesRef, PyCode, PyMemoryView, PyModule, PyStrRef},
84        function::OptionalArg,
85        import, PyObjectRef, PyRef, PyResult, VirtualMachine,
86    };
87
88    #[pyattr]
89    fn check_hash_based_pycs(vm: &VirtualMachine) -> PyStrRef {
90        vm.ctx
91            .new_str(vm.state.settings.check_hash_pycs_mode.clone())
92    }
93
94    #[pyfunction]
95    fn extension_suffixes() -> PyResult<Vec<PyObjectRef>> {
96        Ok(Vec::new())
97    }
98
99    #[pyfunction]
100    fn is_builtin(name: PyStrRef, vm: &VirtualMachine) -> bool {
101        vm.state.module_inits.contains_key(name.as_str())
102    }
103
104    #[pyfunction]
105    fn is_frozen(name: PyStrRef, vm: &VirtualMachine) -> bool {
106        vm.state.frozen.contains_key(name.as_str())
107    }
108
109    #[pyfunction]
110    fn create_builtin(spec: PyObjectRef, vm: &VirtualMachine) -> PyResult {
111        let sys_modules = vm.sys_module.get_attr("modules", vm).unwrap();
112        let name: PyStrRef = spec.get_attr("name", vm)?.try_into_value(vm)?;
113
114        let module = if let Ok(module) = sys_modules.get_item(&*name, vm) {
115            module
116        } else if let Some(make_module_func) = vm.state.module_inits.get(name.as_str()) {
117            make_module_func(vm).into()
118        } else {
119            vm.ctx.none()
120        };
121        Ok(module)
122    }
123
124    #[pyfunction]
125    fn exec_builtin(_mod: PyRef<PyModule>) -> i32 {
126        // TODO: Should we do something here?
127        0
128    }
129
130    #[pyfunction]
131    fn get_frozen_object(name: PyStrRef, vm: &VirtualMachine) -> PyResult<PyRef<PyCode>> {
132        import::make_frozen(vm, name.as_str())
133    }
134
135    #[pyfunction]
136    fn init_frozen(name: PyStrRef, vm: &VirtualMachine) -> PyResult {
137        import::import_frozen(vm, name.as_str())
138    }
139
140    #[pyfunction]
141    fn is_frozen_package(name: PyStrRef, vm: &VirtualMachine) -> PyResult<bool> {
142        super::find_frozen(name.as_str(), vm)
143            .map(|frozen| frozen.package)
144            .map_err(|e| e.to_pyexception(name.as_str(), vm))
145    }
146
147    #[pyfunction]
148    fn _override_frozen_modules_for_tests(value: isize, vm: &VirtualMachine) {
149        vm.state.override_frozen_modules.store(value);
150    }
151
152    #[pyfunction]
153    fn _fix_co_filename(_code: PyObjectRef, _path: PyStrRef) {
154        // TODO:
155    }
156
157    #[pyfunction]
158    fn _frozen_module_names(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
159        let names = vm
160            .state
161            .frozen
162            .keys()
163            .map(|&name| vm.ctx.new_str(name).into())
164            .collect();
165        Ok(names)
166    }
167
168    #[allow(clippy::type_complexity)]
169    #[pyfunction]
170    fn find_frozen(
171        name: PyStrRef,
172        withdata: OptionalArg<bool>,
173        vm: &VirtualMachine,
174    ) -> PyResult<Option<(Option<PyRef<PyMemoryView>>, bool, PyStrRef)>> {
175        use super::FrozenError::*;
176
177        if withdata.into_option().is_some() {
178            // this is keyword-only argument in CPython
179            unimplemented!();
180        }
181
182        let info = match super::find_frozen(name.as_str(), vm) {
183            Ok(info) => info,
184            Err(NotFound | Disabled | BadName) => return Ok(None),
185            Err(e) => return Err(e.to_pyexception(name.as_str(), vm)),
186        };
187
188        let origname = name; // FIXME: origname != name
189        Ok(Some((None, info.package, origname)))
190    }
191
192    #[pyfunction]
193    fn source_hash(key: u64, source: PyBytesRef) -> Vec<u8> {
194        let hash: u64 = crate::common::hash::keyed_hash(key, source.as_bytes());
195        hash.to_le_bytes().to_vec()
196    }
197}