@@ -759,28 +759,55 @@ impl<'a> Interpreter<'a> {
759759 _state : & mut State ,
760760 ) -> BodyInterpretation {
761761 use rustpython_vm as vm;
762- let interp = vm:: Interpreter :: with_init ( vm:: Settings :: default ( ) , |vm| {
763- //vm.add_native_modules(rustpython_stdlib::get_module_inits());
762+
763+ let mut settings = rustpython_vm:: Settings :: default ( ) ;
764+
765+ // add PYTHONPATH to sys.path
766+ settings. path_list . extend ( get_paths ( "PDLPYTHONPATH" ) ) ;
767+ settings. path_list . extend ( get_paths ( "PYTHONPATH" ) ) ;
768+
769+ if let Ok ( venv) = :: std:: env:: var ( "VIRTUAL_ENV" ) {
770+ let path = :: std:: path:: PathBuf :: from ( venv) . join ( if cfg ! ( windows) {
771+ "lib/site-packages"
772+ } else {
773+ // TODO generalize this!
774+ "lib/python3.12/site-packages"
775+ } ) ;
776+ settings = settings. with_path ( path. display ( ) . to_string ( ) ) ;
777+ }
778+
779+ let interp = vm:: Interpreter :: with_init ( settings, |vm| {
780+ vm. add_native_modules ( rustpython_stdlib:: get_module_inits ( ) ) ;
764781 vm. add_frozen ( rustpython_pylib:: FROZEN_STDLIB ) ;
765782 } ) ;
766783 interp. enter ( |vm| -> BodyInterpretation {
767784 let scope = vm. new_scope_with_builtins ( ) ;
768785
769- // TODO vm.new_syntax_error(&err, Some(block.code.as_str()))
770- let code_obj = match vm. compile (
771- block. code . as_str ( ) ,
772- vm:: compiler:: Mode :: Exec ,
786+ // Sigh, this is copy-pasted from RustPython/src/lib.rs
787+ // `run_rustpython` as of 20250416 commit hash
788+ // a917da3b1. Without this (and also: importlib and
789+ // encodings features on rustpython-vm crate), then
790+ // pulling in venvs does not work.
791+ match vm. run_code_string (
792+ vm. new_scope_with_builtins ( ) ,
793+ "import sys; sys.path.insert(0, '')" ,
773794 "<embedded>" . to_owned ( ) ,
774795 ) {
775- Ok ( x ) => Ok ( x ) ,
776- Err ( exc) => Err ( PdlError :: from ( format ! (
777- "Syntax error in Python code {:?}" ,
778- exc
779- ) ) ) ,
796+ Ok ( _ ) => Ok ( ( ) ) ,
797+ Err ( exc) => {
798+ vm . print_exception ( exc ) ;
799+ Err ( PdlError :: from ( "Error setting up Python site path" ) )
800+ }
780801 } ?;
802+ let site_result = vm. import ( "site" , 0 ) ;
803+ if site_result. is_err ( ) {
804+ println ! (
805+ "Failed to import site, consider adding the Lib directory to your RUSTPYTHONPATH \
806+ environment variable",
807+ ) ;
808+ }
781809
782- // TODO vm.print_exception(exc);
783- match vm. run_code_obj ( code_obj, scope. clone ( ) ) {
810+ match vm. run_code_string ( scope. clone ( ) , block. code . as_str ( ) , "<embedded>" . to_owned ( ) ) {
784811 Ok ( _) => Ok ( ( ) ) ,
785812 Err ( exc) => {
786813 vm. print_exception ( exc) ;
@@ -1500,3 +1527,30 @@ pub fn load_scope(
15001527
15011528 Ok ( scope)
15021529}
1530+
1531+ /// Helper function to retrieve a sequence of paths from an environment variable.
1532+ fn get_paths ( env_variable_name : & str ) -> impl Iterator < Item = String > + ' _ {
1533+ :: std:: env:: var_os ( env_variable_name)
1534+ . into_iter ( )
1535+ . flat_map ( move |paths| {
1536+ split_paths ( & paths)
1537+ . map ( |path| {
1538+ path. into_os_string ( )
1539+ . into_string ( )
1540+ . unwrap_or_else ( |_| panic ! ( "{env_variable_name} isn't valid unicode" ) )
1541+ } )
1542+ . collect :: < Vec < _ > > ( )
1543+ } )
1544+ }
1545+
1546+ #[ cfg( not( target_os = "wasi" ) ) ]
1547+ pub ( crate ) use :: std:: env:: split_paths;
1548+ #[ cfg( target_os = "wasi" ) ]
1549+ pub ( crate ) fn split_paths < T : AsRef < std:: ffi:: OsStr > + ?Sized > (
1550+ s : & T ,
1551+ ) -> impl Iterator < Item = std:: path:: PathBuf > + ' _ {
1552+ use std:: os:: wasi:: ffi:: OsStrExt ;
1553+ let s = s. as_ref ( ) . as_bytes ( ) ;
1554+ s. split ( |b| * b == b':' )
1555+ . map ( |x| std:: ffi:: OsStr :: from_bytes ( x) . to_owned ( ) . into ( ) )
1556+ }
0 commit comments