Skip to content

Commit 93dfbdc

Browse files
authored
Merge pull request RustPython#1144 from RustPython/env-var-processing
Move processing of PYTHONPATH out of vm.
2 parents f752c93 + cdfcf52 commit 93dfbdc

File tree

3 files changed

+116
-48
lines changed

3 files changed

+116
-48
lines changed

src/main.rs

Lines changed: 105 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,36 @@ use rustpython_vm::{
1717
};
1818
use std::convert::TryInto;
1919

20+
use std::env;
2021
use std::path::PathBuf;
2122
use std::process;
23+
use std::str::FromStr;
2224

2325
fn main() {
2426
#[cfg(feature = "flame-it")]
2527
let main_guard = flame::start_guard("RustPython main");
2628
env_logger::init();
27-
let app = App::new("RustPython")
29+
let app = App::new("RustPython");
30+
let matches = parse_arguments(app);
31+
let settings = create_settings(&matches);
32+
let vm = VirtualMachine::new(settings);
33+
34+
let res = run_rustpython(&vm, &matches);
35+
// See if any exception leaked out:
36+
handle_exception(&vm, res);
37+
38+
#[cfg(feature = "flame-it")]
39+
{
40+
main_guard.end();
41+
if let Err(e) = write_profile(&matches) {
42+
error!("Error writing profile information: {}", e);
43+
process::exit(1);
44+
}
45+
}
46+
}
47+
48+
fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
49+
let app = app
2850
.version(crate_version!())
2951
.author(crate_authors!())
3052
.about("Rust implementation of the Python language")
@@ -62,6 +84,11 @@ fn main() {
6284
.short("S")
6385
.help("don't imply 'import site' on initialization"),
6486
)
87+
.arg(
88+
Arg::with_name("ignore-environment")
89+
.short("E")
90+
.help("Ignore environment variables PYTHON* such as PYTHONPATH"),
91+
)
6592
.arg(
6693
Arg::with_name("c")
6794
.short("c")
@@ -89,38 +116,92 @@ fn main() {
89116
.takes_value(true)
90117
.help("the profile format to output the profiling information in"),
91118
);
92-
let matches = app.get_matches();
93-
94-
let opt_level: u8 = matches.occurrences_of("optimize").try_into().unwrap();
95-
let verbosity_level: u8 = matches.occurrences_of("verbose").try_into().unwrap();
119+
app.get_matches()
120+
}
96121

