1+ //! Python code compilation functions.
2+ //!
3+ //! For code execution functions, see pythonrun.rs
4+
15use 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
911impl 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}
0 commit comments