1pub(crate) mod monitoring;
2
3use crate::{Py, PyPayload, PyResult, VirtualMachine, builtins::PyModule, convert::ToPyObject};
4
5#[cfg(all(not(feature = "host_env"), feature = "stdio"))]
6pub(crate) use sys::SandboxStdio;
7pub(crate) use sys::{DOC, MAXSIZE, RUST_MULTIARCH, UnraisableHookArgsData, module_def, multiarch};
8
9#[pymodule(name = "_jit")]
10mod sys_jit {
11 #[pyfunction]
14 const fn is_available() -> bool {
15 false }
17
18 #[pyfunction]
21 const fn is_enabled() -> bool {
22 false }
24
25 #[pyfunction]
28 const fn is_active() -> bool {
29 false }
31}
32
33#[pymodule]
34mod sys {
35 use crate::{
36 AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyRefExact, PyResult,
37 builtins::{
38 PyBaseExceptionRef, PyDictRef, PyFrozenSet, PyNamespace, PyStr, PyStrRef, PyTuple,
39 PyTupleRef, PyTypeRef, PyUtf8StrRef,
40 },
41 common::{
42 ascii,
43 hash::{PyHash, PyUHash},
44 },
45 convert::ToPyObject,
46 frame::{Frame, FrameRef},
47 function::{FuncArgs, KwArgs, OptionalArg, PosArgs},
48 stdlib::{_warnings::warn, builtins},
49 types::PyStructSequence,
50 version,
51 vm::{Settings, VirtualMachine},
52 };
53 use core::sync::atomic::Ordering;
54 use num_traits::ToPrimitive;
55 use std::{
56 env::{self, VarError},
57 io::{IsTerminal, Read, Write},
58 };
59
60 #[cfg(windows)]
61 use windows_sys::Win32::{
62 Foundation::MAX_PATH,
63 Storage::FileSystem::{
64 GetFileVersionInfoSizeW, GetFileVersionInfoW, VS_FIXEDFILEINFO, VerQueryValueW,
65 },
66 System::LibraryLoader::{GetModuleFileNameW, GetModuleHandleW},
67 };
68
69 pub(crate) const RUST_MULTIARCH: &str = env!("RUSTPYTHON_TARGET_TRIPLE");
71
72 pub(crate) fn multiarch() -> String {
75 RUST_MULTIARCH.replace("-unknown", "")
76 }
77
78 #[pymodule(name = "monitoring", with(super::monitoring::sys_monitoring))]
79 pub(super) mod monitoring {}
80
81 #[pyclass(no_attr, name = "_BootstrapStderr")]
82 #[derive(Debug, PyPayload)]
83 pub(super) struct BootstrapStderr;
84
85 #[pyclass]
86 impl BootstrapStderr {
87 #[pymethod]
88 fn write(&self, s: PyStrRef) -> PyResult<usize> {
89 let bytes = s.as_bytes();
90 let _ = std::io::stderr().write_all(bytes);
91 Ok(bytes.len())
92 }
93
94 #[pymethod]
95 fn flush(&self) -> PyResult<()> {
96 let _ = std::io::stderr().flush();
97 Ok(())
98 }
99 }
100
101 #[pyclass(no_attr, name = "_SandboxStdio")]
104 #[derive(Debug, PyPayload)]
105 pub struct SandboxStdio {
106 pub fd: i32,
107 pub name: String,
108 pub mode: String,
109 }
110
111 #[pyclass]
112 impl SandboxStdio {
113 #[pymethod]
114 fn write(&self, s: PyStrRef, vm: &VirtualMachine) -> PyResult<usize> {
115 if self.fd == 0 {
116 return Err(vm.new_os_error("not writable".to_owned()));
117 }
118 let bytes = s.as_bytes();
119 if self.fd == 2 {
120 std::io::stderr()
121 .write_all(bytes)
122 .map_err(|e| vm.new_os_error(e.to_string()))?;
123 } else {
124 std::io::stdout()
125 .write_all(bytes)
126 .map_err(|e| vm.new_os_error(e.to_string()))?;
127 }
128 Ok(bytes.len())
129 }
130
131 #[pymethod]
132 fn readline(&self, size: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult<String> {
133 if self.fd != 0 {
134 return Err(vm.new_os_error("not readable".to_owned()));
135 }
136 let size = size.unwrap_or(-1);
137 if size == 0 {
138 return Ok(String::new());
139 }
140 let mut line = String::new();
141 std::io::stdin()
142 .read_line(&mut line)
143 .map_err(|e| vm.new_os_error(e.to_string()))?;
144 if size > 0 {
145 line.truncate(size as usize);
146 }
147 Ok(line)
148 }
149
150 #[pymethod]
151 fn flush(&self, vm: &VirtualMachine) -> PyResult<()> {
152 match self.fd {
153 1 => {
154 std::io::stdout()
155 .flush()
156 .map_err(|e| vm.new_os_error(e.to_string()))?;
157 }
158 2 => {
159 std::io::stderr()
160 .flush()
161 .map_err(|e| vm.new_os_error(e.to_string()))?;
162 }
163 _ => {}
164 }
165 Ok(())
166 }
167
168 #[pymethod]
169 fn fileno(&self) -> i32 {
170 self.fd
171 }
172
173 #[pymethod]
174 fn isatty(&self) -> bool {
175 match self.fd {
176 0 => std::io::stdin().is_terminal(),
177 1 => std::io::stdout().is_terminal(),
178 2 => std::io::stderr().is_terminal(),
179 _ => false,
180 }
181 }
182
183 #[pymethod]
184 fn readable(&self) -> bool {
185 self.fd == 0
186 }
187
188 #[pymethod]
189 fn writable(&self) -> bool {
190 self.fd == 1 || self.fd == 2
191 }
192
193 #[pygetset]
194 fn closed(&self) -> bool {
195 false
196 }
197
198 #[pygetset]
199 fn encoding(&self) -> String {
200 "utf-8".to_owned()
201 }
202
203 #[pygetset]
204 fn errors(&self) -> String {
205 if self.fd == 2 {
206 "backslashreplace"
207 } else {
208 "strict"
209 }
210 .to_owned()
211 }
212
213 #[pygetset(name = "name")]
214 fn name_prop(&self) -> String {
215 self.name.clone()
216 }
217
218 #[pygetset(name = "mode")]
219 fn mode_prop(&self) -> String {
220 self.mode.clone()
221 }
222 }
223
224 #[pyattr(name = "_rustpython_debugbuild")]
225 const RUSTPYTHON_DEBUGBUILD: bool = cfg!(debug_assertions);
226
227 #[cfg(not(windows))]
228 #[pyattr(name = "abiflags")]
229 const ABIFLAGS_ATTR: &str = "t"; pub const ABIFLAGS: &str = "t";
232 #[pyattr(name = "api_version")]
233 const API_VERSION: u32 = 0x0; #[pyattr(name = "copyright")]
235 const COPYRIGHT: &str = "Copyright (c) 2019 RustPython Team";
236 #[pyattr(name = "float_repr_style")]
237 const FLOAT_REPR_STYLE: &str = "short";
238 #[pyattr(name = "_framework")]
239 const FRAMEWORK: &str = "";
240 #[pyattr(name = "hexversion")]
241 const HEXVERSION: usize = version::VERSION_HEX;
242 #[pyattr(name = "maxsize")]
243 pub(crate) const MAXSIZE: isize = isize::MAX;
244 #[pyattr(name = "maxunicode")]
245 const MAXUNICODE: u32 = core::char::MAX as u32;
246 #[pyattr(name = "platform")]
247 pub const PLATFORM: &str = {
248 cfg_if::cfg_if! {
249 if #[cfg(target_os = "linux")] {
250 "linux"
251 } else if #[cfg(target_os = "android")] {
252 "android"
253 } else if #[cfg(target_os = "macos")] {
254 "darwin"
255 } else if #[cfg(target_os = "ios")] {
256 "ios"
257 } else if #[cfg(windows)] {
258 "win32"
259 } else if #[cfg(target_os = "wasi")] {
260 "wasi"
261 } else {
262 "unknown"
263 }
264 }
265 };
266 #[pyattr(name = "ps1")]
267 const PS1: &str = ">>>>> ";
268 #[pyattr(name = "ps2")]
269 const PS2: &str = "..... ";
270
271 #[cfg(windows)]
272 #[pyattr(name = "_vpath")]
273 const VPATH: Option<&'static str> = None; #[cfg(windows)]
276 #[pyattr(name = "dllhandle")]
277 const DLLHANDLE: usize = 0;
278
279 #[pyattr]
280 fn prefix(vm: &VirtualMachine) -> String {
281 vm.state.config.paths.prefix.clone()
282 }
283 #[pyattr]
284 fn base_prefix(vm: &VirtualMachine) -> String {
285 vm.state.config.paths.base_prefix.clone()
286 }
287 #[pyattr]
288 fn exec_prefix(vm: &VirtualMachine) -> String {
289 vm.state.config.paths.exec_prefix.clone()
290 }
291 #[pyattr]
292 fn base_exec_prefix(vm: &VirtualMachine) -> String {
293 vm.state.config.paths.base_exec_prefix.clone()
294 }
295 #[pyattr]
296 fn platlibdir(_vm: &VirtualMachine) -> &'static str {
297 option_env!("RUSTPYTHON_PLATLIBDIR").unwrap_or("lib")
298 }
299 #[pyattr]
300 fn _stdlib_dir(vm: &VirtualMachine) -> PyObjectRef {
301 vm.state.config.paths.stdlib_dir.clone().to_pyobject(vm)
302 }
303
304 #[pyattr]
307 fn argv(vm: &VirtualMachine) -> Vec<PyObjectRef> {
308 vm.state
309 .config
310 .settings
311 .argv
312 .iter()
313 .map(|arg| vm.ctx.new_str(arg.clone()).into())
314 .collect()
315 }
316
317 #[pyattr]
318 fn builtin_module_names(vm: &VirtualMachine) -> PyTupleRef {
319 let mut module_names: Vec<String> =
320 vm.state.module_defs.keys().map(|&s| s.to_owned()).collect();
321 module_names.push("sys".to_owned());
322 module_names.push("builtins".to_owned());
323
324 module_names.sort();
325 vm.ctx.new_tuple(
326 module_names
327 .into_iter()
328 .map(|n| vm.ctx.new_str(n).into())
329 .collect(),
330 )
331 }
332
333 const STDLIB_MODULE_NAMES: &[&str] = &[
335 "__future__",
336 "_abc",
337 "_aix_support",
338 "_android_support",
339 "_apple_support",
340 "_ast",
341 "_asyncio",
342 "_bisect",
343 "_blake2",
344 "_bz2",
345 "_codecs",
346 "_codecs_cn",
347 "_codecs_hk",
348 "_codecs_iso2022",
349 "_codecs_jp",
350 "_codecs_kr",
351 "_codecs_tw",
352 "_collections",
353 "_collections_abc",
354 "_colorize",
355 "_compat_pickle",
356 "_compression",
357 "_contextvars",
358 "_csv",
359 "_ctypes",
360 "_curses",
361 "_curses_panel",
362 "_datetime",
363 "_dbm",
364 "_decimal",
365 "_elementtree",
366 "_frozen_importlib",
367 "_frozen_importlib_external",
368 "_functools",
369 "_gdbm",
370 "_hashlib",
371 "_heapq",
372 "_imp",
373 "_interpchannels",
374 "_interpqueues",
375 "_interpreters",
376 "_io",
377 "_ios_support",
378 "_json",
379 "_locale",
380 "_lsprof",
381 "_lzma",
382 "_markupbase",
383 "_md5",
384 "_multibytecodec",
385 "_multiprocessing",
386 "_opcode",
387 "_opcode_metadata",
388 "_operator",
389 "_osx_support",
390 "_overlapped",
391 "_pickle",
392 "_posixshmem",
393 "_posixsubprocess",
394 "_py_abc",
395 "_pydatetime",
396 "_pydecimal",
397 "_pyio",
398 "_pylong",
399 "_pyrepl",
400 "_queue",
401 "_random",
402 "_scproxy",
403 "_sha1",
404 "_sha2",
405 "_sha3",
406 "_signal",
407 "_sitebuiltins",
408 "_socket",
409 "_sqlite3",
410 "_sre",
411 "_ssl",
412 "_stat",
413 "_statistics",
414 "_string",
415 "_strptime",
416 "_struct",
417 "_suggestions",
418 "_symtable",
419 "_sysconfig",
420 "_thread",
421 "_threading_local",
422 "_tkinter",
423 "_tokenize",
424 "_tracemalloc",
425 "_typing",
426 "_uuid",
427 "_warnings",
428 "_weakref",
429 "_weakrefset",
430 "_winapi",
431 "_wmi",
432 "_zoneinfo",
433 "abc",
434 "antigravity",
435 "argparse",
436 "array",
437 "ast",
438 "asyncio",
439 "atexit",
440 "base64",
441 "bdb",
442 "binascii",
443 "bisect",
444 "builtins",
445 "bz2",
446 "cProfile",
447 "calendar",
448 "cmath",
449 "cmd",
450 "code",
451 "codecs",
452 "codeop",
453 "collections",
454 "colorsys",
455 "compileall",
456 "concurrent",
457 "configparser",
458 "contextlib",
459 "contextvars",
460 "copy",
461 "copyreg",
462 "csv",
463 "ctypes",
464 "curses",
465 "dataclasses",
466 "datetime",
467 "dbm",
468 "decimal",
469 "difflib",
470 "dis",
471 "doctest",
472 "email",
473 "encodings",
474 "ensurepip",
475 "enum",
476 "errno",
477 "faulthandler",
478 "fcntl",
479 "filecmp",
480 "fileinput",
481 "fnmatch",
482 "fractions",
483 "ftplib",
484 "functools",
485 "gc",
486 "genericpath",
487 "getopt",
488 "getpass",
489 "gettext",
490 "glob",
491 "graphlib",
492 "grp",
493 "gzip",
494 "hashlib",
495 "heapq",
496 "hmac",
497 "html",
498 "http",
499 "idlelib",
500 "imaplib",
501 "importlib",
502 "inspect",
503 "io",
504 "ipaddress",
505 "itertools",
506 "json",
507 "keyword",
508 "linecache",
509 "locale",
510 "logging",
511 "lzma",
512 "mailbox",
513 "marshal",
514 "math",
515 "mimetypes",
516 "mmap",
517 "modulefinder",
518 "msvcrt",
519 "multiprocessing",
520 "netrc",
521 "nt",
522 "ntpath",
523 "nturl2path",
524 "numbers",
525 "opcode",
526 "operator",
527 "optparse",
528 "os",
529 "pathlib",
530 "pdb",
531 "pickle",
532 "pickletools",
533 "pkgutil",
534 "platform",
535 "plistlib",
536 "poplib",
537 "posix",
538 "posixpath",
539 "pprint",
540 "profile",
541 "pstats",
542 "pty",
543 "pwd",
544 "py_compile",
545 "pyclbr",
546 "pydoc",
547 "pydoc_data",
548 "pyexpat",
549 "queue",
550 "quopri",
551 "random",
552 "re",
553 "readline",
554 "reprlib",
555 "resource",
556 "rlcompleter",
557 "runpy",
558 "sched",
559 "secrets",
560 "select",
561 "selectors",
562 "shelve",
563 "shlex",
564 "shutil",
565 "signal",
566 "site",
567 "smtplib",
568 "socket",
569 "socketserver",
570 "sqlite3",
571 "sre_compile",
572 "sre_constants",
573 "sre_parse",
574 "ssl",
575 "stat",
576 "statistics",
577 "string",
578 "stringprep",
579 "struct",
580 "subprocess",
581 "symtable",
582 "sys",
583 "sysconfig",
584 "syslog",
585 "tabnanny",
586 "tarfile",
587 "tempfile",
588 "termios",
589 "textwrap",
590 "this",
591 "threading",
592 "time",
593 "timeit",
594 "tkinter",
595 "token",
596 "tokenize",
597 "tomllib",
598 "trace",
599 "traceback",
600 "tracemalloc",
601 "tty",
602 "turtle",
603 "turtledemo",
604 "types",
605 "typing",
606 "unicodedata",
607 "unittest",
608 "urllib",
609 "uuid",
610 "venv",
611 "warnings",
612 "wave",
613 "weakref",
614 "webbrowser",
615 "winreg",
616 "winsound",
617 "wsgiref",
618 "xml",
619 "xmlrpc",
620 "zipapp",
621 "zipfile",
622 "zipimport",
623 "zlib",
624 "zoneinfo",
625 ];
626
627 #[pyattr(once)]
628 fn stdlib_module_names(vm: &VirtualMachine) -> PyObjectRef {
629 let names = STDLIB_MODULE_NAMES
630 .iter()
631 .map(|&n| vm.ctx.new_str(n).into());
632 PyFrozenSet::from_iter(vm, names)
633 .expect("Creating stdlib_module_names frozen set must succeed")
634 .to_pyobject(vm)
635 }
636
637 #[pyattr]
638 fn byteorder(vm: &VirtualMachine) -> PyStrRef {
639 vm.ctx
641 .intern_str(if cfg!(target_endian = "little") {
642 "little"
643 } else if cfg!(target_endian = "big") {
644 "big"
645 } else {
646 "unknown"
647 })
648 .to_owned()
649 }
650
651 #[pyattr]
652 fn _base_executable(vm: &VirtualMachine) -> String {
653 vm.state.config.paths.base_executable.clone()
654 }
655
656 #[pyattr]
657 fn dont_write_bytecode(vm: &VirtualMachine) -> bool {
658 !vm.state.config.settings.write_bytecode
659 }
660
661 #[pyattr]
662 fn executable(vm: &VirtualMachine) -> String {
663 vm.state.config.paths.executable.clone()
664 }
665
666 #[pyattr]
667 fn _git(vm: &VirtualMachine) -> PyTupleRef {
668 vm.new_tuple((
669 ascii!("RustPython"),
670 version::get_git_identifier(),
671 version::get_git_revision(),
672 ))
673 }
674
675 #[pyattr]
676 fn implementation(vm: &VirtualMachine) -> PyRef<PyNamespace> {
677 const NAME: &str = "rustpython";
678
679 let cache_tag = format!("{NAME}-{}{}", version::MAJOR, version::MINOR);
680 let ctx = &vm.ctx;
681 py_namespace!(vm, {
682 "name" => ctx.new_str(NAME),
683 "cache_tag" => ctx.new_str(cache_tag),
684 "_multiarch" => ctx.new_str(multiarch()),
685 "version" => version_info(vm),
686 "hexversion" => ctx.new_int(version::VERSION_HEX),
687 "supports_isolated_interpreters" => ctx.new_bool(false),
688 })
689 }
690
691 #[pyattr]
692 const fn meta_path(_vm: &VirtualMachine) -> Vec<PyObjectRef> {
693 Vec::new()
694 }
695
696 #[pyattr]
697 fn orig_argv(vm: &VirtualMachine) -> Vec<PyObjectRef> {
698 env::args().map(|arg| vm.ctx.new_str(arg).into()).collect()
699 }
700
701 #[pyattr]
702 fn path(vm: &VirtualMachine) -> Vec<PyObjectRef> {
703 vm.state
704 .config
705 .paths
706 .module_search_paths
707 .iter()
708 .map(|path| vm.ctx.new_str(path.clone()).into())
709 .collect()
710 }
711
712 #[pyattr]
713 const fn path_hooks(_vm: &VirtualMachine) -> Vec<PyObjectRef> {
714 Vec::new()
715 }
716
717 #[pyattr]
718 fn path_importer_cache(vm: &VirtualMachine) -> PyDictRef {
719 vm.ctx.new_dict()
720 }
721
722 #[pyattr]
723 fn pycache_prefix(vm: &VirtualMachine) -> PyObjectRef {
724 vm.ctx.none()
725 }
726
727 #[pyattr]
728 fn version(_vm: &VirtualMachine) -> String {
729 version::get_version()
730 }
731
732 #[cfg(windows)]
733 #[pyattr]
734 fn winver(_vm: &VirtualMachine) -> String {
735 version::get_winver_number()
737 }
738
739 #[pyattr]
740 fn _xoptions(vm: &VirtualMachine) -> PyDictRef {
741 let ctx = &vm.ctx;
742 let xopts = ctx.new_dict();
743 for (key, value) in &vm.state.config.settings.xoptions {
744 let value = value.as_ref().map_or_else(
745 || ctx.new_bool(true).into(),
746 |s| ctx.new_str(s.clone()).into(),
747 );
748 xopts.set_item(&**key, value, vm).unwrap();
749 }
750 xopts
751 }
752
753 #[pyattr]
754 fn warnoptions(vm: &VirtualMachine) -> Vec<PyObjectRef> {
755 vm.state
756 .config
757 .settings
758 .warnoptions
759 .iter()
760 .map(|s| vm.ctx.new_str(s.clone()).into())
761 .collect()
762 }
763
764 #[cfg(feature = "rustpython-compiler")]
765 #[pyfunction]
766 fn _baserepl(vm: &VirtualMachine) -> PyResult<()> {
767 let stdin = std::io::stdin();
769 let mut handle = stdin.lock();
770 let mut source = String::new();
771 handle
772 .read_to_string(&mut source)
773 .map_err(|e| vm.new_os_error(format!("Error reading from stdin: {e}")))?;
774 vm.compile(&source, crate::compiler::Mode::Single, "<stdin>".to_owned())
775 .map_err(|e| vm.new_os_error(format!("Error running stdin: {e}")))?;
776 Ok(())
777 }
778
779 #[pyfunction]
780 fn audit(_args: FuncArgs) {
781 }
783
784 #[pyfunction]
785 const fn _is_gil_enabled() -> bool {
786 false }
788
789 #[pyfunction]
791 const fn is_remote_debug_enabled() -> bool {
792 false }
794
795 #[pyfunction]
796 fn exit(code: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
797 let status = code.unwrap_or_none(vm);
798 let args = if let Some(status_tuple) = status.downcast_ref::<PyTuple>() {
799 status_tuple.as_slice().to_vec()
800 } else {
801 vec![status]
802 };
803 let exc = vm.invoke_exception(vm.ctx.exceptions.system_exit.to_owned(), args)?;
804 Err(exc)
805 }
806
807 #[pyfunction]
808 fn call_tracing(func: PyObjectRef, args: PyTupleRef, vm: &VirtualMachine) -> PyResult {
809 func.call(PosArgs::new(args.as_slice().to_vec()), vm)
813 }
814
815 #[pyfunction]
816 fn exception(vm: &VirtualMachine) -> Option<PyBaseExceptionRef> {
817 vm.topmost_exception()
818 }
819
820 #[pyfunction(name = "__displayhook__")]
821 #[pyfunction]
822 fn displayhook(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
823 if vm.is_none(&obj) {
825 return Ok(());
826 }
827 vm.builtins.set_attr("_", vm.ctx.none(), vm)?;
829 let repr = obj.repr(vm)?.into();
831 builtins::print(PosArgs::new(vec![repr]), Default::default(), vm)?;
832 vm.builtins.set_attr("_", obj, vm)?;
833 Ok(())
834 }
835
836 #[pyfunction(name = "__excepthook__")]
837 #[pyfunction]
838 fn excepthook(
839 exc_type: PyObjectRef,
840 exc_val: PyObjectRef,
841 exc_tb: PyObjectRef,
842 vm: &VirtualMachine,
843 ) -> PyResult<()> {
844 let stderr = super::get_stderr(vm)?;
845 match vm.normalize_exception(exc_type.clone(), exc_val.clone(), exc_tb) {
846 Ok(exc) => {
847 if let Ok(tb_mod) = vm.import("traceback", 0)
849 && let Ok(print_exc_builtin) = tb_mod.get_attr("_print_exception_bltin", vm)
850 && print_exc_builtin
851 .call((exc.as_object().to_owned(),), vm)
852 .is_ok()
853 {
854 return Ok(());
855 }
856 vm.write_exception(&mut crate::py_io::PyWriter(stderr, vm), &exc)
858 }
859 Err(_) => {
860 let type_name = exc_val.class().name();
861 let msg = format!(
862 "TypeError: print_exception(): Exception expected for value, {type_name} found\n"
863 );
864 use crate::py_io::Write;
865 write!(&mut crate::py_io::PyWriter(stderr, vm), "{msg}")?;
866 Ok(())
867 }
868 }
869 }
870
871 #[pyfunction(name = "__breakpointhook__")]
872 #[pyfunction]
873 pub fn breakpointhook(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
874 let env_var = std::env::var("PYTHONBREAKPOINT")
875 .and_then(|env_var| {
876 if env_var.is_empty() {
877 Err(VarError::NotPresent)
878 } else {
879 Ok(env_var)
880 }
881 })
882 .unwrap_or_else(|_| "pdb.set_trace".to_owned());
883
884 if env_var.eq("0") {
885 return Ok(vm.ctx.none());
886 };
887
888 let print_unimportable_module_warn = || {
889 warn(
890 vm.ctx.exceptions.runtime_warning,
891 format!("Ignoring unimportable $PYTHONBREAKPOINT: \"{env_var}\"",),
892 0,
893 vm,
894 )
895 .unwrap();
896 Ok(vm.ctx.none())
897 };
898
899 let last = match env_var.rsplit_once('.') {
900 Some((_, last)) => last,
901 None if !env_var.is_empty() => env_var.as_str(),
902 _ => return print_unimportable_module_warn(),
903 };
904
905 let (module_path, attr_name) = if last == env_var {
906 ("builtins", env_var.as_str())
907 } else {
908 (&env_var[..(env_var.len() - last.len() - 1)], last)
909 };
910
911 let module = match vm.import(&vm.ctx.new_str(module_path), 0) {
912 Ok(module) => module,
913 Err(_) => {
914 return print_unimportable_module_warn();
915 }
916 };
917
918 match vm.get_attribute_opt(module, &vm.ctx.new_str(attr_name)) {
919 Ok(Some(hook)) => hook.as_ref().call(args, vm),
920 _ => print_unimportable_module_warn(),
921 }
922 }
923
924 #[pyfunction]
925 fn exc_info(vm: &VirtualMachine) -> (PyObjectRef, PyObjectRef, PyObjectRef) {
926 match vm.topmost_exception() {
927 Some(exception) => vm.split_exception(exception),
928 None => (vm.ctx.none(), vm.ctx.none(), vm.ctx.none()),
929 }
930 }
931
932 #[pyattr]
933 fn flags(vm: &VirtualMachine) -> PyTupleRef {
934 PyFlags::from_data(FlagsData::from_settings(&vm.state.config.settings), vm)
935 }
936
937 #[pyattr]
938 fn float_info(vm: &VirtualMachine) -> PyTupleRef {
939 PyFloatInfo::from_data(FloatInfoData::INFO, vm)
940 }
941
942 #[pyfunction]
943 const fn getdefaultencoding() -> &'static str {
944 crate::codecs::DEFAULT_ENCODING
945 }
946
947 #[pyfunction]
948 fn getrefcount(obj: PyObjectRef) -> usize {
949 obj.strong_count()
950 }
951
952 #[pyfunction]
953 fn getrecursionlimit(vm: &VirtualMachine) -> usize {
954 vm.recursion_limit.get()
955 }
956
957 #[derive(FromArgs)]
958 struct GetsizeofArgs {
959 obj: PyObjectRef,
960 #[pyarg(any, optional)]
961 default: Option<PyObjectRef>,
962 }
963
964 #[pyfunction]
965 fn getsizeof(args: GetsizeofArgs, vm: &VirtualMachine) -> PyResult {
966 let sizeof = || -> PyResult<usize> {
967 let res = vm.call_special_method(&args.obj, identifier!(vm, __sizeof__), ())?;
968 let res = res.try_index(vm)?.try_to_primitive::<usize>(vm)?;
969 Ok(res + core::mem::size_of::<PyObject>())
970 };
971 sizeof()
972 .map(|x| vm.ctx.new_int(x).into())
973 .or_else(|err| args.default.ok_or(err))
974 }
975
976 #[pyfunction]
977 fn getfilesystemencoding(vm: &VirtualMachine) -> PyStrRef {
978 vm.fs_encoding().to_owned()
979 }
980
981 #[pyfunction]
982 fn getfilesystemencodeerrors(vm: &VirtualMachine) -> PyUtf8StrRef {
983 vm.fs_encode_errors().to_owned()
984 }
985
986 #[pyfunction]
987 fn getprofile(vm: &VirtualMachine) -> PyObjectRef {
988 vm.profile_func.borrow().clone()
989 }
990
991 #[pyfunction]
992 fn _getframe(offset: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult<FrameRef> {
993 let offset = offset.into_option().unwrap_or(0);
994 let frames = vm.frames.borrow();
995 if offset >= frames.len() {
996 return Err(vm.new_value_error("call stack is not deep enough"));
997 }
998 let idx = frames.len() - offset - 1;
999 let py: &crate::Py<Frame> = unsafe { frames[idx].as_ref() };
1001 Ok(py.to_owned())
1002 }
1003
1004 #[pyfunction]
1005 fn _getframemodulename(depth: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult {
1006 let depth = depth.into_option().unwrap_or(0);
1007
1008 let func_obj = {
1010 let frames = vm.frames.borrow();
1011 if depth >= frames.len() {
1012 return Ok(vm.ctx.none());
1013 }
1014 let idx = frames.len() - depth - 1;
1015 let frame: &crate::Py<Frame> = unsafe { frames[idx].as_ref() };
1017 frame.func_obj.clone()
1018 };
1019
1020 if let Some(func_obj) = func_obj {
1022 match func_obj.get_attr(identifier!(vm, __module__), vm) {
1023 Ok(module) => Ok(module),
1024 Err(_) => {
1025 Ok(vm.ctx.none())
1027 }
1028 }
1029 } else {
1030 Ok(vm.ctx.none())
1031 }
1032 }
1033
1034 #[cfg(feature = "threading")]
1037 #[pyfunction]
1038 fn _current_frames(vm: &VirtualMachine) -> PyResult<PyDictRef> {
1039 use crate::AsObject;
1040 use crate::stdlib::_thread::get_all_current_frames;
1041
1042 let frames = get_all_current_frames(vm);
1043 let dict = vm.ctx.new_dict();
1044
1045 for (thread_id, frame) in frames {
1046 let key = vm.ctx.new_int(thread_id);
1047 dict.set_item(key.as_object(), frame.into(), vm)?;
1048 }
1049
1050 Ok(dict)
1051 }
1052
1053 #[cfg(feature = "threading")]
1056 #[pyfunction]
1057 fn _current_exceptions(vm: &VirtualMachine) -> PyResult<PyDictRef> {
1058 use crate::AsObject;
1059 use crate::vm::thread::get_all_current_exceptions;
1060
1061 let dict = vm.ctx.new_dict();
1062 for (thread_id, exc) in get_all_current_exceptions(vm) {
1063 let key = vm.ctx.new_int(thread_id);
1064 let value = exc.map_or_else(|| vm.ctx.none(), |e| e.into());
1065 dict.set_item(key.as_object(), value, vm)?;
1066 }
1067
1068 Ok(dict)
1069 }
1070
1071 #[cfg(not(feature = "threading"))]
1072 #[pyfunction]
1073 fn _current_exceptions(vm: &VirtualMachine) -> PyResult<PyDictRef> {
1074 let dict = vm.ctx.new_dict();
1075 let key = vm.ctx.new_int(0);
1076 dict.set_item(key.as_object(), vm.topmost_exception().to_pyobject(vm), vm)?;
1077 Ok(dict)
1078 }
1079
1080 #[cfg(not(feature = "threading"))]
1082 #[pyfunction]
1083 fn _current_frames(vm: &VirtualMachine) -> PyResult<PyDictRef> {
1084 Ok(vm.ctx.new_dict())
1085 }
1086
1087 #[pyfunction]
1088 fn gettrace(vm: &VirtualMachine) -> PyObjectRef {
1089 vm.trace_func.borrow().clone()
1090 }
1091
1092 #[cfg(windows)]
1093 fn get_kernel32_version() -> std::io::Result<(u32, u32, u32)> {
1094 use crate::common::windows::ToWideString;
1095 unsafe {
1096 let module_name: Vec<u16> = std::ffi::OsStr::new("kernel32.dll").to_wide_with_nul();
1098 let h_kernel32 = GetModuleHandleW(module_name.as_ptr());
1099 if h_kernel32.is_null() {
1100 return Err(std::io::Error::last_os_error());
1101 }
1102
1103 let mut kernel32_path = [0u16; MAX_PATH as usize];
1105 let len = GetModuleFileNameW(
1106 h_kernel32,
1107 kernel32_path.as_mut_ptr(),
1108 kernel32_path.len() as u32,
1109 );
1110 if len == 0 {
1111 return Err(std::io::Error::last_os_error());
1112 }
1113
1114 let ver_block_size =
1116 GetFileVersionInfoSizeW(kernel32_path.as_ptr(), core::ptr::null_mut());
1117 if ver_block_size == 0 {
1118 return Err(std::io::Error::last_os_error());
1119 }
1120
1121 let mut ver_block = vec![0u8; ver_block_size as usize];
1123 if GetFileVersionInfoW(
1124 kernel32_path.as_ptr(),
1125 0,
1126 ver_block_size,
1127 ver_block.as_mut_ptr() as *mut _,
1128 ) == 0
1129 {
1130 return Err(std::io::Error::last_os_error());
1131 }
1132
1133 let sub_block: Vec<u16> = std::ffi::OsStr::new("").to_wide_with_nul();
1135
1136 let mut ffi_ptr: *mut VS_FIXEDFILEINFO = core::ptr::null_mut();
1137 let mut ffi_len: u32 = 0;
1138 if VerQueryValueW(
1139 ver_block.as_ptr() as *const _,
1140 sub_block.as_ptr(),
1141 &mut ffi_ptr as *mut *mut VS_FIXEDFILEINFO as *mut *mut _,
1142 &mut ffi_len as *mut u32,
1143 ) == 0
1144 || ffi_ptr.is_null()
1145 {
1146 return Err(std::io::Error::last_os_error());
1147 }
1148
1149 let ffi = *ffi_ptr;
1151 let real_major = (ffi.dwProductVersionMS >> 16) & 0xFFFF;
1152 let real_minor = ffi.dwProductVersionMS & 0xFFFF;
1153 let real_build = (ffi.dwProductVersionLS >> 16) & 0xFFFF;
1154
1155 Ok((real_major, real_minor, real_build))
1156 }
1157 }
1158
1159 #[cfg(windows)]
1160 #[pyfunction]
1161 fn getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::builtins::tuple::PyTupleRef> {
1162 use std::ffi::OsString;
1163 use std::os::windows::ffi::OsStringExt;
1164 use windows_sys::Win32::System::SystemInformation::{
1165 GetVersionExW, OSVERSIONINFOEXW, OSVERSIONINFOW,
1166 };
1167
1168 let mut version: OSVERSIONINFOEXW = unsafe { core::mem::zeroed() };
1169 version.dwOSVersionInfoSize = core::mem::size_of::<OSVERSIONINFOEXW>() as u32;
1170 let result = unsafe {
1171 let os_vi = &mut version as *mut OSVERSIONINFOEXW as *mut OSVERSIONINFOW;
1172 GetVersionExW(os_vi)
1175 };
1176
1177 if result == 0 {
1178 return Err(vm.new_os_error("failed to get windows version".to_owned()));
1179 }
1180
1181 let service_pack = {
1182 let (last, _) = version
1183 .szCSDVersion
1184 .iter()
1185 .take_while(|&x| x != &0)
1186 .enumerate()
1187 .last()
1188 .unwrap_or((0, &0));
1189 let sp = OsString::from_wide(&version.szCSDVersion[..last]);
1190 sp.into_string()
1191 .map_err(|_| vm.new_os_error("service pack is not ASCII".to_owned()))?
1192 };
1193 let real_version = get_kernel32_version().map_err(|e| vm.new_os_error(e.to_string()))?;
1194 let winver = WindowsVersionData {
1195 major: real_version.0,
1196 minor: real_version.1,
1197 build: real_version.2,
1198 platform: version.dwPlatformId,
1199 service_pack,
1200 service_pack_major: version.wServicePackMajor,
1201 service_pack_minor: version.wServicePackMinor,
1202 suite_mask: version.wSuiteMask,
1203 product_type: version.wProductType,
1204 platform_version: (real_version.0, real_version.1, real_version.2), };
1206 Ok(PyWindowsVersion::from_data(winver, vm))
1207 }
1208
1209 fn _unraisablehook(unraisable: UnraisableHookArgsData, vm: &VirtualMachine) -> PyResult<()> {
1210 use super::PyStderr;
1211
1212 let stderr = PyStderr(vm);
1213 if !vm.is_none(&unraisable.object) {
1214 if !vm.is_none(&unraisable.err_msg) {
1215 write!(stderr, "{}: ", unraisable.err_msg.str(vm)?);
1216 } else {
1217 write!(stderr, "Exception ignored in: ");
1218 }
1219 let repr = &unraisable.object.repr(vm);
1221 let str = match repr {
1222 Ok(v) => v.to_string(),
1223 Err(_) => format!(
1224 "<object {} repr() failed>",
1225 unraisable.object.class().name()
1226 ),
1227 };
1228 writeln!(stderr, "{str}");
1229 } else if !vm.is_none(&unraisable.err_msg) {
1230 writeln!(stderr, "{}:", unraisable.err_msg.str(vm)?);
1231 }
1232
1233 if !vm.is_none(&unraisable.exc_traceback) {
1235 let tb_module = vm.import("traceback", 0)?;
1236 let print_tb = tb_module.get_attr("print_tb", vm)?;
1237 let stderr_obj = super::get_stderr(vm)?;
1238 let kwargs: KwArgs = [("file".to_string(), stderr_obj)].into_iter().collect();
1239 let _ = print_tb.call(
1240 FuncArgs::new(vec![unraisable.exc_traceback.clone()], kwargs),
1241 vm,
1242 );
1243 }
1244
1245 if vm.is_none(unraisable.exc_type.as_object()) {
1247 return Ok(());
1248 }
1249 assert!(
1250 unraisable
1251 .exc_type
1252 .fast_issubclass(vm.ctx.exceptions.base_exception_type)
1253 );
1254
1255 let module_name = unraisable.exc_type.__module__(vm);
1257 if let Ok(module_str) = module_name.downcast::<PyStr>() {
1258 let module = module_str.as_wtf8();
1259 if module != "builtins" && module != "__main__" {
1260 write!(stderr, "{}.", module);
1261 }
1262 } else {
1263 write!(stderr, "<unknown>.");
1264 }
1265
1266 let qualname = unraisable.exc_type.__qualname__(vm);
1268 if let Ok(qualname_str) = qualname.downcast::<PyStr>() {
1269 write!(stderr, "{}", qualname_str.as_wtf8());
1270 } else {
1271 write!(stderr, "{}", unraisable.exc_type.name());
1272 }
1273
1274 if !vm.is_none(&unraisable.exc_value) {
1276 write!(stderr, ": ");
1277 if let Ok(str) = unraisable.exc_value.str(vm) {
1278 write!(stderr, "{}", str.as_wtf8());
1279 } else {
1280 write!(stderr, "<exception str() failed>");
1281 }
1282 }
1283 writeln!(stderr);
1284
1285 if let Ok(stderr_obj) = super::get_stderr(vm)
1287 && let Ok(flush) = stderr_obj.get_attr("flush", vm)
1288 {
1289 let _ = flush.call((), vm);
1290 }
1291
1292 Ok(())
1293 }
1294
1295 #[pyattr]
1296 #[pyfunction(name = "__unraisablehook__")]
1297 fn unraisablehook(unraisable: UnraisableHookArgsData, vm: &VirtualMachine) {
1298 if let Err(e) = _unraisablehook(unraisable, vm) {
1299 let stderr = super::PyStderr(vm);
1300 writeln!(
1301 stderr,
1302 "{}",
1303 e.as_object()
1304 .repr(vm)
1305 .unwrap_or_else(|_| vm.ctx.empty_str.to_owned())
1306 );
1307 }
1308 }
1309
1310 #[pyattr]
1311 fn hash_info(vm: &VirtualMachine) -> PyTupleRef {
1312 PyHashInfo::from_data(HashInfoData::INFO, vm)
1313 }
1314
1315 #[pyfunction]
1316 fn intern(s: PyRefExact<PyStr>, vm: &VirtualMachine) -> PyRef<PyStr> {
1317 vm.ctx.intern_str(s).to_owned()
1318 }
1319
1320 #[pyattr]
1321 fn int_info(vm: &VirtualMachine) -> PyTupleRef {
1322 PyIntInfo::from_data(IntInfoData::INFO, vm)
1323 }
1324
1325 #[pyfunction]
1326 fn get_int_max_str_digits(vm: &VirtualMachine) -> usize {
1327 vm.state.int_max_str_digits.load()
1328 }
1329
1330 #[pyfunction]
1331 fn set_int_max_str_digits(maxdigits: usize, vm: &VirtualMachine) -> PyResult<()> {
1332 let threshold = IntInfoData::INFO.str_digits_check_threshold;
1333 if maxdigits == 0 || maxdigits >= threshold {
1334 vm.state.int_max_str_digits.store(maxdigits);
1335 Ok(())
1336 } else {
1337 let error = format!("maxdigits must be 0 or larger than {threshold:?}");
1338 Err(vm.new_value_error(error))
1339 }
1340 }
1341
1342 #[pyfunction]
1343 fn is_finalizing(vm: &VirtualMachine) -> bool {
1344 vm.state.finalizing.load(Ordering::Acquire)
1345 }
1346
1347 #[pyfunction]
1348 fn setprofile(profilefunc: PyObjectRef, vm: &VirtualMachine) {
1349 vm.profile_func.replace(profilefunc);
1350 update_use_tracing(vm);
1351 }
1352
1353 #[pyfunction]
1354 fn setrecursionlimit(recursion_limit: i32, vm: &VirtualMachine) -> PyResult<()> {
1355 let recursion_limit = recursion_limit
1356 .to_usize()
1357 .filter(|&u| u >= 1)
1358 .ok_or_else(|| {
1359 vm.new_value_error("recursion limit must be greater than or equal to one")
1360 })?;
1361 let recursion_depth = vm.current_recursion_depth();
1362
1363 if recursion_limit > recursion_depth {
1364 vm.recursion_limit.set(recursion_limit);
1365 Ok(())
1366 } else {
1367 Err(vm.new_recursion_error(format!(
1368 "cannot set the recursion limit to {recursion_limit} at the recursion depth {recursion_depth}: the limit is too low"
1369 )))
1370 }
1371 }
1372
1373 #[pyfunction]
1374 fn settrace(tracefunc: PyObjectRef, vm: &VirtualMachine) {
1375 vm.trace_func.replace(tracefunc);
1376 update_use_tracing(vm);
1377 }
1378
1379 #[pyfunction]
1380 fn _settraceallthreads(tracefunc: PyObjectRef, vm: &VirtualMachine) {
1381 let func = (!vm.is_none(&tracefunc)).then(|| tracefunc.clone());
1382 *vm.state.global_trace_func.lock() = func;
1383 vm.trace_func.replace(tracefunc);
1384 update_use_tracing(vm);
1385 }
1386
1387 #[pyfunction]
1388 fn _setprofileallthreads(profilefunc: PyObjectRef, vm: &VirtualMachine) {
1389 let func = (!vm.is_none(&profilefunc)).then(|| profilefunc.clone());
1390 *vm.state.global_profile_func.lock() = func;
1391 vm.profile_func.replace(profilefunc);
1392 update_use_tracing(vm);
1393 }
1394
1395 #[cfg(feature = "threading")]
1396 #[pyattr]
1397 fn thread_info(vm: &VirtualMachine) -> PyTupleRef {
1398 PyThreadInfo::from_data(ThreadInfoData::INFO, vm)
1399 }
1400
1401 #[pyattr]
1402 fn version_info(vm: &VirtualMachine) -> PyTupleRef {
1403 PyVersionInfo::from_data(VersionInfoData::VERSION, vm)
1404 }
1405
1406 fn update_use_tracing(vm: &VirtualMachine) {
1407 let trace_is_none = vm.is_none(&vm.trace_func.borrow());
1408 let profile_is_none = vm.is_none(&vm.profile_func.borrow());
1409 let tracing = !(trace_is_none && profile_is_none);
1410 vm.use_tracing.set(tracing);
1411 }
1412
1413 #[pyfunction]
1414 fn set_coroutine_origin_tracking_depth(depth: i32, vm: &VirtualMachine) -> PyResult<()> {
1415 if depth < 0 {
1416 return Err(vm.new_value_error("depth must be >= 0"));
1417 }
1418 crate::vm::thread::COROUTINE_ORIGIN_TRACKING_DEPTH.set(depth as u32);
1419 Ok(())
1420 }
1421
1422 #[pyfunction]
1423 fn get_coroutine_origin_tracking_depth() -> i32 {
1424 crate::vm::thread::COROUTINE_ORIGIN_TRACKING_DEPTH.get() as i32
1425 }
1426
1427 #[pyfunction]
1428 fn _clear_type_descriptors(type_obj: PyTypeRef, vm: &VirtualMachine) -> PyResult<()> {
1429 use crate::types::PyTypeFlags;
1430
1431 if type_obj.slots.flags.has_feature(PyTypeFlags::IMMUTABLETYPE) {
1433 return Err(vm.new_type_error("argument is immutable"));
1434 }
1435
1436 let mut attributes = type_obj.attributes.write();
1437
1438 attributes.swap_remove(identifier!(vm, __dict__));
1440
1441 attributes.swap_remove(identifier!(vm, __weakref__));
1443
1444 drop(attributes);
1445
1446 type_obj.update_slot::<true>(identifier!(vm, __dict__), &vm.ctx);
1448 type_obj.update_slot::<true>(identifier!(vm, __weakref__), &vm.ctx);
1449
1450 Ok(())
1451 }
1452
1453 #[pyfunction]
1454 fn getswitchinterval(vm: &VirtualMachine) -> f64 {
1455 vm.state.switch_interval.load()
1457 }
1458
1459 #[pyfunction]
1461 fn setswitchinterval(interval: f64, vm: &VirtualMachine) -> PyResult<()> {
1462 if interval <= 0.0 {
1464 return Err(vm.new_value_error("switch interval must be strictly positive"));
1465 }
1466
1467 vm.state.switch_interval.store(interval);
1469 Ok(())
1470 }
1471
1472 #[derive(FromArgs)]
1473 struct SetAsyncgenHooksArgs {
1474 #[pyarg(any, optional)]
1475 firstiter: OptionalArg<Option<PyObjectRef>>,
1476 #[pyarg(any, optional)]
1477 finalizer: OptionalArg<Option<PyObjectRef>>,
1478 }
1479
1480 #[pyfunction]
1481 fn set_asyncgen_hooks(args: SetAsyncgenHooksArgs, vm: &VirtualMachine) -> PyResult<()> {
1482 if let Some(Some(finalizer)) = args.finalizer.as_option()
1483 && !finalizer.is_callable()
1484 {
1485 return Err(vm.new_type_error(format!(
1486 "callable finalizer expected, got {:.50}",
1487 finalizer.class().name()
1488 )));
1489 }
1490
1491 if let Some(Some(firstiter)) = args.firstiter.as_option()
1492 && !firstiter.is_callable()
1493 {
1494 return Err(vm.new_type_error(format!(
1495 "callable firstiter expected, got {:.50}",
1496 firstiter.class().name()
1497 )));
1498 }
1499
1500 if let Some(finalizer) = args.finalizer.into_option() {
1501 *vm.async_gen_finalizer.borrow_mut() = finalizer;
1502 }
1503 if let Some(firstiter) = args.firstiter.into_option() {
1504 *vm.async_gen_firstiter.borrow_mut() = firstiter;
1505 }
1506
1507 Ok(())
1508 }
1509
1510 #[pystruct_sequence_data]
1511 pub(super) struct AsyncgenHooksData {
1512 firstiter: PyObjectRef,
1513 finalizer: PyObjectRef,
1514 }
1515
1516 #[pyattr]
1517 #[pystruct_sequence(name = "asyncgen_hooks", data = "AsyncgenHooksData")]
1518 pub(super) struct PyAsyncgenHooks;
1519
1520 #[pyclass(with(PyStructSequence))]
1521 impl PyAsyncgenHooks {}
1522
1523 #[pyfunction]
1524 fn get_asyncgen_hooks(vm: &VirtualMachine) -> AsyncgenHooksData {
1525 AsyncgenHooksData {
1526 firstiter: vm.async_gen_firstiter.borrow().clone().to_pyobject(vm),
1527 finalizer: vm.async_gen_finalizer.borrow().clone().to_pyobject(vm),
1528 }
1529 }
1530
1531 #[derive(Debug)]
1535 #[pystruct_sequence_data]
1536 pub(super) struct FlagsData {
1537 debug: u8,
1539 inspect: u8,
1541 interactive: u8,
1543 optimize: u8,
1545 dont_write_bytecode: u8,
1547 no_user_site: u8,
1549 no_site: u8,
1551 ignore_environment: u8,
1553 verbose: u8,
1555 bytes_warning: u64,
1557 quiet: u8,
1559 hash_randomization: u8,
1561 isolated: u8,
1563 dev_mode: bool,
1565 utf8_mode: u8,
1567 int_max_str_digits: i64,
1569 safe_path: bool,
1571 warn_default_encoding: u8,
1573 }
1574
1575 impl FlagsData {
1576 const fn from_settings(settings: &Settings) -> Self {
1577 Self {
1578 debug: settings.debug,
1579 inspect: settings.inspect as u8,
1580 interactive: settings.interactive as u8,
1581 optimize: settings.optimize,
1582 dont_write_bytecode: (!settings.write_bytecode) as u8,
1583 no_user_site: (!settings.user_site_directory) as u8,
1584 no_site: (!settings.import_site) as u8,
1585 ignore_environment: settings.ignore_environment as u8,
1586 verbose: settings.verbose,
1587 bytes_warning: settings.bytes_warning,
1588 quiet: settings.quiet as u8,
1589 hash_randomization: settings.hash_seed.is_none() as u8,
1590 isolated: settings.isolated as u8,
1591 dev_mode: settings.dev_mode,
1592 utf8_mode: if settings.utf8_mode < 0 {
1593 1
1594 } else {
1595 settings.utf8_mode as u8
1596 },
1597 int_max_str_digits: settings.int_max_str_digits,
1598 safe_path: settings.safe_path,
1599 warn_default_encoding: settings.warn_default_encoding as u8,
1600 }
1601 }
1602 }
1603
1604 #[pystruct_sequence(name = "flags", data = "FlagsData", no_attr)]
1605 pub(super) struct PyFlags;
1606
1607 #[pyclass(with(PyStructSequence))]
1608 impl PyFlags {
1609 #[pyslot]
1610 fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1611 Err(vm.new_type_error("cannot create 'sys.flags' instances"))
1612 }
1613
1614 #[pygetset]
1615 fn context_aware_warnings(&self, vm: &VirtualMachine) -> bool {
1616 vm.state.config.settings.context_aware_warnings
1617 }
1618
1619 #[pygetset]
1620 fn thread_inherit_context(&self, vm: &VirtualMachine) -> bool {
1621 vm.state.config.settings.thread_inherit_context
1622 }
1623 }
1624
1625 #[cfg(feature = "threading")]
1626 #[pystruct_sequence_data]
1627 pub(super) struct ThreadInfoData {
1628 name: Option<&'static str>,
1629 lock: Option<&'static str>,
1630 version: Option<&'static str>,
1631 }
1632
1633 #[cfg(feature = "threading")]
1634 impl ThreadInfoData {
1635 const INFO: Self = Self {
1636 name: crate::stdlib::_thread::_thread::PYTHREAD_NAME,
1637 lock: Some("mutex+cond"),
1640 version: None,
1641 };
1642 }
1643
1644 #[cfg(feature = "threading")]
1645 #[pystruct_sequence(name = "thread_info", data = "ThreadInfoData", no_attr)]
1646 pub(super) struct PyThreadInfo;
1647
1648 #[cfg(feature = "threading")]
1649 #[pyclass(with(PyStructSequence))]
1650 impl PyThreadInfo {}
1651
1652 #[pystruct_sequence_data]
1653 pub(super) struct FloatInfoData {
1654 max: f64,
1655 max_exp: i32,
1656 max_10_exp: i32,
1657 min: f64,
1658 min_exp: i32,
1659 min_10_exp: i32,
1660 dig: u32,
1661 mant_dig: u32,
1662 epsilon: f64,
1663 radix: u32,
1664 rounds: i32,
1665 }
1666
1667 impl FloatInfoData {
1668 const INFO: Self = Self {
1669 max: f64::MAX,
1670 max_exp: f64::MAX_EXP,
1671 max_10_exp: f64::MAX_10_EXP,
1672 min: f64::MIN_POSITIVE,
1673 min_exp: f64::MIN_EXP,
1674 min_10_exp: f64::MIN_10_EXP,
1675 dig: f64::DIGITS,
1676 mant_dig: f64::MANTISSA_DIGITS,
1677 epsilon: f64::EPSILON,
1678 radix: f64::RADIX,
1679 rounds: 1, };
1681 }
1682
1683 #[pystruct_sequence(name = "float_info", data = "FloatInfoData", no_attr)]
1684 pub(super) struct PyFloatInfo;
1685
1686 #[pyclass(with(PyStructSequence))]
1687 impl PyFloatInfo {}
1688
1689 #[pystruct_sequence_data]
1690 pub(super) struct HashInfoData {
1691 width: usize,
1692 modulus: PyUHash,
1693 inf: PyHash,
1694 nan: PyHash,
1695 imag: PyHash,
1696 algorithm: &'static str,
1697 hash_bits: usize,
1698 seed_bits: usize,
1699 cutoff: usize,
1700 }
1701
1702 impl HashInfoData {
1703 const INFO: Self = {
1704 use rustpython_common::hash::*;
1705 Self {
1706 width: core::mem::size_of::<PyHash>() * 8,
1707 modulus: MODULUS,
1708 inf: INF,
1709 nan: NAN,
1710 imag: IMAG,
1711 algorithm: ALGO,
1712 hash_bits: HASH_BITS,
1713 seed_bits: SEED_BITS,
1714 cutoff: 0, }
1716 };
1717 }
1718
1719 #[pystruct_sequence(name = "hash_info", data = "HashInfoData", no_attr)]
1720 pub(super) struct PyHashInfo;
1721
1722 #[pyclass(with(PyStructSequence))]
1723 impl PyHashInfo {}
1724
1725 #[pystruct_sequence_data]
1726 pub(super) struct IntInfoData {
1727 bits_per_digit: usize,
1728 sizeof_digit: usize,
1729 default_max_str_digits: usize,
1730 str_digits_check_threshold: usize,
1731 }
1732
1733 impl IntInfoData {
1734 const INFO: Self = Self {
1735 bits_per_digit: 30, sizeof_digit: core::mem::size_of::<u32>(),
1737 default_max_str_digits: 4300,
1738 str_digits_check_threshold: 640,
1739 };
1740 }
1741
1742 #[pystruct_sequence(name = "int_info", data = "IntInfoData", no_attr)]
1743 pub(super) struct PyIntInfo;
1744
1745 #[pyclass(with(PyStructSequence))]
1746 impl PyIntInfo {}
1747
1748 #[derive(Default, Debug)]
1749 #[pystruct_sequence_data]
1750 pub struct VersionInfoData {
1751 major: usize,
1752 minor: usize,
1753 micro: usize,
1754 releaselevel: &'static str,
1755 serial: usize,
1756 }
1757
1758 impl VersionInfoData {
1759 pub const VERSION: Self = Self {
1760 major: version::MAJOR,
1761 minor: version::MINOR,
1762 micro: version::MICRO,
1763 releaselevel: version::RELEASELEVEL,
1764 serial: version::SERIAL,
1765 };
1766 }
1767
1768 #[pystruct_sequence(name = "version_info", data = "VersionInfoData", no_attr)]
1769 pub struct PyVersionInfo;
1770
1771 #[pyclass(with(PyStructSequence))]
1772 impl PyVersionInfo {
1773 #[pyslot]
1774 fn slot_new(
1775 _cls: crate::builtins::type_::PyTypeRef,
1776 _args: crate::function::FuncArgs,
1777 vm: &crate::VirtualMachine,
1778 ) -> crate::PyResult {
1779 Err(vm.new_type_error("cannot create 'sys.version_info' instances"))
1780 }
1781 }
1782
1783 #[cfg(windows)]
1784 #[derive(Default, Debug)]
1785 #[pystruct_sequence_data]
1786 pub(super) struct WindowsVersionData {
1787 major: u32,
1788 minor: u32,
1789 build: u32,
1790 platform: u32,
1791 service_pack: String,
1792 #[pystruct_sequence(skip)]
1793 service_pack_major: u16,
1794 #[pystruct_sequence(skip)]
1795 service_pack_minor: u16,
1796 #[pystruct_sequence(skip)]
1797 suite_mask: u16,
1798 #[pystruct_sequence(skip)]
1799 product_type: u8,
1800 #[pystruct_sequence(skip)]
1801 platform_version: (u32, u32, u32),
1802 }
1803
1804 #[cfg(windows)]
1805 #[pystruct_sequence(name = "getwindowsversion", data = "WindowsVersionData", no_attr)]
1806 pub(super) struct PyWindowsVersion;
1807
1808 #[cfg(windows)]
1809 #[pyclass(with(PyStructSequence))]
1810 impl PyWindowsVersion {
1811 #[pyslot]
1812 fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1813 Err(vm.new_type_error("cannot create 'sys.getwindowsversion' instances"))
1814 }
1815 }
1816
1817 #[derive(Debug)]
1818 #[pystruct_sequence_data(try_from_object)]
1819 pub struct UnraisableHookArgsData {
1820 pub exc_type: PyTypeRef,
1821 pub exc_value: PyObjectRef,
1822 pub exc_traceback: PyObjectRef,
1823 pub err_msg: PyObjectRef,
1824 pub object: PyObjectRef,
1825 }
1826
1827 #[pystruct_sequence(name = "UnraisableHookArgs", data = "UnraisableHookArgsData", no_attr)]
1828 pub struct PyUnraisableHookArgs;
1829
1830 #[pyclass(with(PyStructSequence))]
1831 impl PyUnraisableHookArgs {}
1832}
1833
1834pub(crate) fn init_module(vm: &VirtualMachine, module: &Py<PyModule>, builtins: &Py<PyModule>) {
1835 module.__init_methods(vm).unwrap();
1836 sys::module_exec(vm, module).unwrap();
1837
1838 let modules = vm.ctx.new_dict();
1839 modules
1840 .set_item("sys", module.to_owned().into(), vm)
1841 .unwrap();
1842 modules
1843 .set_item("builtins", builtins.to_owned().into(), vm)
1844 .unwrap();
1845
1846 let jit_def = sys_jit::module_def(&vm.ctx);
1848 let jit_module = jit_def.create_module(vm).unwrap();
1849
1850 extend_module!(vm, module, {
1851 "__doc__" => sys::DOC.to_owned().to_pyobject(vm),
1852 "modules" => modules,
1853 "_jit" => jit_module,
1854 });
1855}
1856
1857pub(crate) fn set_bootstrap_stderr(vm: &VirtualMachine) -> PyResult<()> {
1858 let stderr = sys::BootstrapStderr.into_ref(&vm.ctx);
1859 let stderr_obj: crate::PyObjectRef = stderr.into();
1860 vm.sys_module.set_attr("stderr", stderr_obj.clone(), vm)?;
1861 vm.sys_module.set_attr("__stderr__", stderr_obj, vm)?;
1862 Ok(())
1863}
1864
1865pub struct PyStderr<'vm>(pub &'vm VirtualMachine);
1877
1878impl PyStderr<'_> {
1879 pub fn write_fmt(&self, args: core::fmt::Arguments<'_>) {
1880 use crate::py_io::Write;
1881
1882 let vm = self.0;
1883 if let Ok(stderr) = get_stderr(vm) {
1884 let mut stderr = crate::py_io::PyWriter(stderr, vm);
1885 if let Ok(()) = stderr.write_fmt(args) {
1886 return;
1887 }
1888 }
1889 eprint!("{args}")
1890 }
1891}
1892
1893pub fn get_stdin(vm: &VirtualMachine) -> PyResult {
1894 vm.sys_module
1895 .get_attr("stdin", vm)
1896 .map_err(|_| vm.new_runtime_error("lost sys.stdin"))
1897}
1898pub fn get_stdout(vm: &VirtualMachine) -> PyResult {
1899 vm.sys_module
1900 .get_attr("stdout", vm)
1901 .map_err(|_| vm.new_runtime_error("lost sys.stdout"))
1902}
1903pub fn get_stderr(vm: &VirtualMachine) -> PyResult {
1904 vm.sys_module
1905 .get_attr("stderr", vm)
1906 .map_err(|_| vm.new_runtime_error("lost sys.stderr"))
1907}
1908
1909pub(crate) fn sysconfigdata_name() -> String {
1910 format!(
1911 "_sysconfigdata_{}_{}_{}",
1912 sys::ABIFLAGS,
1913 sys::PLATFORM,
1914 sys::multiarch()
1915 )
1916}