@@ -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
4649impl 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" ) ]
83103pub 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