diff --git a/examples/call_between_rust_and_python.rs b/examples/call_between_rust_and_python.rs index 98fb434fa..78eef6220 100644 --- a/examples/call_between_rust_and_python.rs +++ b/examples/call_between_rust_and_python.rs @@ -17,7 +17,7 @@ pub fn main() { vm.insert_sys_path(vm.new_pyobj("examples")) .expect("add path"); - let module = vm.import("call_between_rust_and_python", None, 0).unwrap(); + let module = vm.import("call_between_rust_and_python", 0).unwrap(); let init_fn = module.get_attr("python_callback", vm).unwrap(); init_fn.call((), vm).unwrap(); diff --git a/examples/package_embed.rs b/examples/package_embed.rs index b35d06392..fffa98623 100644 --- a/examples/package_embed.rs +++ b/examples/package_embed.rs @@ -7,7 +7,7 @@ fn py_main(interp: &Interpreter) -> vm::PyResult { // Add local library path vm.insert_sys_path(vm.new_pyobj("examples")) .expect("add examples to sys.path failed"); - let module = vm.import("package_embed", None, 0)?; + let module = vm.import("package_embed", 0)?; let name_func = module.get_attr("context", vm)?; let result = name_func.call((), vm)?; let result: PyStrRef = result.get_attr("name", vm)?.try_into_value(vm)?; diff --git a/src/lib.rs b/src/lib.rs index f916dd682..822ea7b44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,7 +175,7 @@ fn run_rustpython(vm: &VirtualMachine, run_mode: RunMode, quiet: bool) -> PyResu )?; } - let site_result = vm.import("site", None, 0); + let site_result = vm.import("site", 0); if site_result.is_err() { warn!( "Failed to import site, consider adding the Lib directory to your RUSTPYTHONPATH \ diff --git a/stdlib/src/array.rs b/stdlib/src/array.rs index a0beb5d1e..9f4540aa2 100644 --- a/stdlib/src/array.rs +++ b/stdlib/src/array.rs @@ -10,7 +10,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef { .expect("Expect array has array type."); let collections_abc = vm - .import("collections.abc", None, 0) + .import("collections.abc", 0) .expect("Expect collections exist."); let abc = collections_abc .get_attr("abc", vm) @@ -1165,7 +1165,7 @@ mod array { let bytes = vm.ctx.new_bytes(array.get_bytes().to_vec()); let code = MachineFormatCode::from_typecode(array.typecode()).unwrap(); let code = PyInt::from(u8::from(code)).into_pyobject(vm); - let module = vm.import("array", None, 0)?; + let module = vm.import("array", 0)?; let func = module.get_attr("_array_reconstructor", vm)?; Ok(( func, diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs index ecc5fea71..e24b7e475 100644 --- a/stdlib/src/sqlite.rs +++ b/stdlib/src/sqlite.rs @@ -1301,7 +1301,7 @@ mod _sqlite { #[pymethod] fn iterdump(zelf: PyRef, vm: &VirtualMachine) -> PyResult { - let module = vm.import("sqlite3.dump", None, 0)?; + let module = vm.import("sqlite3.dump", 0)?; let func = module.get_attr("_iterdump", vm)?; func.call((zelf,), vm) } diff --git a/vm/src/builtins/module.rs b/vm/src/builtins/module.rs index 58174082d..de55b9dea 100644 --- a/vm/src/builtins/module.rs +++ b/vm/src/builtins/module.rs @@ -202,7 +202,7 @@ impl GetAttr for PyModule { impl Representable for PyModule { #[inline] fn repr(zelf: &Py, vm: &VirtualMachine) -> PyResult { - let importlib = vm.import("_frozen_importlib", None, 0)?; + let importlib = vm.import("_frozen_importlib", 0)?; let module_repr = importlib.get_attr("_module_repr", vm)?; let repr = module_repr.call((zelf.to_owned(),), vm)?; repr.downcast() diff --git a/vm/src/builtins/object.rs b/vm/src/builtins/object.rs index 3b3d1ab36..fca68a9f3 100644 --- a/vm/src/builtins/object.rs +++ b/vm/src/builtins/object.rs @@ -366,11 +366,11 @@ pub fn init(ctx: &Context) { fn common_reduce(obj: PyObjectRef, proto: usize, vm: &VirtualMachine) -> PyResult { if proto >= 2 { - let reducelib = vm.import("__reducelib", None, 0)?; + let reducelib = vm.import("__reducelib", 0)?; let reduce_2 = reducelib.get_attr("reduce_2", vm)?; reduce_2.call((obj,), vm) } else { - let copyreg = vm.import("copyreg", None, 0)?; + let copyreg = vm.import("copyreg", 0)?; let reduce_ex = copyreg.get_attr("_reduce_ex", vm)?; reduce_ex.call((obj, proto), vm) } diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs index 63cd3e433..cf267a63b 100644 --- a/vm/src/builtins/tuple.rs +++ b/vm/src/builtins/tuple.rs @@ -510,6 +510,13 @@ impl AsRef<[T]> for PyTupleTyped { } impl PyTupleTyped { + pub fn empty(vm: &VirtualMachine) -> Self { + Self { + tuple: vm.ctx.empty_tuple.clone(), + _marker: PhantomData, + } + } + #[inline] pub fn as_slice(&self) -> &[T] { unsafe { &*(self.tuple.as_slice() as *const [PyObjectRef] as *const [T]) } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 56e0f433d..93417e655 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -1136,12 +1136,13 @@ impl ExecutingFrame<'_> { } #[cfg_attr(feature = "flame-it", flame("Frame"))] - fn import(&mut self, vm: &VirtualMachine, module: Option<&Py>) -> PyResult<()> { - let module = module.unwrap_or(vm.ctx.empty_str); - let from_list = >>::try_from_object(vm, self.pop_value())?; + fn import(&mut self, vm: &VirtualMachine, module_name: Option<&Py>) -> PyResult<()> { + let module_name = module_name.unwrap_or(vm.ctx.empty_str); + let from_list = >>::try_from_object(vm, self.pop_value())? + .unwrap_or_else(|| PyTupleTyped::empty(vm)); let level = usize::try_from_object(vm, self.pop_value())?; - let module = vm.import(module, from_list, level)?; + let module = vm.import_from(module_name, from_list, level)?; self.push_value(module); Ok(()) diff --git a/vm/src/import.rs b/vm/src/import.rs index 918424296..e3ffbbddb 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -46,7 +46,7 @@ pub(crate) fn init_importlib_package(vm: &VirtualMachine, importlib: PyObjectRef let install_external = importlib.get_attr("_install_external_importers", vm)?; install_external.call((), vm)?; // Set pyc magic number to commit hash. Should be changed when bytecode will be more stable. - let importlib_external = vm.import("_frozen_importlib_external", None, 0)?; + let importlib_external = vm.import("_frozen_importlib_external", 0)?; let mut magic = get_git_revision().into_bytes(); magic.truncate(4); if magic.len() != 4 { @@ -55,7 +55,7 @@ pub(crate) fn init_importlib_package(vm: &VirtualMachine, importlib: PyObjectRef let magic: PyObjectRef = vm.ctx.new_bytes(magic).into(); importlib_external.set_attr("MAGIC_NUMBER", magic, vm)?; let zipimport_res = (|| -> PyResult<()> { - let zipimport = vm.import("zipimport", None, 0)?; + let zipimport = vm.import("zipimport", 0)?; let zipimporter = zipimport.get_attr("zipimporter", vm)?; let path_hooks = vm.sys_module.get_attr("path_hooks", vm)?; let path_hooks = list::PyListRef::try_from_object(vm, path_hooks)?; diff --git a/vm/src/stdlib/codecs.rs b/vm/src/stdlib/codecs.rs index 349122fcd..b4051d5c4 100644 --- a/vm/src/stdlib/codecs.rs +++ b/vm/src/stdlib/codecs.rs @@ -355,7 +355,7 @@ mod _codecs { vm: &VirtualMachine, ) -> PyResult { let f = cell.get_or_try_init(|| { - let module = vm.import("_pycodecs", None, 0)?; + let module = vm.import("_pycodecs", 0)?; module.get_attr(name, vm) })?; f.call(args, vm) diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index f6af1f9f9..edebde137 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -2204,7 +2204,7 @@ mod _io { Some(enc) if enc.as_str() != "locale" => enc, _ => { // None without utf8_mode or "locale" encoding - vm.import("locale", None, 0)? + vm.import("locale", 0)? .get_attr("getencoding", vm)? .call((), vm)? .try_into_value(vm)? diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 6035e002a..35dd08fb2 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -538,7 +538,7 @@ mod _operator { } else { // If we have kwargs, create a partial function that contains them and pass back that // along with the args. - let partial = vm.import("functools", None, 0)?.get_attr("partial", vm)?; + let partial = vm.import("functools", 0)?.get_attr("partial", vm)?; let args = FuncArgs::new( vec![zelf.class().to_owned().into(), zelf.name.clone().into()], KwArgs::new(zelf.args.kwargs.clone()), diff --git a/vm/src/stdlib/sre.rs b/vm/src/stdlib/sre.rs index 93ea46ea8..8442002fa 100644 --- a/vm/src/stdlib/sre.rs +++ b/vm/src/stdlib/sre.rs @@ -118,7 +118,7 @@ mod _sre { repl: PyObjectRef, vm: &VirtualMachine, ) -> PyResult> { - let re = vm.import("re", None, 0)?; + let re = vm.import("re", 0)?; let func = re.get_attr("_compile_template", vm)?; let result = func.call((pattern, repl.clone()), vm)?; result @@ -680,7 +680,7 @@ mod _sre { #[pymethod] fn expand(zelf: PyRef, template: PyStrRef, vm: &VirtualMachine) -> PyResult { - let re = vm.import("re", None, 0)?; + let re = vm.import("re", 0)?; let func = re.get_attr("_expand", vm)?; func.call((zelf.pattern.clone(), zelf, template), vm) } diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs index 4c8b6a060..f6d7a122a 100644 --- a/vm/src/stdlib/sys.rs +++ b/vm/src/stdlib/sys.rs @@ -378,7 +378,7 @@ mod sys { (&env_var[..(env_var.len() - last.len() - 1)], last) }; - let module = match vm.import(&vm.ctx.new_str(module_path), None, 0) { + let module = match vm.import(&vm.ctx.new_str(module_path), 0) { Ok(module) => module, Err(_) => { return print_unimportable_module_warn(); @@ -560,7 +560,7 @@ mod sys { } // TODO: print received unraisable.exc_traceback - let tb_module = vm.import("traceback", None, 0)?; + let tb_module = vm.import("traceback", 0)?; let print_stack = tb_module.get_attr("print_stack", vm)?; print_stack.call((), vm)?; diff --git a/vm/src/stdlib/warnings.rs b/vm/src/stdlib/warnings.rs index ef72490f1..be5ad8131 100644 --- a/vm/src/stdlib/warnings.rs +++ b/vm/src/stdlib/warnings.rs @@ -9,7 +9,7 @@ pub fn warn( vm: &VirtualMachine, ) -> PyResult<()> { // TODO: use rust warnings module - if let Ok(module) = vm.import("warnings", None, 0) { + if let Ok(module) = vm.import("warnings", 0) { if let Ok(func) = module.get_attr("warn", vm) { let _ = func.call((message, category.to_owned(), stack_level), vm); } diff --git a/vm/src/vm/compile.rs b/vm/src/vm/compile.rs index c44158f20..1088568d6 100644 --- a/vm/src/vm/compile.rs +++ b/vm/src/vm/compile.rs @@ -29,7 +29,7 @@ impl VirtualMachine { pub fn run_script(&self, scope: Scope, path: &str) -> PyResult<()> { if get_importer(path, self)?.is_some() { self.insert_sys_path(self.new_pyobj(path))?; - let runpy = self.import("runpy", None, 0)?; + let runpy = self.import("runpy", 0)?; let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?; run_module_as_main.call((identifier!(self, __main__).to_owned(), false), self)?; return Ok(()); diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index e943ab7fa..bd44eaed3 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -222,7 +222,7 @@ impl VirtualMachine { /// init_importlib must be called before this call #[cfg(feature = "encodings")] fn import_encodings(&mut self) -> PyResult<()> { - self.import("encodings", None, 0).map_err(|import_err| { + self.import("encodings", 0).map_err(|import_err| { let rustpythonpath_env = std::env::var("RUSTPYTHONPATH").ok(); let pythonpath_env = std::env::var("PYTHONPATH").ok(); let env_set = rustpythonpath_env.as_ref().is_some() || pythonpath_env.as_ref().is_some(); @@ -396,7 +396,7 @@ impl VirtualMachine { #[cold] pub fn run_unraisable(&self, e: PyBaseExceptionRef, msg: Option, object: PyObjectRef) { - let sys_module = self.import("sys", None, 0).unwrap(); + let sys_module = self.import("sys", 0).unwrap(); let unraisablehook = sys_module.get_attr("unraisablehook", self).unwrap(); let exc_type = e.class().to_owned(); @@ -495,7 +495,7 @@ impl VirtualMachine { pub fn try_class(&self, module: &'static str, class: &'static str) -> PyResult { let class = self - .import(module, None, 0)? + .import(module, 0)? .get_attr(class, self)? .downcast() .expect("not a class"); @@ -504,7 +504,7 @@ impl VirtualMachine { pub fn class(&self, module: &'static str, class: &'static str) -> PyTypeRef { let module = self - .import(module, None, 0) + .import(module, 0) .unwrap_or_else(|_| panic!("unable to import {module}")); let class = module @@ -513,11 +513,24 @@ impl VirtualMachine { class.downcast().expect("not a class") } + /// Call Python __import__ function without from_list. + /// Roughly equivalent to `import module_name` or `import top.submodule`. + /// + /// See also [`import_from`] for more advanced import. #[inline] - pub fn import<'a>( + pub fn import<'a>(&self, module_name: impl AsPyStr<'a>, level: usize) -> PyResult { + let module_name = module_name.as_pystr(&self.ctx); + let from_list = PyTupleTyped::empty(self); + self.import_inner(module_name, from_list, level) + } + + /// Call Python __import__ function caller with from_list. + /// Roughly equivalent to `from module_name import item1, item2` or `from top.submodule import item1, item2` + #[inline] + pub fn import_from<'a>( &self, module_name: impl AsPyStr<'a>, - from_list: Option>, + from_list: PyTupleTyped, level: usize, ) -> PyResult { let module_name = module_name.as_pystr(&self.ctx); @@ -527,14 +540,12 @@ impl VirtualMachine { fn import_inner( &self, module: &Py, - from_list: Option>, + from_list: PyTupleTyped, level: usize, ) -> PyResult { // if the import inputs seem weird, e.g a package import or something, rather than just // a straight `import ident` - let weird = module.as_str().contains('.') - || level != 0 - || from_list.as_ref().map_or(false, |x| !x.is_empty()); + let weird = module.as_str().contains('.') || level != 0 || !from_list.is_empty(); let cached_module = if weird { None @@ -567,10 +578,7 @@ impl VirtualMachine { } else { (None, None) }; - let from_list = match from_list { - Some(tup) => tup.to_pyobject(self), - None => self.new_tuple(()).into(), - }; + let from_list = from_list.to_pyobject(self); import_func .call((module.to_owned(), globals, locals, from_list, level), self) .map_err(|exc| import::remove_importlib_frames(self, &exc)) @@ -859,7 +867,7 @@ impl VirtualMachine { } pub fn run_module(&self, module: &str) -> PyResult<()> { - let runpy = self.import("runpy", None, 0)?; + let runpy = self.import("runpy", 0)?; let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?; run_module_as_main.call((module,), self)?; Ok(()) diff --git a/vm/src/warn.rs b/vm/src/warn.rs index d0acccbf2..c1e4dc347 100644 --- a/vm/src/warn.rs +++ b/vm/src/warn.rs @@ -62,7 +62,7 @@ fn get_warnings_attr( .finalizing .load(std::sync::atomic::Ordering::SeqCst) { - match vm.import("warnings", None, 0) { + match vm.import("warnings", 0) { Ok(module) => module, Err(_) => return Ok(None), }