diff --git a/src/main.rs b/src/main.rs index 136007857..48bf381db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,13 +64,13 @@ fn main() { return; } if let Ok(s) = vm.to_str(&arg) { - println!("{}", s); + eprintln!("{}", s); } } }), _ => { if let Ok(r) = vm.to_repr(args.as_object()) { - println!("{}", r); + eprintln!("{}", r); } } } @@ -158,6 +158,17 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { Arg::with_name("ignore-environment") .short("E") .help("Ignore environment variables PYTHON* such as PYTHONPATH"), + ) + .arg( + Arg::with_name("isolate") + .short("I") + .help("isolate Python from the user's environment (implies -E and -s)"), + ) + .arg( + Arg::with_name("implementation-option") + .short("X") + .takes_value(true) + .help("set implementation-specific option"), ); #[cfg(feature = "flame-it")] let app = app @@ -179,7 +190,8 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { /// Create settings by examining command line arguments and environment /// variables. fn create_settings(matches: &ArgMatches) -> PySettings { - let ignore_environment = matches.is_present("ignore-environment"); + let ignore_environment = + matches.is_present("ignore-environment") || matches.is_present("isolate"); let mut settings: PySettings = Default::default(); settings.ignore_environment = ignore_environment; @@ -232,6 +244,7 @@ fn create_settings(matches: &ArgMatches) -> PySettings { settings.no_site = matches.is_present("no-site"); if matches.is_present("no-user-site") + || matches.is_present("isolate") || (!ignore_environment && env::var_os("PYTHONNOUSERSITE").is_some()) { settings.no_user_site = true; diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index 56faa5ede..a20af790b 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -661,6 +661,19 @@ fn key_error_str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStringRef { } } +fn system_exit_code(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyObjectRef { + match exc.args.read().as_slice().first() { + Some(code) => match_class!(match code { + ref tup @ PyTuple => match tup.as_slice() { + [x] => x.clone(), + _ => code.clone(), + }, + other => other.clone(), + }), + None => vm.get_none(), + } +} + pub fn init(ctx: &PyContext) { let excs = &ctx.exceptions; @@ -676,7 +689,7 @@ pub fn init(ctx: &PyContext) { }); extend_class!(ctx, &excs.system_exit, { - "code" => ctx.new_readonly_getset("code", make_arg_getter(0)), + "code" => ctx.new_readonly_getset("code", system_exit_code), }); extend_class!(ctx, &excs.import_error, { diff --git a/vm/src/import.rs b/vm/src/import.rs index c36c15827..f6d51944e 100644 --- a/vm/src/import.rs +++ b/vm/src/import.rs @@ -45,7 +45,7 @@ pub fn init_importlib(vm: &mut VirtualMachine, initialize_parameter: InitParamet Ok(()) })(); if zipimport_res.is_err() { - eprintln!("couldn't init zipimport") + warn!("couldn't init zipimport") } } InitParameter::NoInitialize => { diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index eb4fe3757..b9f74875d 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -1,8 +1,10 @@ +use num_traits::ToPrimitive; use std::{env, mem, path}; use crate::frame::FrameRef; use crate::function::{Args, OptionalArg, PyFuncArgs}; use crate::obj::objstr::PyStringRef; +use crate::obj::objtype::PyClassRef; use crate::pyobject::{IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult}; use crate::vm::{PySettings, VirtualMachine}; use crate::{builtins, exceptions, py_io, version}; @@ -26,7 +28,11 @@ fn argv(vm: &VirtualMachine) -> PyObjectRef { fn executable(ctx: &PyContext) -> PyObjectRef { if let Some(exec_path) = env::args().next() { - if path::Path::new(&exec_path).is_absolute() { + let path = path::Path::new(&exec_path); + if !path.exists() { + return ctx.new_str(""); + } + if path.is_absolute() { return ctx.new_str(exec_path); } if let Ok(dir) = env::current_dir() { @@ -67,50 +73,50 @@ fn getframe(offset: OptionalArg, vm: &VirtualMachine) -> PyResult Self { // Start with sensible defaults: let mut flags: SysFlags = Default::default(); - flags.debug = settings.debug; - flags.inspect = settings.inspect; + flags.debug = settings.debug as u8; + flags.inspect = settings.inspect as u8; flags.optimize = settings.optimize; - flags.no_user_site = settings.no_user_site; - flags.no_site = settings.no_site; - flags.ignore_environment = settings.ignore_environment; + flags.no_user_site = settings.no_user_site as u8; + flags.no_site = settings.no_site as u8; + flags.ignore_environment = settings.ignore_environment as u8; flags.verbose = settings.verbose; - flags.quiet = settings.quiet; - flags.dont_write_bytecode = settings.dont_write_bytecode; + flags.quiet = settings.quiet as u8; + flags.dont_write_bytecode = settings.dont_write_bytecode as u8; flags } } @@ -173,7 +179,13 @@ fn sys_getrecursionlimit(vm: &VirtualMachine) -> usize { vm.recursion_limit.get() } -fn sys_setrecursionlimit(recursion_limit: usize, vm: &VirtualMachine) -> PyResult { +fn sys_setrecursionlimit(recursion_limit: i32, vm: &VirtualMachine) -> PyResult { + let recursion_limit = recursion_limit + .to_usize() + .filter(|&u| u >= 1) + .ok_or_else(|| { + vm.new_value_error("recursion limit must be greater than or equal to one".to_owned()) + })?; let recursion_depth = vm.frames.borrow().len(); if recursion_limit > recursion_depth + 1 { @@ -209,7 +221,7 @@ fn sys_git_info(vm: &VirtualMachine) -> PyObjectRef { } fn sys_exit(code: OptionalArg, vm: &VirtualMachine) -> PyResult { - let code = code.unwrap_or_else(|| vm.new_int(0)); + let code = code.unwrap_or_else(|| vm.get_none()); Err(vm.new_exception(vm.ctx.exceptions.system_exit.clone(), vec![code])) } @@ -350,7 +362,6 @@ pub fn sysconfigdata_name() -> String { } #[pystruct_sequence(module = "sys", name = "hash_info")] -#[derive(Debug)] struct PyHashInfo { width: usize, modulus: PyUHash, @@ -360,9 +371,10 @@ struct PyHashInfo { algorithm: &'static str, hash_bits: usize, seed_bits: usize, + cutoff: usize, } impl PyHashInfo { - pub const INFO: Self = { + const INFO: Self = { use rustpython_common::hash::*; PyHashInfo { width: BITS, @@ -373,20 +385,73 @@ impl PyHashInfo { algorithm: ALGO, hash_bits: HASH_BITS, seed_bits: SEED_BITS, + cutoff: 0, // no small string optimizations } }; } +#[pystruct_sequence(module = "sys", name = "float_info")] +struct PyFloatInfo { + max: f64, + max_exp: i32, + max_10_exp: i32, + min: f64, + min_exp: i32, + min_10_exp: i32, + dig: u32, + mant_dig: u32, + epsilon: f64, + radix: u32, + rounds: i32, +} +impl PyFloatInfo { + const INFO: Self = PyFloatInfo { + max: f64::MAX, + max_exp: f64::MAX_EXP, + max_10_exp: f64::MAX_10_EXP, + min: f64::MIN, + min_exp: f64::MIN_EXP, + min_10_exp: f64::MIN_10_EXP, + dig: f64::DIGITS, + mant_dig: f64::MANTISSA_DIGITS, + epsilon: f64::EPSILON, + radix: f64::RADIX, + rounds: 1, // FE_TONEAREST + }; +} + +#[pystruct_sequence(module = "sys", name = "int_info")] +struct PyIntInfo { + bits_per_digit: usize, + sizeof_digit: usize, +} +impl PyIntInfo { + const INFO: Self = PyIntInfo { + bits_per_digit: 30, //? + sizeof_digit: std::mem::size_of::(), + }; +} + pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) { let ctx = &vm.ctx; let flags_type = SysFlags::make_class(ctx); + extend_class!(ctx, flags_type, { + (slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult { + Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned())) + }, + }); let flags = SysFlags::from_settings(&vm.state.settings) .into_struct_sequence(vm, flags_type) .unwrap(); let version_info_type = version::VersionInfo::make_class(ctx); - let version_info = version::get_version_info() + extend_class!(ctx, version_info_type, { + (slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult { + Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned())) + }, + }); + let version_info = version::VersionInfo::VERSION .into_struct_sequence(vm, version_info_type) .unwrap(); @@ -395,11 +460,23 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR .into_struct_sequence(vm, hash_info_type) .unwrap(); + let float_info_type = PyFloatInfo::make_class(ctx); + let float_info = PyFloatInfo::INFO + .into_struct_sequence(vm, float_info_type) + .unwrap(); + + let int_info_type = PyIntInfo::make_class(ctx); + let int_info = PyIntInfo::INFO + .into_struct_sequence(vm, int_info_type) + .unwrap(); + // TODO Add crate version to this namespace let implementation = py_namespace!(vm, { "name" => ctx.new_str("rustpython".to_owned()), "cache_tag" => ctx.new_str("rustpython-01".to_owned()), "_multiarch" => ctx.new_str(MULTIARCH.to_owned()), + "version" => version_info.clone(), + "hexversion" => ctx.new_int(version::VERSION_HEX), }); let path = ctx.new_list( @@ -532,7 +609,7 @@ settrace() -- set the global debug tracing function "gettrace" => ctx.new_function(sys_gettrace), "hash_info" => hash_info, "intern" => ctx.new_function(sys_intern), - "maxunicode" => ctx.new_int(0x0010_FFFF), + "maxunicode" => ctx.new_int(std::char::MAX as u32), "maxsize" => ctx.new_int(std::isize::MAX), "path" => path, "ps1" => ctx.new_str(">>>>> ".to_owned()), @@ -566,6 +643,11 @@ settrace() -- set the global debug tracing function "__displayhook__" => ctx.new_function(sys_displayhook), "excepthook" => ctx.new_function(sys_excepthook), "__excepthook__" => ctx.new_function(sys_excepthook), + "hexversion" => ctx.new_int(version::VERSION_HEX), + "api_version" => ctx.new_int(0x0), // what C api? + "float_info" => float_info, + "int_info" => int_info, + "float_repr_style" => ctx.new_str("short".to_owned()), }); #[cfg(windows)] diff --git a/vm/src/version.rs b/vm/src/version.rs index f9dd90207..66c2d5fa1 100644 --- a/vm/src/version.rs +++ b/vm/src/version.rs @@ -1,12 +1,20 @@ /* Several function to retrieve version information. */ +use chrono::prelude::DateTime; +use chrono::Local; +use std::time::{Duration, UNIX_EPOCH}; + const MAJOR: usize = 3; const MINOR: usize = 5; const MICRO: usize = 0; const RELEASELEVEL: &str = "alpha"; +const RELEASELEVEL_N: usize = 0xA; const SERIAL: usize = 0; +pub const VERSION_HEX: usize = + (MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL; + #[pystruct_sequence(module = "sys", name = "version_info")] #[derive(Default, Debug)] pub struct VersionInfo { @@ -16,10 +24,6 @@ pub struct VersionInfo { releaselevel: &'static str, serial: usize, } -extern crate chrono; -use chrono::prelude::DateTime; -use chrono::Local; -use std::time::{Duration, UNIX_EPOCH}; pub fn get_version() -> String { format!( @@ -30,14 +34,14 @@ pub fn get_version() -> String { ) } -pub fn get_version_info() -> VersionInfo { - VersionInfo { +impl VersionInfo { + pub const VERSION: VersionInfo = VersionInfo { major: MAJOR, minor: MINOR, micro: MICRO, releaselevel: RELEASELEVEL, serial: SERIAL, - } + }; } pub fn get_version_number() -> String {