Skip to content

Commit 4bd1153

Browse files
committed
Add/fix a bunch of sysmodule attributes
1 parent e165614 commit 4bd1153

5 files changed

Lines changed: 150 additions & 38 deletions

File tree

‎src/main.rs‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ fn main() {
6464
return;
6565
}
6666
if let Ok(s) = vm.to_str(&arg) {
67-
println!("{}", s);
67+
eprintln!("{}", s);
6868
}
6969
}
7070
}),
7171
_ => {
7272
if let Ok(r) = vm.to_repr(args.as_object()) {
73-
println!("{}", r);
73+
eprintln!("{}", r);
7474
}
7575
}
7676
}
@@ -158,6 +158,17 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
158158
Arg::with_name("ignore-environment")
159159
.short("E")
160160
.help("Ignore environment variables PYTHON* such as PYTHONPATH"),
161+
)
162+
.arg(
163+
Arg::with_name("isolate")
164+
.short("I")
165+
.help("isolate Python from the user's environment (implies -E and -s)"),
166+
)
167+
.arg(
168+
Arg::with_name("implementation-option")
169+
.short("X")
170+
.takes_value(true)
171+
.help("set implementation-specific option"),
161172
);
162173
#[cfg(feature = "flame-it")]
163174
let app = app
@@ -179,7 +190,8 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> {
179190
/// Create settings by examining command line arguments and environment
180191
/// variables.
181192
fn create_settings(matches: &ArgMatches) -> PySettings {
182-
let ignore_environment = matches.is_present("ignore-environment");
193+
let ignore_environment =
194+
matches.is_present("ignore-environment") || matches.is_present("isolate");
183195
let mut settings: PySettings = Default::default();
184196
settings.ignore_environment = ignore_environment;
185197

@@ -232,6 +244,7 @@ fn create_settings(matches: &ArgMatches) -> PySettings {
232244
settings.no_site = matches.is_present("no-site");
233245

234246
if matches.is_present("no-user-site")
247+
|| matches.is_present("isolate")
235248
|| (!ignore_environment && env::var_os("PYTHONNOUSERSITE").is_some())
236249
{
237250
settings.no_user_site = true;

‎vm/src/exceptions.rs‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,19 @@ fn key_error_str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStringRef {
661661
}
662662
}
663663

664+
fn system_exit_code(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyObjectRef {
665+
match exc.args.read().as_slice().first() {
666+
Some(code) => match_class!(match code {
667+
ref tup @ PyTuple => match tup.as_slice() {
668+
[x] => x.clone(),
669+
_ => code.clone(),
670+
},
671+
other => other.clone(),
672+
}),
673+
None => vm.get_none(),
674+
}
675+
}
676+
664677
pub fn init(ctx: &PyContext) {
665678
let excs = &ctx.exceptions;
666679

@@ -676,7 +689,7 @@ pub fn init(ctx: &PyContext) {
676689
});
677690

678691
extend_class!(ctx, &excs.system_exit, {
679-
"code" => ctx.new_readonly_getset("code", make_arg_getter(0)),
692+
"code" => ctx.new_readonly_getset("code", system_exit_code),
680693
});
681694

682695
extend_class!(ctx, &excs.import_error, {

‎vm/src/import.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn init_importlib(vm: &mut VirtualMachine, initialize_parameter: InitParamet
4545
Ok(())
4646
})();
4747
if zipimport_res.is_err() {
48-
eprintln!("couldn't init zipimport")
48+
warn!("couldn't init zipimport")
4949
}
5050
}
5151
InitParameter::NoInitialize => {

‎vm/src/sysmodule.rs‎

Lines changed: 108 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use num_traits::ToPrimitive;
12
use std::{env, mem, path};
23

34
use crate::frame::FrameRef;
45
use crate::function::{Args, OptionalArg, PyFuncArgs};
56
use crate::obj::objstr::PyStringRef;
7+
use crate::obj::objtype::PyClassRef;
68
use crate::pyobject::{IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult};
79
use crate::vm::{PySettings, VirtualMachine};
810
use crate::{builtins, exceptions, py_io, version};
@@ -26,7 +28,11 @@ fn argv(vm: &VirtualMachine) -> PyObjectRef {
2628

2729
fn executable(ctx: &PyContext) -> PyObjectRef {
2830
if let Some(exec_path) = env::args().next() {
29-
if path::Path::new(&exec_path).is_absolute() {
31+
let path = path::Path::new(&exec_path);
32+
if !path.exists() {
33+
return ctx.new_str("");
34+
}
35+
if path.is_absolute() {
3036
return ctx.new_str(exec_path);
3137
}
3238
if let Ok(dir) = env::current_dir() {
@@ -67,50 +73,50 @@ fn getframe(offset: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult<FrameRe
6773
#[derive(Default, Debug)]
6874
struct SysFlags {
6975
/// -d
70-
debug: bool,
76+
debug: u8,
7177
/// -i
72-
inspect: bool,
78+
inspect: u8,
7379
/// -i
74-
interactive: bool,
80+
interactive: u8,
7581
/// -O or -OO
7682
optimize: u8,
7783
/// -B
78-
dont_write_bytecode: bool,
84+
dont_write_bytecode: u8,
7985
/// -s
80-
no_user_site: bool,
86+
no_user_site: u8,
8187
/// -S
82-
no_site: bool,
88+
no_site: u8,
8389
/// -E
84-
ignore_environment: bool,
90+
ignore_environment: u8,
8591
/// -v
8692
verbose: u8,
8793
/// -b
88-
bytes_warning: bool,
94+
bytes_warning: u8,
8995
/// -q
90-
quiet: bool,
96+
quiet: u8,
9197
/// -R
92-
hash_randomization: bool,
98+
hash_randomization: u8,
9399
/// -I
94-
isolated: bool,
100+
isolated: u8,
95101
/// -X dev
96102
dev_mode: bool,
97103
/// -X utf8
98-
utf8_mode: bool,
104+
utf8_mode: u8,
99105
}
100106

101107
impl SysFlags {
102108
fn from_settings(settings: &PySettings) -> Self {
103109
// Start with sensible defaults:
104110
let mut flags: SysFlags = Default::default();
105-
flags.debug = settings.debug;
106-
flags.inspect = settings.inspect;
111+
flags.debug = settings.debug as u8;
112+
flags.inspect = settings.inspect as u8;
107113
flags.optimize = settings.optimize;
108-
flags.no_user_site = settings.no_user_site;
109-
flags.no_site = settings.no_site;
110-
flags.ignore_environment = settings.ignore_environment;
114+
flags.no_user_site = settings.no_user_site as u8;
115+
flags.no_site = settings.no_site as u8;
116+
flags.ignore_environment = settings.ignore_environment as u8;
111117
flags.verbose = settings.verbose;
112-
flags.quiet = settings.quiet;
113-
flags.dont_write_bytecode = settings.dont_write_bytecode;
118+
flags.quiet = settings.quiet as u8;
119+
flags.dont_write_bytecode = settings.dont_write_bytecode as u8;
114120
flags
115121
}
116122
}
@@ -173,7 +179,13 @@ fn sys_getrecursionlimit(vm: &VirtualMachine) -> usize {
173179
vm.recursion_limit.get()
174180
}
175181

176-
fn sys_setrecursionlimit(recursion_limit: usize, vm: &VirtualMachine) -> PyResult {
182+
fn sys_setrecursionlimit(recursion_limit: i32, vm: &VirtualMachine) -> PyResult {
183+
let recursion_limit = recursion_limit
184+
.to_usize()
185+
.filter(|&u| u >= 1)
186+
.ok_or_else(|| {
187+
vm.new_value_error("recursion limit must be greater than or equal to one".to_owned())
188+
})?;
177189
let recursion_depth = vm.frames.borrow().len();
178190

179191
if recursion_limit > recursion_depth + 1 {
@@ -209,7 +221,7 @@ fn sys_git_info(vm: &VirtualMachine) -> PyObjectRef {
209221
}
210222

211223
fn sys_exit(code: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
212-
let code = code.unwrap_or_else(|| vm.new_int(0));
224+
let code = code.unwrap_or_else(|| vm.get_none());
213225
Err(vm.new_exception(vm.ctx.exceptions.system_exit.clone(), vec![code]))
214226
}
215227

@@ -350,7 +362,6 @@ pub fn sysconfigdata_name() -> String {
350362
}
351363

352364
#[pystruct_sequence(module = "sys", name = "hash_info")]
353-
#[derive(Debug)]
354365
struct PyHashInfo {
355366
width: usize,
356367
modulus: PyUHash,
@@ -360,9 +371,10 @@ struct PyHashInfo {
360371
algorithm: &'static str,
361372
hash_bits: usize,
362373
seed_bits: usize,
374+
cutoff: usize,
363375
}
364376
impl PyHashInfo {
365-
pub const INFO: Self = {
377+
const INFO: Self = {
366378
use rustpython_common::hash::*;
367379
PyHashInfo {
368380
width: BITS,
@@ -373,20 +385,73 @@ impl PyHashInfo {
373385
algorithm: ALGO,
374386
hash_bits: HASH_BITS,
375387
seed_bits: SEED_BITS,
388+
cutoff: 0, // no small string optimizations
376389
}
377390
};
378391
}
379392

393+
#[pystruct_sequence(module = "sys", name = "float_info")]
394+
struct PyFloatInfo {
395+
max: f64,
396+
max_exp: i32,
397+
max_10_exp: i32,
398+
min: f64,
399+
min_exp: i32,
400+
min_10_exp: i32,
401+
dig: u32,
402+
mant_dig: u32,
403+
epsilon: f64,
404+
radix: u32,
405+
rounds: i32,
406+
}
407+
impl PyFloatInfo {
408+
const INFO: Self = PyFloatInfo {
409+
max: f64::MAX,
410+
max_exp: f64::MAX_EXP,
411+
max_10_exp: f64::MAX_10_EXP,
412+
min: f64::MIN,
413+
min_exp: f64::MIN_EXP,
414+
min_10_exp: f64::MIN_10_EXP,
415+
dig: f64::DIGITS,
416+
mant_dig: f64::MANTISSA_DIGITS,
417+
epsilon: f64::EPSILON,
418+
radix: f64::RADIX,
419+
rounds: 1, // FE_TONEAREST
420+
};
421+
}
422+
423+
#[pystruct_sequence(module = "sys", name = "int_info")]
424+
struct PyIntInfo {
425+
bits_per_digit: usize,
426+
sizeof_digit: usize,
427+
}
428+
impl PyIntInfo {
429+
const INFO: Self = PyIntInfo {
430+
bits_per_digit: 30, //?
431+
sizeof_digit: std::mem::size_of::<u32>(),
432+
};
433+
}
434+
380435
pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) {
381436
let ctx = &vm.ctx;
382437

383438
let flags_type = SysFlags::make_class(ctx);
439+
extend_class!(ctx, flags_type, {
440+
(slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult {
441+
Err(vm.new_type_error("cannot create 'sys.flags' instances".to_owned()))
442+
},
443+
});
384444
let flags = SysFlags::from_settings(&vm.state.settings)
385445
.into_struct_sequence(vm, flags_type)
386446
.unwrap();
387447

388448
let version_info_type = version::VersionInfo::make_class(ctx);
389-
let version_info = version::get_version_info()
449+
extend_class!(ctx, version_info_type, {
450+
(slot new) => |_cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine| -> PyResult {
451+
Err(vm.new_type_error("cannot create 'sys.version_info' instances".to_owned()))
452+
},
453+
});
454+
let version_info = version::VersionInfo::VERSION
390455
.into_struct_sequence(vm, version_info_type)
391456
.unwrap();
392457

@@ -395,11 +460,23 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR
395460
.into_struct_sequence(vm, hash_info_type)
396461
.unwrap();
397462

463+
let float_info_type = PyFloatInfo::make_class(ctx);
464+
let float_info = PyFloatInfo::INFO
465+
.into_struct_sequence(vm, float_info_type)
466+
.unwrap();
467+
468+
let int_info_type = PyIntInfo::make_class(ctx);
469+
let int_info = PyIntInfo::INFO
470+
.into_struct_sequence(vm, int_info_type)
471+
.unwrap();
472+
398473
// TODO Add crate version to this namespace
399474
let implementation = py_namespace!(vm, {
400475
"name" => ctx.new_str("rustpython".to_owned()),
401476
"cache_tag" => ctx.new_str("rustpython-01".to_owned()),
402477
"_multiarch" => ctx.new_str(MULTIARCH.to_owned()),
478+
"version" => version_info.clone(),
479+
"hexversion" => ctx.new_int(version::VERSION_HEX),
403480
});
404481

405482
let path = ctx.new_list(
@@ -532,7 +609,7 @@ settrace() -- set the global debug tracing function
532609
"gettrace" => ctx.new_function(sys_gettrace),
533610
"hash_info" => hash_info,
534611
"intern" => ctx.new_function(sys_intern),
535-
"maxunicode" => ctx.new_int(0x0010_FFFF),
612+
"maxunicode" => ctx.new_int(std::char::MAX as u32),
536613
"maxsize" => ctx.new_int(std::isize::MAX),
537614
"path" => path,
538615
"ps1" => ctx.new_str(">>>>> ".to_owned()),
@@ -566,6 +643,11 @@ settrace() -- set the global debug tracing function
566643
"__displayhook__" => ctx.new_function(sys_displayhook),
567644
"excepthook" => ctx.new_function(sys_excepthook),
568645
"__excepthook__" => ctx.new_function(sys_excepthook),
646+
"hexversion" => ctx.new_int(version::VERSION_HEX),
647+
"api_version" => ctx.new_int(0x0), // what C api?
648+
"float_info" => float_info,
649+
"int_info" => int_info,
650+
"float_repr_style" => ctx.new_str("short".to_owned()),
569651
});
570652

571653
#[cfg(windows)]

‎vm/src/version.rs‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
/* Several function to retrieve version information.
22
*/
33

4+
use chrono::prelude::DateTime;
5+
use chrono::Local;
6+
use std::time::{Duration, UNIX_EPOCH};
7+
48
const MAJOR: usize = 3;
59
const MINOR: usize = 5;
610
const MICRO: usize = 0;
711
const RELEASELEVEL: &str = "alpha";
12+
const RELEASELEVEL_N: usize = 0xA;
813
const SERIAL: usize = 0;
914

15+
pub const VERSION_HEX: usize =
16+
(MAJOR << 24) | (MINOR << 16) | (MICRO << 8) | (RELEASELEVEL_N << 4) | SERIAL;
17+
1018
#[pystruct_sequence(module = "sys", name = "version_info")]
1119
#[derive(Default, Debug)]
1220
pub struct VersionInfo {
@@ -16,10 +24,6 @@ pub struct VersionInfo {
1624
releaselevel: &'static str,
1725
serial: usize,
1826
}
19-
extern crate chrono;
20-
use chrono::prelude::DateTime;
21-
use chrono::Local;
22-
use std::time::{Duration, UNIX_EPOCH};
2327

2428
pub fn get_version() -> String {
2529
format!(
@@ -30,14 +34,14 @@ pub fn get_version() -> String {
3034
)
3135
}
3236

33-
pub fn get_version_info() -> VersionInfo {
34-
VersionInfo {
37+
impl VersionInfo {
38+
pub const VERSION: VersionInfo = VersionInfo {
3539
major: MAJOR,
3640
minor: MINOR,
3741
micro: MICRO,
3842
releaselevel: RELEASELEVEL,
3943
serial: SERIAL,
40-
}
44+
};
4145
}
4246

4347
pub fn get_version_number() -> String {

0 commit comments

Comments
 (0)