Skip to content

Commit 076b975

Browse files
committed
Make argument parsing fully match CPython's
1 parent f336263 commit 076b975

File tree

1 file changed

+45
-38
lines changed

1 file changed

+45
-38
lines changed

src/main.rs

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ extern crate env_logger;
44
#[macro_use]
55
extern crate log;
66

7-
use clap::{App, Arg, ArgMatches};
7+
use clap::{App, AppSettings, Arg, ArgMatches};
88
use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType};
99
use rustpython_parser::error::ParseErrorType;
1010
use rustpython_vm::{
@@ -47,17 +47,38 @@ fn main() {
4747

4848
fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
4949
let app = app
50+
.setting(AppSettings::TrailingVarArg)
5051
.version(crate_version!())
5152
.author(crate_authors!())
5253
.about("Rust implementation of the Python language")
5354
.usage("rustpython [OPTIONS] [-c CMD | -m MODULE | FILE | -] [PYARGS]...")
5455
.arg(
5556
Arg::with_name("script")
5657
.required(false)
58+
.allow_hyphen_values(true)
59+
.multiple(true)
60+
.value_name("script, args")
61+
.min_values(1),
62+
)
63+
.arg(
64+
Arg::with_name("c")
65+
.short("c")
66+
.takes_value(true)
67+
.allow_hyphen_values(true)
5768
.multiple(true)
69+
.value_name("cmd, args")
5870
.min_values(1)
71+
.help("run the given string as a program"),
72+
)
73+
.arg(
74+
Arg::with_name("m")
75+
.short("m")
76+
.takes_value(true)
5977
.allow_hyphen_values(true)
60-
.value_names(&["script", "args..."]),
78+
.multiple(true)
79+
.value_name("module, args")
80+
.min_values(1)
81+
.help("run library module as script"),
6182
)
6283
.arg(
6384
Arg::with_name("optimize")
@@ -101,22 +122,6 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
101122
Arg::with_name("ignore-environment")
102123
.short("E")
103124
.help("Ignore environment variables PYTHON* such as PYTHONPATH"),
104-
)
105-
.arg(
106-
Arg::with_name("c")
107-
.short("c")
108-
.takes_value(true)
109-
.help("run the given string as a program"),
110-
)
111-
.arg(
112-
Arg::with_name("m")
113-
.short("m")
114-
.takes_value(true)
115-
.allow_hyphen_values(true)
116-
.multiple(true)
117-
// .value
118-
.value_names(&["module", "args..."])
119-
.help("run library module as script"),
120125
);
121126
#[cfg(feature = "flame-it")]
122127
let app = app
@@ -142,6 +147,9 @@ fn create_settings(matches: &ArgMatches) -> PySettings {
142147
let mut settings: PySettings = Default::default();
143148
settings.ignore_environment = ignore_environment;
144149

150+
// add the current directory to sys.path
151+
settings.path_list.push("".to_owned());
152+
145153
if !ignore_environment {
146154
settings.path_list.append(&mut get_paths("RUSTPYTHONPATH"));
147155
settings.path_list.append(&mut get_paths("PYTHONPATH"));
@@ -193,32 +201,20 @@ fn create_settings(matches: &ArgMatches) -> PySettings {
193201
settings.dont_write_bytecode = true;
194202
}
195203

196-
let mut argv = if let Some(script) = matches.values_of("script") {
204+
let argv = if let Some(script) = matches.values_of("script") {
197205
script.map(ToOwned::to_owned).collect()
198-
} else if let Some(mut module) = matches.values_of("m") {
199-
let argv0 = if let Ok(module_path) = std::fs::canonicalize(module.next().unwrap()) {
200-
module_path
201-
.into_os_string()
202-
.into_string()
203-
.expect("invalid utf8 in module path")
204-
} else {
205-
// if it's not a real file/don't have permissions it'll probably fail anyway
206-
String::new()
207-
};
208-
std::iter::once(argv0)
209-
.chain(module.map(ToOwned::to_owned))
206+
} else if let Some(module) = matches.values_of("m") {
207+
std::iter::once("PLACEHOLEDER".to_owned())
208+
.chain(module.skip(1).map(ToOwned::to_owned))
209+
.collect()
210+
} else if let Some(cmd) = matches.values_of("c") {
211+
std::iter::once("-c".to_owned())
212+
.chain(cmd.skip(1).map(ToOwned::to_owned))
210213
.collect()
211214
} else {
212215
vec![]
213216
};
214217

215-
argv.extend(
216-
matches
217-
.values_of("pyargs")
218-
.unwrap_or_default()
219-
.map(ToOwned::to_owned),
220-
);
221-
222218
settings.argv = argv;
223219

224220
settings
@@ -357,6 +353,17 @@ fn run_command(vm: &VirtualMachine, source: String) -> PyResult<()> {
357353

358354
fn run_module(vm: &VirtualMachine, module: &str) -> PyResult<()> {
359355
debug!("Running module {}", module);
356+
let importlib = vm.import("_frozen_importlib", &vm.ctx.new_tuple(vec![]), 0)?;
357+
let find_spec = vm.get_attribute(importlib, "_find_spec")?;
358+
let spec = vm.invoke(
359+
find_spec,
360+
vec![vm.ctx.new_str(module.to_owned()), vm.get_none()],
361+
)?;
362+
if !vm.is_none(&spec) {
363+
let origin = vm.get_attribute(spec, "origin")?;
364+
let sys_path = vm.get_attribute(vm.sys_module.clone(), "argv")?;
365+
sys_path.set_item(0, origin, vm)?;
366+
}
360367
vm.import(module, &vm.ctx.new_tuple(vec![]), 0)?;
361368
Ok(())
362369
}

0 commit comments

Comments
 (0)