1use crate::{
5 builtins::{list, traceback::PyTraceback, PyBaseExceptionRef, PyCode},
6 scope::Scope,
7 version::get_git_revision,
8 vm::{thread, VirtualMachine},
9 AsObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
10};
11use rand::Rng;
12
13pub(crate) fn init_importlib_base(vm: &mut VirtualMachine) -> PyResult<PyObjectRef> {
14 flame_guard!("init importlib");
15
16 #[cfg(all(feature = "threading", not(target_os = "wasi")))]
19 import_builtin(vm, "_thread")?;
20 import_builtin(vm, "_warnings")?;
21 import_builtin(vm, "_weakref")?;
22
23 let importlib = thread::enter_vm(vm, || {
24 let bootstrap = import_frozen(vm, "_frozen_importlib")?;
25 let install = bootstrap.get_attr("_install", vm)?;
26 let imp = import_builtin(vm, "_imp")?;
27 install.call((vm.sys_module.clone(), imp), vm)?;
28 Ok(bootstrap)
29 })?;
30 vm.import_func = importlib.get_attr(identifier!(vm, __import__), vm)?;
31 Ok(importlib)
32}
33
34pub(crate) fn init_importlib_package(vm: &VirtualMachine, importlib: PyObjectRef) -> PyResult<()> {
35 thread::enter_vm(vm, || {
36 flame_guard!("install_external");
37
38 #[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
40 import_builtin(vm, crate::stdlib::os::MODULE_NAME)?;
41 #[cfg(windows)]
42 import_builtin(vm, "winreg")?;
43 import_builtin(vm, "_io")?;
44 import_builtin(vm, "marshal")?;
45
46 let install_external = importlib.get_attr("_install_external_importers", vm)?;
47 install_external.call((), vm)?;
48 let importlib_external = vm.import("_frozen_importlib_external", 0)?;
50 let mut magic = get_git_revision().into_bytes();
51 magic.truncate(4);
52 if magic.len() != 4 {
53 magic = rand::thread_rng().gen::<[u8; 4]>().to_vec();
54 }
55 let magic: PyObjectRef = vm.ctx.new_bytes(magic).into();
56 importlib_external.set_attr("MAGIC_NUMBER", magic, vm)?;
57 let zipimport_res = (|| -> PyResult<()> {
58 let zipimport = vm.import("zipimport", 0)?;
59 let zipimporter = zipimport.get_attr("zipimporter", vm)?;
60 let path_hooks = vm.sys_module.get_attr("path_hooks", vm)?;
61 let path_hooks = list::PyListRef::try_from_object(vm, path_hooks)?;
62 path_hooks.insert(0, zipimporter);
63 Ok(())
64 })();
65 if zipimport_res.is_err() {
66 warn!("couldn't init zipimport")
67 }
68 Ok(())
69 })
70}
71
72pub fn make_frozen(vm: &VirtualMachine, name: &str) -> PyResult<PyRef<PyCode>> {
73 let frozen = vm.state.frozen.get(name).ok_or_else(|| {
74 vm.new_import_error(
75 format!("No such frozen object named {name}"),
76 vm.ctx.new_str(name),
77 )
78 })?;
79 Ok(vm.ctx.new_code(frozen.code))
80}
81
82pub fn import_frozen(vm: &VirtualMachine, module_name: &str) -> PyResult {
83 let frozen = make_frozen(vm, module_name)?;
84 let module = import_codeobj(vm, module_name, frozen, false)?;
85 debug_assert!(module.get_attr(identifier!(vm, __name__), vm).is_ok());
86 module.set_attr("__origname__", vm.ctx.new_str(module_name.to_owned()), vm)?;
88 Ok(module)
89}
90
91pub fn import_builtin(vm: &VirtualMachine, module_name: &str) -> PyResult {
92 let make_module_func = vm.state.module_inits.get(module_name).ok_or_else(|| {
93 vm.new_import_error(
94 format!("Cannot import builtin module {module_name}"),
95 vm.ctx.new_str(module_name),
96 )
97 })?;
98 let module = make_module_func(vm);
99 let sys_modules = vm.sys_module.get_attr("modules", vm)?;
100 sys_modules.set_item(module_name, module.as_object().to_owned(), vm)?;
101 Ok(module.into())
102}
103
104#[cfg(feature = "rustpython-compiler")]
105pub fn import_file(
106 vm: &VirtualMachine,
107 module_name: &str,
108 file_path: String,
109 content: &str,
110) -> PyResult {
111 let code = vm
112 .compile_with_opts(
113 content,
114 crate::compiler::Mode::Exec,
115 file_path,
116 vm.compile_opts(),
117 )
118 .map_err(|err| vm.new_syntax_error(&err, Some(content)))?;
119 import_codeobj(vm, module_name, code, true)
120}
121
122#[cfg(feature = "rustpython-compiler")]
123pub fn import_source(vm: &VirtualMachine, module_name: &str, content: &str) -> PyResult {
124 let code = vm
125 .compile_with_opts(
126 content,
127 crate::compiler::Mode::Exec,
128 "<source>".to_owned(),
129 vm.compile_opts(),
130 )
131 .map_err(|err| vm.new_syntax_error(&err, Some(content)))?;
132 import_codeobj(vm, module_name, code, false)
133}
134
135pub fn import_codeobj(
136 vm: &VirtualMachine,
137 module_name: &str,
138 code_obj: PyRef<PyCode>,
139 set_file_attr: bool,
140) -> PyResult {
141 let attrs = vm.ctx.new_dict();
142 attrs.set_item(
143 identifier!(vm, __name__),
144 vm.ctx.new_str(module_name).into(),
145 vm,
146 )?;
147 if set_file_attr {
148 attrs.set_item(
149 identifier!(vm, __file__),
150 code_obj.source_path.to_object(),
151 vm,
152 )?;
153 }
154 let module = vm.new_module(module_name, attrs.clone(), None);
155
156 let sys_modules = vm.sys_module.get_attr("modules", vm)?;
158 sys_modules.set_item(module_name, module.clone().into(), vm)?;
159
160 let scope = Scope::with_builtins(None, attrs, vm);
162 vm.run_code_obj(code_obj, scope)?;
163 Ok(module.into())
164}
165
166fn remove_importlib_frames_inner(
167 vm: &VirtualMachine,
168 tb: Option<PyRef<PyTraceback>>,
169 always_trim: bool,
170) -> (Option<PyRef<PyTraceback>>, bool) {
171 let traceback = if let Some(tb) = tb {
172 tb
173 } else {
174 return (None, false);
175 };
176
177 let file_name = traceback.frame.code.source_path.as_str();
178
179 let (inner_tb, mut now_in_importlib) =
180 remove_importlib_frames_inner(vm, traceback.next.lock().clone(), always_trim);
181 if file_name == "_frozen_importlib" || file_name == "_frozen_importlib_external" {
182 if traceback.frame.code.obj_name.as_str() == "_call_with_frames_removed" {
183 now_in_importlib = true;
184 }
185 if always_trim || now_in_importlib {
186 return (inner_tb, now_in_importlib);
187 }
188 } else {
189 now_in_importlib = false;
190 }
191
192 (
193 Some(
194 PyTraceback::new(
195 inner_tb,
196 traceback.frame.clone(),
197 traceback.lasti,
198 traceback.lineno,
199 )
200 .into_ref(&vm.ctx),
201 ),
202 now_in_importlib,
203 )
204}
205
206pub fn remove_importlib_frames(
209 vm: &VirtualMachine,
210 exc: &PyBaseExceptionRef,
211) -> PyBaseExceptionRef {
212 let always_trim = exc.fast_isinstance(vm.ctx.exceptions.import_error);
213
214 if let Some(tb) = exc.traceback() {
215 let trimmed_tb = remove_importlib_frames_inner(vm, Some(tb), always_trim).0;
216 exc.set_traceback(trimmed_tb);
217 }
218 exc.clone()
219}