1use crate::{
4 AsObject, PyRef, PyResult, VirtualMachine,
5 builtins::PyCode,
6 compiler::{self},
7 scope::Scope,
8};
9
10impl VirtualMachine {
11 pub fn run_simple_string(&self, source: &str) -> PyResult {
15 let scope = self.new_scope_with_builtins();
16 self.run_string(scope, source, "<string>".to_owned())
17 }
18
19 pub fn run_string(&self, scope: Scope, source: &str, source_path: String) -> PyResult {
23 let code_obj = self
24 .compile(source, compiler::Mode::Exec, source_path)
25 .map_err(|err| self.new_syntax_error(&err, Some(source)))?;
26 let _ = self.register_code_in_linecache(&code_obj, source);
28 self.run_code_obj(code_obj, scope)
29 }
30
31 fn register_code_in_linecache(&self, code: &PyRef<PyCode>, source: &str) -> PyResult<()> {
34 let linecache = self.import("linecache", 0)?;
35 let register = linecache.get_attr("_register_code", self)?;
36 let source_str = self.ctx.new_str(source);
37 let filename = self.ctx.new_str(code.source_path().as_str());
38 register.call((code.as_object().to_owned(), source_str, filename), self)?;
39 Ok(())
40 }
41
42 #[deprecated(note = "use run_string instead")]
43 pub fn run_code_string(&self, scope: Scope, source: &str, source_path: String) -> PyResult {
44 self.run_string(scope, source, source_path)
45 }
46
47 pub fn run_block_expr(&self, scope: Scope, source: &str) -> PyResult {
48 let code_obj = self
49 .compile(source, compiler::Mode::BlockExpr, "<embedded>".to_owned())
50 .map_err(|err| self.new_syntax_error(&err, Some(source)))?;
51 self.run_code_obj(code_obj, scope)
52 }
53}
54
55#[cfg(feature = "host_env")]
56mod file_run {
57 use crate::{
58 Py, PyResult, VirtualMachine,
59 builtins::{PyCode, PyDict},
60 compiler::{self},
61 scope::Scope,
62 };
63
64 impl VirtualMachine {
65 #[doc(hidden)]
72 pub fn run_any_file(&self, scope: Scope, path: &str) -> PyResult<()> {
73 let path = if path.is_empty() { "???" } else { path };
74 self.run_simple_file(scope, path)
75 }
76
77 fn run_simple_file(&self, scope: Scope, path: &str) -> PyResult<()> {
82 self.with_simple_run(path, |module_dict| {
83 self.run_simple_file_inner(module_dict, scope, path)
84 })
85 }
86
87 fn run_simple_file_inner(
88 &self,
89 module_dict: &Py<PyDict>,
90 scope: Scope,
91 path: &str,
92 ) -> PyResult<()> {
93 let pyc = maybe_pyc_file(path);
94 if pyc {
95 set_main_loader(module_dict, path, "SourcelessFileLoader", self)?;
97 let loader = module_dict.get_item("__loader__", self)?;
98 let get_code = loader.get_attr("get_code", self)?;
99 let code_obj = get_code.call((identifier!(self, __main__).to_owned(),), self)?;
100 let code = code_obj
101 .downcast::<PyCode>()
102 .map_err(|_| self.new_runtime_error("Bad code object in .pyc file"))?;
103 self.run_code_obj(code, scope)?;
104 } else {
105 if path != "<stdin>" {
106 set_main_loader(module_dict, path, "SourceFileLoader", self)?;
107 }
108 match std::fs::read_to_string(path) {
109 Ok(source) => {
110 let code_obj = self
111 .compile(&source, compiler::Mode::Exec, path.to_owned())
112 .map_err(|err| self.new_syntax_error(&err, Some(&source)))?;
113 self.run_code_obj(code_obj, scope)?;
114 }
115 Err(err) => {
116 return Err(self.new_os_error(err.to_string()));
117 }
118 }
119 }
120 Ok(())
121 }
122
123 pub fn run_script(&self, scope: Scope, path: &str) -> PyResult<()> {
125 self.run_any_file(scope, path)
126 }
127 }
128
129 fn set_main_loader(
130 module_dict: &Py<PyDict>,
131 filename: &str,
132 loader_name: &str,
133 vm: &VirtualMachine,
134 ) -> PyResult<()> {
135 vm.import("importlib.machinery", 0)?;
136 let sys_modules = vm.sys_module.get_attr(identifier!(vm, modules), vm)?;
137 let machinery = sys_modules.get_item("importlib.machinery", vm)?;
138 let loader_name = vm.ctx.new_str(loader_name);
139 let loader_class = machinery.get_attr(&loader_name, vm)?;
140 let loader = loader_class.call((identifier!(vm, __main__).to_owned(), filename), vm)?;
141 module_dict.set_item("__loader__", loader, vm)?;
142 Ok(())
143 }
144
145 fn maybe_pyc_file(path: &str) -> bool {
151 if path.ends_with(".pyc") {
152 return true;
153 }
154 maybe_pyc_file_with_magic(path).unwrap_or(false)
155 }
156
157 fn maybe_pyc_file_with_magic(path: &str) -> std::io::Result<bool> {
158 let path_obj = std::path::Path::new(path);
159 if !path_obj.is_file() {
160 return Ok(false);
161 }
162
163 let mut file = std::fs::File::open(path)?;
164 let mut buf = [0u8; 2];
165
166 use std::io::Read;
167 if file.read(&mut buf)? != 2 {
168 return Ok(false);
169 }
170
171 Ok(crate::import::check_pyc_magic_number_bytes(&buf))
175 }
176}