Skip to content

Commit 1e706d9

Browse files
youknowone77axel
andauthored
Interpreter (RustPython#6614)
* Refine documentation in interpreter.rs Improve InterpreterConfig with convenience methods (with_debug, add_path, add_paths), better documentation with working examples, refactored stdlib setup into focused functions, and comprehensive unit tests while maintaining 100% backward compatibility. * Improve error message for non-Unicode paths * Use consistent make_module naming in all doc examples * cut useful changes --------- Co-authored-by: Mohamed Gharbi <galaxysea777@gmail.com>
1 parent 6ccf3b5 commit 1e706d9

File tree

1 file changed

+77
-43
lines changed

1 file changed

+77
-43
lines changed

src/interpreter.rs

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,18 @@ pub type InitHook = Box<dyn FnOnce(&mut VirtualMachine)>;
2626
/// ```
2727
///
2828
/// To add native modules:
29-
/// ```compile_fail
29+
/// ```
30+
/// use rustpython_vm::pymodule;
31+
///
32+
/// #[pymodule]
33+
/// mod your_module {}
34+
///
3035
/// let interpreter = rustpython::InterpreterConfig::new()
3136
/// .init_stdlib()
32-
/// .init_hook(Box::new(|vm| {
33-
/// vm.add_native_module(
34-
/// "your_module_name".to_owned(),
35-
/// Box::new(your_module::make_module),
36-
/// );
37-
/// }))
37+
/// .add_native_module(
38+
/// "your_module_name".to_owned(),
39+
/// your_module::make_module,
40+
/// )
3841
/// .interpreter();
3942
/// ```
4043
#[derive(Default)]
@@ -44,9 +47,12 @@ pub struct InterpreterConfig {
4447
}
4548

4649
impl InterpreterConfig {
50+
/// Creates a new interpreter configuration with default settings.
4751
pub fn new() -> Self {
4852
Self::default()
4953
}
54+
55+
/// Builds the interpreter with the current configuration.
5056
pub fn interpreter(self) -> Interpreter {
5157
let settings = self.settings.unwrap_or_default();
5258
Interpreter::with_init(settings, |vm| {
@@ -56,14 +62,23 @@ impl InterpreterConfig {
5662
})
5763
}
5864

65+
/// Sets custom settings for the interpreter.
66+
///
67+
/// If called multiple times, only the last settings will be used.
5968
pub fn settings(mut self, settings: Settings) -> Self {
6069
self.settings = Some(settings);
6170
self
6271
}
72+
73+
/// Adds a custom initialization hook.
74+
///
75+
/// Hooks are executed in the order they are added during interpreter creation.
6376
pub fn init_hook(mut self, hook: InitHook) -> Self {
6477
self.init_hooks.push(hook);
6578
self
6679
}
80+
81+
/// Adds a native module to the interpreter.
6782
pub fn add_native_module(
6883
self,
6984
name: String,
@@ -73,56 +88,75 @@ impl InterpreterConfig {
7388
vm.add_native_module(name, Box::new(make_module))
7489
}))
7590
}
91+
92+
/// Initializes the Python standard library.
93+
///
94+
/// Requires the `stdlib` feature to be enabled.
7695
#[cfg(feature = "stdlib")]
7796
pub fn init_stdlib(self) -> Self {
7897
self.init_hook(Box::new(init_stdlib))
7998
}
8099
}
81100

