Skip to content

Commit e2d7bed

Browse files
committed
pythonrun
1 parent 8bfe927 commit e2d7bed

File tree

4 files changed

+240
-198
lines changed

4 files changed

+240
-198
lines changed

crates/vm/src/vm/compile.rs

Lines changed: 6 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
//! Python code compilation functions.
2+
//!
3+
//! For code execution functions, see pythonrun.rs
4+
15
use crate::{
2-
AsObject, PyObjectRef, PyRef, PyResult, VirtualMachine,
3-
builtins::{PyCode, PyDictRef},
6+
PyRef, VirtualMachine,
7+
builtins::PyCode,
48
compiler::{self, CompileError, CompileOpts},
5-
convert::TryFromObject,
6-
scope::Scope,
79
};
810

911
impl VirtualMachine {
@@ -25,191 +27,4 @@ impl VirtualMachine {
2527
) -> Result<PyRef<PyCode>, CompileError> {
2628
compiler::compile(source, mode, &source_path, opts).map(|code| self.ctx.new_code(code))
2729
}
28-
29-
// pymain_run_file_obj
30-
pub fn run_script(&self, scope: Scope, path: &str) -> PyResult<()> {
31-
// when pymain_run_module?
32-
if get_importer(path, self)?.is_some() {
33-
self.insert_sys_path(self.new_pyobj(path))?;
34-
let runpy = self.import("runpy", 0)?;
35-
let run_module_as_main = runpy.get_attr("_run_module_as_main", self)?;
36-
run_module_as_main.call((identifier!(self, __main__).to_owned(), false), self)?;
37-
return Ok(());
38-
}
39-
40-
// TODO: check if this is proper place
41-
if !self.state.config.settings.safe_path {
42-
let dir = std::path::Path::new(path)
43-
.parent()
44-
.unwrap()
45-
.to_str()
46-
.unwrap();
47-
self.insert_sys_path(self.new_pyobj(dir))?;
48-
}
49-
50-
self.run_any_file(scope, path)
51-
}
52-
53-
// = _PyRun_AnyFileObject
54-
fn run_any_file(&self, scope: Scope, path: &str) -> PyResult<()> {
55-
let path = if path.is_empty() { "???" } else { path };
56-
57-
self.run_simple_file(scope, path)
58-
}
59-
60-
// = _PyRun_SimpleFileObject
61-
fn run_simple_file(&self, scope: Scope, path: &str) -> PyResult<()> {
62-
// __main__ is given by scope
63-
let sys_modules = self.sys_module.get_attr(identifier!(self, modules), self)?;
64-
let main_module = sys_modules.get_item(identifier!(self, __main__), self)?;
65-
let module_dict = main_module.dict().expect("main module must have __dict__");
66-
if !module_dict.contains_key(identifier!(self, __file__), self) {
67-
module_dict.set_item(
68-
identifier!(self, __file__),
69-
self.ctx.new_str(path).into(),
70-
self,
71-
)?;
72-
module_dict.set_item(identifier!(self, __cached__), self.ctx.none(), self)?;
73-
}
74-
75-
// Consider to use enum to distinguish `path`
76-
// https://github.com/RustPython/RustPython/pull/6276#discussion_r2529849479
77-
78-
let pyc = maybe_pyc_file(path);
79-
if pyc {
80-
// pyc file execution
81-
set_main_loader(&module_dict, path, "SourcelessFileLoader", self)?;
82-
let loader = module_dict.get_item("__loader__", self)?;
83-
let get_code = loader.get_attr("get_code", self)?;
84-
let code_obj = get_code.call((identifier!(self, __main__).to_owned(),), self)?;
85-
let code = code_obj
86-
.downcast::<PyCode>()
87-
.map_err(|_| self.new_runtime_error("Bad code object in .pyc file".to_owned()))?;
88-
self.run_code_obj(code, scope)?;
89-
} else {
90-
if path != "<stdin>" {
91-
set_main_loader(&module_dict, path, "SourceFileLoader", self)?;
92-
}
93-
// TODO: replace to something equivalent to py_run_file
94-
match std::fs::read_to_string(path) {
95-
Ok(source) => {
96-
let code_obj = self
97-
.compile(&source, compiler::Mode::Exec, path.to_owned())
98-
.map_err(|err| self.new_syntax_error(&err, Some(&source)))?;
99-
// trace!("Code object: {:?}", code_obj.borrow());
100-
self.run_code_obj(code_obj, scope)?;
101-
}
102-
Err(err) => {
103-
error!("Failed reading file '{path}': {err}");
104-
// TODO: Need to change to ExitCode or Termination
105-
std::process::exit(1);
106-
}
107-
}
108-
}
109-
Ok(())
110-
}
111-
112-
// TODO: deprecate or reimplement using other primitive functions
113-
pub fn run_code_string(&self, scope: Scope, source: &str, source_path: String) -> PyResult {
114-
let code_obj = self
115-
.compile(source, compiler::Mode::Exec, source_path.clone())
116-
.map_err(|err| self.new_syntax_error(&err, Some(source)))?;
117-
// trace!("Code object: {:?}", code_obj.borrow());
118-
// Only set __file__ for real file paths, not pseudo-paths like <string>
119-
if !(source_path.starts_with('<') && source_path.ends_with('>')) {
120-
scope.globals.set_item(
121-
identifier!(self, __file__),
122-
self.new_pyobj(source_path),
123-
self,
124-
)?;
125-
}
126-
self.run_code_obj(code_obj, scope)
127-
}
128-
129-
pub fn run_block_expr(&self, scope: Scope, source: &str) -> PyResult {
130-
let code_obj = self
131-
.compile(source, compiler::Mode::BlockExpr, "<embedded>".to_owned())
132-
.map_err(|err| self.new_syntax_error(&err, Some(source)))?;
133-
// trace!("Code object: {:?}", code_obj.borrow());
134-
self.run_code_obj(code_obj, scope)
135-
}
136-
}
137-
138-
fn set_main_loader(
139-
module_dict: &PyDictRef,
140-
filename: &str,
141-
loader_name: &str,
142-
vm: &VirtualMachine,
143-
) -> PyResult<()> {
144-
vm.import("importlib.machinery", 0)?;
145-
let sys_modules = vm.sys_module.get_attr(identifier!(vm, modules), vm)?;
146-
let machinery = sys_modules.get_item("importlib.machinery", vm)?;
147-
let loader_name = vm.ctx.new_str(loader_name);
148-
let loader_class = machinery.get_attr(&loader_name, vm)?;
149-
let loader = loader_class.call((identifier!(vm, __main__).to_owned(), filename), vm)?;
150-
module_dict.set_item("__loader__", loader, vm)?;
151-
Ok(())
152-
}
153-
154-
/// Check whether a file is maybe a pyc file.
155-
///
156-
/// Detection is performed by:
157-
/// 1. Checking if the filename ends with ".pyc"
158-
/// 2. If not, reading the first 2 bytes and comparing with the magic number
159-
fn maybe_pyc_file(path: &str) -> bool {
160-
// 1. Check if filename ends with ".pyc"
161-
if path.ends_with(".pyc") {
162-
return true;
163-
}
164-
maybe_pyc_file_with_magic(path, &crate::version::PYC_MAGIC_NUMBER_BYTES).unwrap_or(false)
165-
}
166-
167-
fn maybe_pyc_file_with_magic(path: &str, magic_number: &[u8]) -> std::io::Result<bool> {
168-
// part of maybe_pyc_file
169-
// For non-.pyc extension, check magic number
170-
let path_obj = std::path::Path::new(path);
171-
if !path_obj.is_file() {
172-
return Ok(false);
173-
}
174-
175-
let mut file = std::fs::File::open(path)?;
176-
let mut buf = [0u8; 2];
177-
178-
use std::io::Read;
179-
if file.read(&mut buf)? != 2 || magic_number.len() < 2 {
180-
return Ok(false);
181-
}
182-
183-
// Read only two bytes of the magic. If the file was opened in
184-
// text mode, the bytes 3 and 4 of the magic (\r\n) might not
185-
// be read as they are on disk.
186-
Ok(buf == magic_number[..2])
187-
}
188-
189-
fn get_importer(path: &str, vm: &VirtualMachine) -> PyResult<Option<PyObjectRef>> {
190-
let path_importer_cache = vm.sys_module.get_attr("path_importer_cache", vm)?;
191-
let path_importer_cache = PyDictRef::try_from_object(vm, path_importer_cache)?;
192-
if let Some(importer) = path_importer_cache.get_item_opt(path, vm)? {
193-
return Ok(Some(importer));
194-
}
195-
let path = vm.ctx.new_str(path);
196-
let path_hooks = vm.sys_module.get_attr("path_hooks", vm)?;
197-
let mut importer = None;
198-
let path_hooks: Vec<PyObjectRef> = path_hooks.try_into_value(vm)?;
199-
for path_hook in path_hooks {
200-
match path_hook.call((path.clone(),), vm) {
201-
Ok(imp) => {
202-
importer = Some(imp);
203-
break;
204-
}
205-
Err(e) if e.fast_isinstance(vm.ctx.exceptions.import_error) => continue,
206-
Err(e) => return Err(e),
207-
}
208-
}
209-
Ok(if let Some(imp) = importer {
210-
let imp = path_importer_cache.get_or_insert(vm, path.into(), || imp.clone())?;
211-
Some(imp)
212-
} else {
213-
None
214-
})
21530
}

crates/vm/src/vm/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mod compile;
88
mod context;
99
mod interpreter;
1010
mod method;
11+
#[cfg(feature = "rustpython-compiler")]
12+
mod pythonrun;
1113
mod setting;
1214
pub mod thread;
1315
mod vm_new;

0 commit comments

Comments
 (0)