97-
// Construct vm:
122+
/// Create settings by examining command line arguments and environment
123+
/// variables.
124+
fn create_settings(matches: &ArgMatches) -> PySettings {
125+
let ignore_environment = matches.is_present("ignore-environment");
98126
let mut settings: PySettings = Default::default();
99-
settings.debug = matches.is_present("debug");
100-
settings.inspect = matches.is_present("inspect");
101-
settings.optimize = opt_level;
102-
settings.no_site = matches.is_present("no-site");
103-
settings.no_user_site = matches.is_present("no-user-site");
104-
settings.verbose = verbosity_level;
105-
settings.quiet = matches.is_present("quiet");
106-
let vm = VirtualMachine::new(settings);
127+
settings.ignore_environment = ignore_environment;
107128

108-
let res = run_rustpython(&vm, matches);
109-
// See if any exception leaked out:
110-
handle_exception(&vm, res);
129+
if !ignore_environment {
130+
settings.path_list.append(&mut get_paths("RUSTPYTHONPATH"));
131+
settings.path_list.append(&mut get_paths("PYTHONPATH"));
132+
}
111133

112-
#[cfg(feature = "flame-it")]
134+
// Now process command line flags:
135+
if matches.is_present("debug") || (!ignore_environment && env::var_os("PYTHONDEBUG").is_some())
113136
{
114-
main_guard.end();
115-
if let Err(e) = write_profile(matches) {
116-
error!("Error writing profile information: {}", e);
117-
process::exit(1);
137+
settings.debug = true;
138+
}
139+
140+
if matches.is_present("inspect")
141+
|| (!ignore_environment && env::var_os("PYTHONINSPECT").is_some())
142+
{
143+
settings.inspect = true;
144+
}
145+
146+
if matches.is_present("optimize") {
147+
settings.optimize = matches.occurrences_of("optimize").try_into().unwrap();
148+
} else if !ignore_environment {
149+
if let Ok(value) = get_env_var_value("PYTHONOPTIMIZE") {
150+
settings.optimize = value;
118151
}
119152
}
153+
154+
if matches.is_present("verbose") {
155+
settings.verbose = matches.occurrences_of("verbose").try_into().unwrap();
156+
} else if !ignore_environment {
157+
if let Ok(value) = get_env_var_value("PYTHONVERBOSE") {
158+
settings.verbose = value;
159+
}
160+
}
161+
162+
settings.no_site = matches.is_present("no-site");
163+
164+
if matches.is_present("no-user-site")
165+
|| (!ignore_environment && env::var_os("PYTHONNOUSERSITE").is_some())
166+
{
167+
settings.no_user_site = true;
168+
}
169+
170+
if matches.is_present("quiet") {
171+
settings.quiet = true;
172+
}
173+
174+
settings
175+
}
176+
177+
/// Get environment variable and turn it into integer.
178+
fn get_env_var_value(name: &str) -> Result<u8, std::env::VarError> {
179+
env::var(name).map(|value| {
180+
if let Ok(value) = u8::from_str(&value) {
181+
value
182+
} else {
183+
1
184+
}
185+
})
186+
}
187+
188+
/// Helper function to retrieve a sequence of paths from an environment variable.
189+
fn get_paths(env_variable_name: &str) -> Vec<String> {
190+
let paths = env::var_os(env_variable_name);
191+
match paths {
192+
Some(paths) => env::split_paths(&paths)
193+
.map(|path| {
194+
path.into_os_string()
195+
.into_string()
196+
.unwrap_or_else(|_| panic!("{} isn't valid unicode", env_variable_name))
197+
})
198+
.collect(),
199+
None => vec![],
200+
}
120201
}
121202

122203
#[cfg(feature = "flame-it")]
123-
fn write_profile(matches: ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
204+
fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
124205
use std::fs::File;
125206

126207
enum ProfileFormat {
@@ -163,7 +244,7 @@ fn write_profile(matches: ArgMatches) -> Result<(), Box<dyn std::error::Error>>
163244
Ok(())
164245
}
165246

166-
fn run_rustpython(vm: &VirtualMachine, matches: ArgMatches) -> PyResult<()> {
247+
fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> {
167248
import::init_importlib(&vm, true)?;
168249

169250
if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") {

vm/src/sysmodule.rs

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -163,30 +163,13 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR
163163
"cache_tag" => ctx.new_str("rustpython-01".to_string()),
164164
});
165165

166-
let path_list = if cfg!(target_arch = "wasm32") {
167-
vec![]
168-
} else {
169-
fn get_paths(env_variable_name: &str) -> Vec<String> {
170-
let paths = env::var_os(env_variable_name);
171-
match paths {
172-
Some(paths) => env::split_paths(&paths)
173-
.map(|path| {
174-
path.into_os_string()
175-
.into_string()
176-
.unwrap_or_else(|_| panic!("{} isn't valid unicode", env_variable_name))
177-
})
178-
.collect(),
179-
None => vec![],
180-
}
181-
}
182-
183-
get_paths("RUSTPYTHONPATH")
184-
.into_iter()
185-
.chain(get_paths("PYTHONPATH").into_iter())
186-
.map(|path| ctx.new_str(path))
187-
.collect()
188-
};
189-
let path = ctx.new_list(path_list);
166+
let path = ctx.new_list(
167+
vm.settings
168+
.path_list
169+
.iter()
170+
.map(|path| ctx.new_str(path.clone()))
171+
.collect(),
172+
);
190173

191174
let platform = if cfg!(target_os = "linux") {
192175
"linux".to_string()

vm/src/vm.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ pub struct PySettings {
8888

8989
/// -q
9090
pub quiet: bool,
91+
92+
/// Environment PYTHONPATH and RUSTPYTHONPATH:
93+
pub path_list: Vec<String>,
9194
}
9295

9396
/// Trace events for sys.settrace and sys.setprofile.
@@ -118,6 +121,7 @@ impl Default for PySettings {
118121
ignore_environment: false,
119122
verbose: 0,
120123
quiet: false,
124+
path_list: vec![],
121125
}
122126
}
123127
}

0 commit comments

Comments
 (0)