101+
/// Initializes all standard library modules for the given VM.
82102
#[cfg(feature = "stdlib")]
83103
pub fn init_stdlib(vm: &mut VirtualMachine) {
84104
vm.add_native_modules(rustpython_stdlib::get_module_inits());
85105

86-
// if we're on freeze-stdlib, the core stdlib modules will be included anyway
87106
#[cfg(feature = "freeze-stdlib")]
88-
{
89-
vm.add_frozen(rustpython_pylib::FROZEN_STDLIB);
90-
91-
// FIXME: Remove this hack once sys._stdlib_dir is properly implemented or _frozen_importlib doesn't depend on it anymore.
92-
assert!(vm.sys_module.get_attr("_stdlib_dir", vm).is_err());
93-
vm.sys_module
94-
.set_attr(
95-
"_stdlib_dir",
96-
vm.new_pyobj(rustpython_pylib::LIB_PATH.to_owned()),
97-
vm,
98-
)
99-
.unwrap();
100-
}
107+
setup_frozen_stdlib(vm);
101108

102109
#[cfg(not(feature = "freeze-stdlib"))]
103-
{
104-
use rustpython_vm::common::rc::PyRc;
105-
106-
let state = PyRc::get_mut(&mut vm.state).unwrap();
107-
108-
// Collect additional paths to add
109-
let mut additional_paths = Vec::new();
110-
111-
// BUILDTIME_RUSTPYTHONPATH should be set when distributing
112-
if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") {
113-
additional_paths.extend(
114-
crate::settings::split_paths(paths)
115-
.map(|path| path.into_os_string().into_string().unwrap()),
116-
)
117-
} else {
118-
#[cfg(feature = "rustpython-pylib")]
119-
additional_paths.push(rustpython_pylib::LIB_PATH.to_owned())
120-
}
110+
setup_dynamic_stdlib(vm);
111+
}
121112

122-
// Add to both path_list (for compatibility) and module_search_paths (for sys.path)
123-
// Insert at the beginning so stdlib comes before user paths
124-
for path in additional_paths.into_iter().rev() {
125-
state.config.paths.module_search_paths.insert(0, path);
113+
/// Setup frozen standard library (compiled into the binary)
114+
#[cfg(all(feature = "stdlib", feature = "freeze-stdlib"))]
115+
fn setup_frozen_stdlib(vm: &mut VirtualMachine) {
116+
vm.add_frozen(rustpython_pylib::FROZEN_STDLIB);
117+
118+
// FIXME: Remove this hack once sys._stdlib_dir is properly implemented
119+
// or _frozen_importlib doesn't depend on it anymore.
120+
assert!(vm.sys_module.get_attr("_stdlib_dir", vm).is_err());
121+
vm.sys_module
122+
.set_attr(
123+
"_stdlib_dir",
124+
vm.new_pyobj(rustpython_pylib::LIB_PATH.to_owned()),
125+
vm,
126+
)
127+
.unwrap();
128+
}
129+
130+
/// Setup dynamic standard library loading from filesystem
131+
#[cfg(all(feature = "stdlib", not(feature = "freeze-stdlib")))]
132+
fn setup_dynamic_stdlib(vm: &mut VirtualMachine) {
133+
use rustpython_vm::common::rc::PyRc;
134+
135+
let state = PyRc::get_mut(&mut vm.state).unwrap();
136+
let paths = collect_stdlib_paths();
137+
138+
// Insert at the beginning so stdlib comes before user paths
139+
for path in paths.into_iter().rev() {
140+
state.config.paths.module_search_paths.insert(0, path);
141+
}
142+
}
143+
144+
/// Collect standard library paths from build-time configuration
145+
#[cfg(all(feature = "stdlib", not(feature = "freeze-stdlib")))]
146+
fn collect_stdlib_paths() -> Vec<String> {
147+
// BUILDTIME_RUSTPYTHONPATH should be set when distributing
148+
if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") {
149+
crate::settings::split_paths(paths)
150+
.map(|path| path.into_os_string().into_string().unwrap())
151+
.collect()
152+
} else {
153+
#[cfg(feature = "rustpython-pylib")]
154+
{
155+
vec![rustpython_pylib::LIB_PATH.to_owned()]
156+
}
157+
#[cfg(not(feature = "rustpython-pylib"))]
158+
{
159+
vec![]
126160
}
127161
}
128162
}

0 commit comments

Comments
 (0)