Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Use lexopt for argument parsing #5602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 7 additions & 26 deletions 33 Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion 2 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ cfg-if = { workspace = true }
log = { workspace = true }
flame = { workspace = true, optional = true }

clap = "2.34"
lexopt = "0.3"
dirs = { package = "dirs-next", version = "2.0.0" }
env_logger = { version = "0.9.0", default-features = false, features = ["atty", "termcolor"] }
flamescope = { version = "0.1.2", optional = true }
Expand Down
8 changes: 0 additions & 8 deletions 8 Lib/test/test_cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ def verify_valid_flag(self, cmd_line):
self.assertNotIn(b'Traceback', err)
return out

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_help(self):
self.verify_valid_flag('-h')
self.verify_valid_flag('-?')
Expand Down Expand Up @@ -82,8 +80,6 @@ def test_optimize(self):
def test_site_flag(self):
self.verify_valid_flag('-S')

# NOTE: RUSTPYTHON version never starts with Python
@unittest.expectedFailure
def test_version(self):
version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii")
for switch in '-V', '--version', '-VV':
Expand Down Expand Up @@ -550,8 +546,6 @@ def test_no_stderr(self):
def test_no_std_streams(self):
self._test_no_stdio(['stdin', 'stdout', 'stderr'])

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_hash_randomization(self):
# Verify that -R enables hash randomization:
self.verify_valid_flag('-R')
Expand Down Expand Up @@ -966,8 +960,6 @@ def test_ignore_PYTHONPATH(self):
self.run_ignoring_vars("'{}' not in sys.path".format(path),
PYTHONPATH=path)

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_ignore_PYTHONHASHSEED(self):
self.run_ignoring_vars("sys.flags.hash_randomization == 1",
PYTHONHASHSEED="0")
Expand Down
86 changes: 40 additions & 46 deletions 86 examples/dis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,67 +6,59 @@
/// example usage:
/// $ cargo run --release --example dis demo*.py

#[macro_use]
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;

use clap::{App, Arg};
use lexopt::ValueExt;
use rustpython_compiler as compiler;
use std::error::Error;
use std::fs;
use std::path::Path;
use std::path::{Path, PathBuf};

fn main() {
fn main() -> Result<(), lexopt::Error> {
env_logger::init();
let app = App::new("dis")
.version(crate_version!())
.author(crate_authors!())
.about("Compiles and disassembles python script files for viewing their bytecode.")
.arg(
Arg::with_name("scripts")
.help("Scripts to scan")
.multiple(true)
.required(true),
)
.arg(
Arg::with_name("mode")
.help("The mode to compile the scripts in")
.long("mode")
.short("m")
.default_value("exec")
.possible_values(&["exec", "single", "eval"])
.takes_value(true),
)
.arg(
Arg::with_name("no_expand")
.help(
"Don't expand CodeObject LoadConst instructions to show \
the instructions inside",
)
.long("no-expand")
.short("x"),
)
.arg(
Arg::with_name("optimize")
.help("The amount of optimization to apply to the compiled bytecode")
.short("O")
.multiple(true),
);
let matches = app.get_matches();

let mode = matches.value_of_lossy("mode").unwrap().parse().unwrap();
let expand_code_objects = !matches.is_present("no_expand");
let optimize = matches.occurrences_of("optimize") as u8;
let scripts = matches.values_of_os("scripts").unwrap();
let mut scripts = vec![];
let mut mode = compiler::Mode::Exec;
let mut expand_code_objects = true;
let mut optimize = 0;

let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
use lexopt::Arg::*;
match arg {
Long("help") | Short('h') => {
let bin_name = parser.bin_name().unwrap_or("dis");
println!(
"usage: {bin_name} <scripts...> [-m,--mode=exec|single|eval] [-x,--no-expand] [-O]"
);
println!(
"Compiles and disassembles python script files for viewing their bytecode."
);
return Ok(());
}
Value(x) => scripts.push(PathBuf::from(x)),
Long("mode") | Short('m') => {
mode = parser
.value()?
.parse_with(|s| s.parse::<compiler::Mode>().map_err(|e| e.to_string()))?
}
Long("no-expand") | Short('x') => expand_code_objects = false,
Short('O') => optimize += 1,
_ => return Err(arg.unexpected()),
}
}

if scripts.is_empty() {
return Err("expected at least one argument".into());
}

let opts = compiler::CompileOpts {
optimize,
..Default::default()
};

for script in scripts.map(Path::new) {
for script in &scripts {
if script.exists() && script.is_file() {
let res = display_script(script, mode, opts.clone(), expand_code_objects);
if let Err(e) = res {
Expand All @@ -76,6 +68,8 @@ fn main() {
eprintln!("{script:?} is not a file.");
}
}

Ok(())
}

fn display_script(
Expand Down
24 changes: 7 additions & 17 deletions 24 examples/parse_folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,28 @@
///
/// example usage:
/// $ RUST_LOG=info cargo run --release parse_folder /usr/lib/python3.7

#[macro_use]
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;

use clap::{App, Arg};
use rustpython_parser::{Parse, ast};
use std::{
path::Path,
path::{Path, PathBuf},
time::{Duration, Instant},
};

fn main() {
env_logger::init();
let app = App::new("parse_folders")
.version(crate_version!())
.author(crate_authors!())
.about("Walks over all .py files in a folder, and parses them.")
.arg(
Arg::with_name("folder")
.help("Folder to scan")
.required(true),
);
let matches = app.get_matches();

let folder = Path::new(matches.value_of("folder").unwrap());
let folder: PathBuf = std::env::args_os()
.nth(1)
.expect("please pass a path argument")
.into();

if folder.exists() && folder.is_dir() {
println!("Parsing folder of python code: {folder:?}");
let t1 = Instant::now();
let parsed_files = parse_folder(folder).unwrap();
let parsed_files = parse_folder(&folder).unwrap();
let t2 = Instant::now();
let results = ScanResult {
t1,
Expand Down
13 changes: 8 additions & 5 deletions 13 src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@
//! it will have your modules loaded into the vm.
#![allow(clippy::needless_doctest_main)]

#[macro_use]
extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;

Expand All @@ -57,7 +54,7 @@ use std::process::ExitCode;

pub use interpreter::InterpreterConfig;
pub use rustpython_vm as vm;
pub use settings::{InstallPipMode, RunMode, opts_with_clap};
pub use settings::{InstallPipMode, RunMode, parse_opts};
pub use shell::run_shell;

/// The main cli of the `rustpython` interpreter. This function will return `std::process::ExitCode`
Expand All @@ -73,7 +70,13 @@ pub fn run(init: impl FnOnce(&mut VirtualMachine) + 'static) -> ExitCode {
};
}

let (settings, run_mode) = opts_with_clap();
let (settings, run_mode) = match parse_opts() {
Ok(x) => x,
Err(e) => {
println!("{e}");
return ExitCode::FAILURE;
}
};

// don't translate newlines (\r\n <=> \n)
#[cfg(windows)]
Expand Down
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.