1use crate::{Py, VirtualMachine, builtins::PyModule, class::PyClassImpl};
5pub(crate) use builtins::{DOC, module_def};
6pub use builtins::{ascii, print, reversed};
7
8#[pymodule]
9mod builtins {
10 use crate::{
11 AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
12 builtins::{
13 PyByteArray, PyBytes, PyDictRef, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType,
14 PyUtf8StrRef,
15 enumerate::PyReverseSequenceIterator,
16 function::{PyCellRef, PyFunction},
17 int::PyIntRef,
18 iter::PyCallableIterator,
19 list::{PyList, SortOptions},
20 },
21 common::hash::PyHash,
22 function::{
23 ArgBytesLike, ArgCallable, ArgIndex, ArgIntoBool, ArgIterable, ArgMapping,
24 ArgStrOrBytesLike, Either, FsPath, FuncArgs, KwArgs, OptionalArg, OptionalOption,
25 PosArgs,
26 },
27 protocol::{PyIter, PyIterReturn},
28 py_io,
29 readline::{Readline, ReadlineResult},
30 stdlib::sys,
31 types::PyComparisonOp,
32 };
33 use itertools::Itertools;
34 use num_traits::{Signed, ToPrimitive, Zero};
35 use rustpython_common::wtf8::CodePoint;
36
37 #[cfg(not(feature = "rustpython-compiler"))]
38 const CODEGEN_NOT_SUPPORTED: &str =
39 "can't compile() to bytecode when the `codegen` feature of rustpython is disabled";
40
41 #[pyfunction]
42 fn abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
43 vm._abs(&x)
44 }
45
46 #[pyfunction]
47 fn all(iterable: ArgIterable<ArgIntoBool>, vm: &VirtualMachine) -> PyResult<bool> {
48 for item in iterable.iter(vm)? {
49 if !item?.into_bool() {
50 return Ok(false);
51 }
52 }
53 Ok(true)
54 }
55
56 #[pyfunction]
57 fn any(iterable: ArgIterable<ArgIntoBool>, vm: &VirtualMachine) -> PyResult<bool> {
58 for item in iterable.iter(vm)? {
59 if item?.into_bool() {
60 return Ok(true);
61 }
62 }
63 Ok(false)
64 }
65
66 #[pyfunction]
67 pub fn ascii(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
68 obj.ascii(vm)
69 }
70
71 #[pyfunction]
72 fn bin(x: PyIntRef) -> String {
73 let x = x.as_bigint();
74 if x.is_negative() {
75 format!("-0b{:b}", x.abs())
76 } else {
77 format!("0b{x:b}")
78 }
79 }
80
81 #[pyfunction]
82 fn callable(obj: PyObjectRef) -> bool {
83 obj.is_callable()
84 }
85
86 #[pyfunction]
87 fn chr(i: PyIntRef, vm: &VirtualMachine) -> PyResult<CodePoint> {
88 let value = i
89 .as_bigint()
90 .to_u32()
91 .and_then(CodePoint::from_u32)
92 .ok_or_else(|| vm.new_value_error("chr() arg not in range(0x110000)"))?;
93 Ok(value)
94 }
95
96 #[derive(FromArgs)]
97 #[allow(dead_code)]
98 struct CompileArgs {
99 source: PyObjectRef,
100 filename: FsPath,
101 mode: PyUtf8StrRef,
102 #[pyarg(any, optional)]
103 flags: OptionalArg<PyIntRef>,
104 #[pyarg(any, optional)]
105 dont_inherit: OptionalArg<bool>,
106 #[pyarg(any, optional)]
107 optimize: OptionalArg<PyIntRef>,
108 #[pyarg(any, optional)]
109 _feature_version: OptionalArg<i32>,
110 }
111
112 #[cfg(feature = "parser")]
116 fn detect_source_encoding(source: &[u8]) -> Option<String> {
117 fn find_encoding_in_line(line: &[u8]) -> Option<String> {
118 let hash_pos = line.iter().position(|&b| b == b'#')?;
120 if !line[..hash_pos]
121 .iter()
122 .all(|&b| b == b' ' || b == b'\t' || b == b'\x0c' || b == b'\r')
123 {
124 return None;
125 }
126 let after_hash = &line[hash_pos..];
127
128 let coding_pos = after_hash.windows(6).position(|w| w == b"coding")?;
130 let after_coding = &after_hash[coding_pos + 6..];
131
132 let rest = if after_coding.first() == Some(&b':') || after_coding.first() == Some(&b'=')
134 {
135 &after_coding[1..]
136 } else {
137 return None;
138 };
139
140 let rest = rest
142 .iter()
143 .copied()
144 .skip_while(|&b| b == b' ' || b == b'\t')
145 .collect::<Vec<_>>();
146
147 let name: String = rest
149 .iter()
150 .take_while(|&&b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_' || b == b'.')
151 .map(|&b| b as char)
152 .collect();
153
154 if name.is_empty() { None } else { Some(name) }
155 }
156
157 let mut lines = source.splitn(3, |&b| b == b'\n');
159
160 if let Some(first) = lines.next() {
161 let first = first.strip_prefix(b"\xef\xbb\xbf").unwrap_or(first);
163 if let Some(enc) = find_encoding_in_line(first) {
164 return Some(enc);
165 }
166 let trimmed = first
168 .iter()
169 .skip_while(|&&b| b == b' ' || b == b'\t' || b == b'\x0c' || b == b'\r')
170 .copied()
171 .collect::<Vec<_>>();
172 if !trimmed.is_empty() && trimmed[0] != b'#' {
173 return None;
174 }
175 }
176
177 lines.next().and_then(find_encoding_in_line)
178 }
179
180 #[cfg(feature = "parser")]
186 fn is_utf8_encoding(name: &str) -> bool {
187 let normalized: String = name.chars().filter(|&c| c != '-' && c != '_').collect();
188 normalized.eq_ignore_ascii_case("utf8")
189 }
190
191 #[cfg(feature = "parser")]
192 fn decode_source_bytes(source: &[u8], filename: &str, vm: &VirtualMachine) -> PyResult<String> {
193 let has_bom = source.starts_with(b"\xef\xbb\xbf");
194 let encoding = detect_source_encoding(source);
195
196 let is_utf8 = encoding.as_deref().is_none_or(is_utf8_encoding);
197
198 if has_bom && !is_utf8 {
200 return Err(vm.new_exception_msg(
201 vm.ctx.exceptions.syntax_error.to_owned(),
202 format!("encoding problem for '{filename}': utf-8").into(),
203 ));
204 }
205
206 if is_utf8 {
207 let src = if has_bom { &source[3..] } else { source };
208 match core::str::from_utf8(src) {
209 Ok(s) => Ok(s.to_owned()),
210 Err(e) => {
211 let bad_byte = src[e.valid_up_to()];
212 let line = src[..e.valid_up_to()]
213 .iter()
214 .filter(|&&b| b == b'\n')
215 .count()
216 + 1;
217 Err(vm.new_exception_msg(
218 vm.ctx.exceptions.syntax_error.to_owned(),
219 format!(
220 "Non-UTF-8 code starting with '\\x{bad_byte:02x}' \
221 on line {line}, but no encoding declared; \
222 see https://peps.python.org/pep-0263/ for details \
223 ({filename}, line {line})"
224 )
225 .into(),
226 ))
227 }
228 }
229 } else {
230 let enc = encoding.as_deref().unwrap();
232 let bytes_obj = vm.ctx.new_bytes(source.to_vec());
233 let decoded = vm
234 .state
235 .codec_registry
236 .decode_text(bytes_obj.into(), enc, None, vm)
237 .map_err(|exc| {
238 if exc.fast_isinstance(vm.ctx.exceptions.lookup_error) {
239 vm.new_exception_msg(
240 vm.ctx.exceptions.syntax_error.to_owned(),
241 format!("unknown encoding for '{filename}': {enc}").into(),
242 )
243 } else {
244 exc
245 }
246 })?;
247 Ok(decoded.to_string_lossy().into_owned())
248 }
249 }
250
251 #[cfg(any(feature = "parser", feature = "compiler"))]
252 #[pyfunction]
253 fn compile(args: CompileArgs, vm: &VirtualMachine) -> PyResult {
254 #[cfg(not(feature = "ast"))]
255 {
256 _ = args; return Err(vm.new_type_error("AST Not Supported"));
258 }
259 #[cfg(feature = "ast")]
260 {
261 use crate::{class::PyClassImpl, stdlib::_ast};
262
263 let feature_version = feature_version_from_arg(args._feature_version, vm)?;
264
265 let mode_str = args.mode.as_str();
266
267 let optimize: i32 = args.optimize.map_or(Ok(-1), |v| v.try_to_primitive(vm))?;
268 let optimize: u8 = if optimize == -1 {
269 vm.state.config.settings.optimize
270 } else {
271 optimize
272 .try_into()
273 .map_err(|_| vm.new_value_error("compile() optimize value invalid"))?
274 };
275
276 if args
277 .source
278 .fast_isinstance(&_ast::NodeAst::make_static_type())
279 {
280 let flags: i32 = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
281 let is_ast_only = !(flags & _ast::PY_CF_ONLY_AST).is_zero();
282
283 if mode_str == "func_type" && !is_ast_only {
285 return Err(vm.new_value_error(
286 "compile() mode 'func_type' requires flag PyCF_ONLY_AST",
287 ));
288 }
289
290 if is_ast_only {
292 let (expected_type, expected_name) = _ast::mode_type_and_name(mode_str)
293 .ok_or_else(|| {
294 vm.new_value_error(
295 "compile() mode must be 'exec', 'eval', 'single' or 'func_type'",
296 )
297 })?;
298 if !args.source.fast_isinstance(&expected_type) {
299 return Err(vm.new_type_error(format!(
300 "expected {} node, got {}",
301 expected_name,
302 args.source.class().name()
303 )));
304 }
305 _ast::validate_ast_object(vm, args.source.clone())?;
306 return Ok(args.source);
307 }
308
309 #[cfg(not(feature = "rustpython-codegen"))]
310 {
311 return Err(vm.new_type_error(CODEGEN_NOT_SUPPORTED.to_owned()));
312 }
313 #[cfg(feature = "rustpython-codegen")]
314 {
315 let mode = mode_str
316 .parse::<crate::compiler::Mode>()
317 .map_err(|err| vm.new_value_error(err.to_string()))?;
318 return _ast::compile(
319 vm,
320 args.source,
321 &args.filename.to_string_lossy(),
322 mode,
323 Some(optimize),
324 );
325 }
326 }
327
328 #[cfg(not(feature = "parser"))]
329 {
330 const PARSER_NOT_SUPPORTED: &str = "can't compile() source code when the `parser` feature of rustpython is disabled";
331 Err(vm.new_type_error(PARSER_NOT_SUPPORTED.to_owned()))
332 }
333 #[cfg(feature = "parser")]
334 {
335 use crate::convert::ToPyException;
336
337 use ruff_python_parser as parser;
338
339 let source = ArgStrOrBytesLike::try_from_object(vm, args.source)?;
340 let source = source.borrow_bytes();
341
342 let source = decode_source_bytes(&source, &args.filename.to_string_lossy(), vm)?;
343 let source = source.as_str();
344
345 let flags = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
346
347 if !(flags & !_ast::PY_COMPILE_FLAGS_MASK).is_zero() {
348 return Err(vm.new_value_error("compile() unrecognized flags"));
349 }
350
351 let allow_incomplete = !(flags & _ast::PY_CF_ALLOW_INCOMPLETE_INPUT).is_zero();
352 let type_comments = !(flags & _ast::PY_CF_TYPE_COMMENTS).is_zero();
353
354 let optimize_level = optimize;
355
356 if (flags & _ast::PY_CF_ONLY_AST).is_zero() {
357 #[cfg(not(feature = "compiler"))]
358 {
359 Err(vm.new_value_error(CODEGEN_NOT_SUPPORTED.to_owned()))
360 }
361 #[cfg(feature = "compiler")]
362 {
363 if let Some(feature_version) = feature_version {
364 let mode = mode_str
365 .parse::<parser::Mode>()
366 .map_err(|err| vm.new_value_error(err.to_string()))?;
367 let _ = _ast::parse(
368 vm,
369 source,
370 mode,
371 optimize_level,
372 Some(feature_version),
373 type_comments,
374 )
375 .map_err(|e| (e, Some(source), allow_incomplete).to_pyexception(vm))?;
376 }
377
378 let mode = mode_str
379 .parse::<crate::compiler::Mode>()
380 .map_err(|err| vm.new_value_error(err.to_string()))?;
381
382 let mut opts = vm.compile_opts();
383 opts.optimize = optimize;
384
385 let code = vm
386 .compile_with_opts(
387 source,
388 mode,
389 args.filename.to_string_lossy().into_owned(),
390 opts,
391 )
392 .map_err(|err| {
393 (err, Some(source), allow_incomplete).to_pyexception(vm)
394 })?;
395 Ok(code.into())
396 }
397 } else {
398 if mode_str == "func_type" {
399 return _ast::parse_func_type(vm, source, optimize_level, feature_version)
400 .map_err(|e| (e, Some(source), allow_incomplete).to_pyexception(vm));
401 }
402
403 let mode = mode_str
404 .parse::<parser::Mode>()
405 .map_err(|err| vm.new_value_error(err.to_string()))?;
406 let parsed = _ast::parse(
407 vm,
408 source,
409 mode,
410 optimize_level,
411 feature_version,
412 type_comments,
413 )
414 .map_err(|e| (e, Some(source), allow_incomplete).to_pyexception(vm))?;
415
416 if mode_str == "single" {
417 return _ast::wrap_interactive(vm, parsed);
418 }
419
420 Ok(parsed)
421 }
422 }
423 }
424 }
425
426 #[cfg(feature = "ast")]
427 fn feature_version_from_arg(
428 feature_version: OptionalArg<i32>,
429 vm: &VirtualMachine,
430 ) -> PyResult<Option<ruff_python_ast::PythonVersion>> {
431 let minor = match feature_version.into_option() {
432 Some(minor) => minor,
433 None => return Ok(None),
434 };
435
436 if minor < 0 {
437 return Ok(None);
438 }
439
440 let minor = u8::try_from(minor)
441 .map_err(|_| vm.new_value_error("compile() _feature_version out of range"))?;
442 Ok(Some(ruff_python_ast::PythonVersion { major: 3, minor }))
443 }
444
445 #[pyfunction]
446 fn delattr(obj: PyObjectRef, attr: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
447 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
448 vm.new_type_error(format!(
449 "attribute name must be string, not '{}'",
450 attr.class().name()
451 ))
452 })?;
453 obj.del_attr(attr, vm)
454 }
455
456 #[pyfunction]
457 fn dir(obj: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<PyList> {
458 vm.dir(obj.into_option())
459 }
460
461 #[pyfunction]
462 fn divmod(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult {
463 vm._divmod(&a, &b)
464 }
465
466 #[derive(FromArgs)]
467 struct ScopeArgs {
468 #[pyarg(any, default)]
469 globals: Option<PyObjectRef>,
470 #[pyarg(any, default)]
471 locals: Option<ArgMapping>,
472 }
473
474 impl ScopeArgs {
475 fn make_scope(
476 self,
477 vm: &VirtualMachine,
478 func_name: &'static str,
479 ) -> PyResult<crate::scope::Scope> {
480 fn validate_globals_dict(
481 globals: &PyObject,
482 vm: &VirtualMachine,
483 func_name: &'static str,
484 ) -> PyResult<()> {
485 if !globals.fast_isinstance(vm.ctx.types.dict_type) {
486 return Err(match func_name {
487 "eval" => {
488 let is_mapping = globals.mapping_unchecked().check();
489 vm.new_type_error(if is_mapping {
490 "globals must be a real dict; try eval(expr, {}, mapping)"
491 .to_owned()
492 } else {
493 "globals must be a dict".to_owned()
494 })
495 }
496 "exec" => vm.new_type_error(format!(
497 "exec() globals must be a dict, not {}",
498 globals.class().name()
499 )),
500 _ => vm.new_type_error("globals must be a dict"),
501 });
502 }
503 Ok(())
504 }
505
506 let (globals, locals) = match self.globals {
507 Some(globals) => {
508 validate_globals_dict(&globals, vm, func_name)?;
509
510 let globals = PyDictRef::try_from_object(vm, globals)?;
511 if !globals.contains_key(identifier!(vm, __builtins__), vm) {
512 let builtins_dict = vm.builtins.dict().into();
513 globals.set_item(identifier!(vm, __builtins__), builtins_dict, vm)?;
514 }
515 (
516 globals.clone(),
517 self.locals
518 .unwrap_or_else(|| ArgMapping::from_dict_exact(globals.clone())),
519 )
520 }
521 None => (
522 vm.current_globals(),
523 if let Some(locals) = self.locals {
524 locals
525 } else {
526 vm.current_locals()?
527 },
528 ),
529 };
530
531 let scope = crate::scope::Scope::with_builtins(Some(locals), globals, vm);
532 Ok(scope)
533 }
534 }
535
536 #[pyfunction]
537 fn eval(
538 source: Either<ArgStrOrBytesLike, PyRef<crate::builtins::PyCode>>,
539 scope: ScopeArgs,
540 vm: &VirtualMachine,
541 ) -> PyResult {
542 let scope = scope.make_scope(vm, "eval")?;
543
544 let code = match source {
546 Either::A(either) => {
547 let source: &[u8] = &either.borrow_bytes();
548 if source.contains(&0) {
549 return Err(vm.new_exception_msg(
550 vm.ctx.exceptions.syntax_error.to_owned(),
551 "source code string cannot contain null bytes".into(),
552 ));
553 }
554
555 let source = core::str::from_utf8(source).map_err(|err| {
556 let msg = format!(
557 "(unicode error) 'utf-8' codec can't decode byte 0x{:x?} in position {}: invalid start byte",
558 source[err.valid_up_to()],
559 err.valid_up_to()
560 );
561
562 vm.new_exception_msg(vm.ctx.exceptions.syntax_error.to_owned(), msg.into())
563 })?;
564 Ok(Either::A(vm.ctx.new_utf8_str(source.trim_start())))
565 }
566 Either::B(code) => Ok(Either::B(code)),
567 }?;
568 run_code(vm, code, scope, crate::compiler::Mode::Eval, "eval")
569 }
570
571 #[pyfunction]
572 fn exec(
573 source: Either<PyUtf8StrRef, PyRef<crate::builtins::PyCode>>,
574 scope: ScopeArgs,
575 vm: &VirtualMachine,
576 ) -> PyResult {
577 let scope = scope.make_scope(vm, "exec")?;
578 run_code(vm, source, scope, crate::compiler::Mode::Exec, "exec")
579 }
580
581 fn run_code(
582 vm: &VirtualMachine,
583 source: Either<PyUtf8StrRef, PyRef<crate::builtins::PyCode>>,
584 scope: crate::scope::Scope,
585 #[allow(unused_variables)] mode: crate::compiler::Mode,
586 func: &str,
587 ) -> PyResult {
588 let code_obj = match source {
590 #[cfg(feature = "rustpython-compiler")]
591 Either::A(string) => {
592 let source = string.as_str();
593 vm.compile(source, mode, "<string>".to_owned())
594 .map_err(|err| vm.new_syntax_error(&err, Some(source)))?
595 }
596 #[cfg(not(feature = "rustpython-compiler"))]
597 Either::A(_) => return Err(vm.new_type_error(CODEGEN_NOT_SUPPORTED.to_owned())),
598 Either::B(code_obj) => code_obj,
599 };
600
601 if !code_obj.freevars.is_empty() {
602 return Err(vm.new_type_error(format!(
603 "code object passed to {func}() may not contain free variables"
604 )));
605 }
606
607 vm.run_code_obj(code_obj, scope)
609 }
610
611 #[pyfunction]
612 fn format(
613 value: PyObjectRef,
614 format_spec: OptionalArg<PyStrRef>,
615 vm: &VirtualMachine,
616 ) -> PyResult<PyStrRef> {
617 vm.format(&value, format_spec.unwrap_or(vm.ctx.new_str("")))
618 }
619
620 #[pyfunction]
621 fn getattr(
622 obj: PyObjectRef,
623 attr: PyObjectRef,
624 default: OptionalArg<PyObjectRef>,
625 vm: &VirtualMachine,
626 ) -> PyResult {
627 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
628 vm.new_type_error(format!(
629 "attribute name must be string, not '{}'",
630 attr.class().name()
631 ))
632 })?;
633
634 if let OptionalArg::Present(default) = default {
635 Ok(vm.get_attribute_opt(obj, attr)?.unwrap_or(default))
636 } else {
637 obj.get_attr(attr, vm)
638 }
639 }
640
641 #[pyfunction]
642 fn globals(vm: &VirtualMachine) -> PyDictRef {
643 vm.current_globals()
644 }
645
646 #[pyfunction]
647 fn hasattr(obj: PyObjectRef, attr: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
648 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
649 vm.new_type_error(format!(
650 "attribute name must be string, not '{}'",
651 attr.class().name()
652 ))
653 })?;
654 Ok(vm.get_attribute_opt(obj, attr)?.is_some())
655 }
656
657 #[pyfunction]
658 fn hash(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyHash> {
659 obj.hash(vm)
660 }
661
662 #[pyfunction]
663 fn breakpoint(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
664 match vm
665 .sys_module
666 .get_attr(vm.ctx.intern_str("breakpointhook"), vm)
667 {
668 Ok(hook) => hook.as_ref().call(args, vm),
669 Err(_) => Err(vm.new_runtime_error("lost sys.breakpointhook")),
670 }
671 }
672
673 #[pyfunction]
674 fn hex(number: ArgIndex) -> String {
675 let number = number.into_int_ref();
676 let n = number.as_bigint();
677 format!("{n:#x}")
678 }
679
680 #[pyfunction]
681 fn id(obj: PyObjectRef) -> usize {
682 obj.get_id()
683 }
684
685 #[pyfunction]
686 fn input(prompt: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult {
687 use std::io::IsTerminal;
688
689 let stdin = sys::get_stdin(vm)?;
690 let stdout = sys::get_stdout(vm)?;
691 let stderr = sys::get_stderr(vm)?;
692
693 let _ = vm.call_method(&stderr, "flush", ());
694
695 let fd_matches = |obj, expected| {
696 vm.call_method(obj, "fileno", ())
697 .and_then(|o| i64::try_from_object(vm, o))
698 .is_ok_and(|fd| fd == expected)
699 };
700
701 let use_rustyline = fd_matches(&stdin, 0)
703 && fd_matches(&stdout, 1)
704 && std::io::stdin().is_terminal()
705 && !is_pty_child();
706
707 let prompt_str = match &prompt {
709 OptionalArg::Present(s) => s.to_str(),
710 OptionalArg::Missing => Some(""),
711 };
712 let use_rustyline = use_rustyline && prompt_str.is_some();
713
714 if use_rustyline {
715 let prompt = prompt_str.unwrap();
716 let mut readline = Readline::new(());
717 match readline.readline(prompt) {
718 ReadlineResult::Line(s) => Ok(vm.ctx.new_str(s).into()),
719 ReadlineResult::Eof => {
720 Err(vm.new_exception_empty(vm.ctx.exceptions.eof_error.to_owned()))
721 }
722 ReadlineResult::Interrupt => {
723 Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.to_owned()))
724 }
725 ReadlineResult::Io(e) => Err(vm.new_os_error(e.to_string())),
726 #[cfg(unix)]
727 ReadlineResult::OsError(num) => Err(vm.new_os_error(num.to_string())),
728 ReadlineResult::Other(e) => Err(vm.new_runtime_error(e.to_string())),
729 }
730 } else {
731 if let OptionalArg::Present(prompt) = prompt {
732 vm.call_method(&stdout, "write", (prompt,))?;
733 }
734 let _ = vm.call_method(&stdout, "flush", ());
735 py_io::file_readline(&stdin, None, vm)
736 }
737 }
738
739 #[cfg(unix)]
743 fn is_pty_child() -> bool {
744 use nix::unistd::{getpid, getsid};
745 getsid(None) == Ok(getpid())
747 }
748
749 #[cfg(not(unix))]
750 fn is_pty_child() -> bool {
751 false
752 }
753
754 #[pyfunction]
755 fn isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
756 obj.is_instance(&typ, vm)
757 }
758
759 #[pyfunction]
760 fn issubclass(subclass: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
761 subclass.is_subclass(&typ, vm)
762 }
763
764 #[pyfunction]
765 fn iter(
766 iter_target: PyObjectRef,
767 sentinel: OptionalArg<PyObjectRef>,
768 vm: &VirtualMachine,
769 ) -> PyResult<PyIter> {
770 if let OptionalArg::Present(sentinel) = sentinel {
771 let callable = ArgCallable::try_from_object(vm, iter_target)?;
772 let iterator = PyCallableIterator::new(callable, sentinel)
773 .into_ref(&vm.ctx)
774 .into();
775 Ok(PyIter::new(iterator))
776 } else {
777 iter_target.get_iter(vm)
778 }
779 }
780
781 #[pyfunction]
782 fn aiter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult {
783 iter_target.get_aiter(vm)
784 }
785
786 #[pyfunction]
787 fn anext(
788 aiter: PyObjectRef,
789 default_value: OptionalArg<PyObjectRef>,
790 vm: &VirtualMachine,
791 ) -> PyResult {
792 use crate::builtins::asyncgenerator::PyAnextAwaitable;
793
794 if !aiter.class().has_attr(identifier!(vm, __anext__)) {
796 return Err(vm.new_type_error(format!(
797 "'{}' object is not an async iterator",
798 aiter.class().name()
799 )));
800 }
801
802 let awaitable = vm.call_method(&aiter, "__anext__", ())?;
803
804 if let OptionalArg::Present(default) = default_value {
805 Ok(PyAnextAwaitable::new(awaitable, default)
806 .into_ref(&vm.ctx)
807 .into())
808 } else {
809 Ok(awaitable)
810 }
811 }
812
813 #[pyfunction]
814 fn len(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
815 obj.length(vm)
816 }
817
818 #[pyfunction]
819 fn locals(vm: &VirtualMachine) -> PyResult<ArgMapping> {
820 vm.current_locals()
821 }
822
823 fn min_or_max(
824 mut args: FuncArgs,
825 vm: &VirtualMachine,
826 func_name: &str,
827 op: PyComparisonOp,
828 ) -> PyResult {
829 let default = args.take_keyword("default");
830 let key_func = args.take_keyword("key");
831
832 if let Some(err) = args.check_kwargs_empty(vm) {
833 return Err(err);
834 }
835
836 let candidates = match args.args.len().cmp(&1) {
837 core::cmp::Ordering::Greater => {
838 if default.is_some() {
839 return Err(vm.new_type_error(format!(
840 "Cannot specify a default for {func_name}() with multiple positional arguments"
841 )));
842 }
843 args.args
844 }
845 core::cmp::Ordering::Equal => args.args[0].try_to_value(vm)?,
846 core::cmp::Ordering::Less => {
847 return Err(
849 vm.new_type_error(format!("{func_name} expected at least 1 argument, got 0"))
850 );
851 }
852 };
853
854 let mut candidates_iter = candidates.into_iter();
855 let mut x = match candidates_iter.next() {
856 Some(x) => x,
857 None => {
858 return default.ok_or_else(|| {
859 vm.new_value_error(format!("{func_name}() iterable argument is empty"))
860 });
861 }
862 };
863
864 let key_func = key_func.filter(|f| !vm.is_none(f));
865 if let Some(ref key_func) = key_func {
866 let mut x_key = key_func.call((x.clone(),), vm)?;
867 for y in candidates_iter {
868 let y_key = key_func.call((y.clone(),), vm)?;
869 if y_key.rich_compare_bool(&x_key, op, vm)? {
870 x = y;
871 x_key = y_key;
872 }
873 }
874 } else {
875 for y in candidates_iter {
876 if y.rich_compare_bool(&x, op, vm)? {
877 x = y;
878 }
879 }
880 }
881
882 Ok(x)
883 }
884
885 #[pyfunction]
886 fn max(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
887 min_or_max(args, vm, "max", PyComparisonOp::Gt)
888 }
889
890 #[pyfunction]
891 fn min(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
892 min_or_max(args, vm, "min", PyComparisonOp::Lt)
893 }
894
895 #[pyfunction]
896 fn next(
897 iterator: PyObjectRef,
898 default_value: OptionalArg<PyObjectRef>,
899 vm: &VirtualMachine,
900 ) -> PyResult<PyIterReturn> {
901 if !PyIter::check(&iterator) {
902 return Err(vm.new_type_error(format!(
903 "{} object is not an iterator",
904 iterator.class().name()
905 )));
906 }
907 PyIter::new(iterator)
908 .next(vm)
909 .map(|iter_ret| match iter_ret {
910 PyIterReturn::Return(obj) => PyIterReturn::Return(obj),
911 PyIterReturn::StopIteration(v) => {
912 default_value.map_or(PyIterReturn::StopIteration(v), PyIterReturn::Return)
913 }
914 })
915 }
916
917 #[pyfunction]
918 fn oct(number: ArgIndex, vm: &VirtualMachine) -> PyResult {
919 let number = number.into_int_ref();
920 let n = number.as_bigint();
921 let s = if n.is_negative() {
922 format!("-0o{:o}", n.abs())
923 } else {
924 format!("0o{n:o}")
925 };
926
927 Ok(vm.ctx.new_str(s).into())
928 }
929
930 #[pyfunction]
931 fn ord(string: Either<ArgBytesLike, PyStrRef>, vm: &VirtualMachine) -> PyResult<u32> {
932 match string {
933 Either::A(bytes) => bytes.with_ref(|bytes| {
934 let bytes_len = bytes.len();
935 if bytes_len != 1 {
936 return Err(vm.new_type_error(format!(
937 "ord() expected a character, but string of length {bytes_len} found"
938 )));
939 }
940 Ok(u32::from(bytes[0]))
941 }),
942 Either::B(string) => match string.as_wtf8().code_points().exactly_one() {
943 Ok(character) => Ok(character.to_u32()),
944 Err(_) => {
945 let string_len = string.char_len();
946 Err(vm.new_type_error(format!(
947 "ord() expected a character, but string of length {string_len} found"
948 )))
949 }
950 },
951 }
952 }
953
954 #[derive(FromArgs)]
955 struct PowArgs {
956 base: PyObjectRef,
957 exp: PyObjectRef,
958 #[pyarg(any, optional, name = "mod")]
959 modulus: Option<PyObjectRef>,
960 }
961
962 #[pyfunction]
963 fn pow(args: PowArgs, vm: &VirtualMachine) -> PyResult {
964 let PowArgs {
965 base: x,
966 exp: y,
967 modulus,
968 } = args;
969 let modulus = modulus.as_ref().map_or(vm.ctx.none.as_object(), |m| m);
970 vm._pow(&x, &y, modulus)
971 }
972
973 #[pyfunction]
974 pub fn exit(exit_code_arg: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
975 let code = exit_code_arg.unwrap_or_else(|| vm.ctx.new_int(0).into());
976 Err(vm.new_exception(vm.ctx.exceptions.system_exit.to_owned(), vec![code]))
977 }
978
979 #[derive(Debug, Default, FromArgs)]
980 pub struct PrintOptions {
981 #[pyarg(named, default)]
982 sep: Option<PyStrRef>,
983 #[pyarg(named, default)]
984 end: Option<PyStrRef>,
985 #[pyarg(named, default = ArgIntoBool::FALSE)]
986 flush: ArgIntoBool,
987 #[pyarg(named, default)]
988 file: Option<PyObjectRef>,
989 }
990
991 #[pyfunction]
992 pub fn print(objects: PosArgs, options: PrintOptions, vm: &VirtualMachine) -> PyResult<()> {
993 let file = match options.file {
994 Some(f) => f,
995 None => sys::get_stdout(vm)?,
996 };
997 let write = |obj: PyStrRef| vm.call_method(&file, "write", (obj,));
998
999 let sep = options.sep.unwrap_or_else(|| vm.ctx.new_str(" "));
1000
1001 let mut first = true;
1002 for object in objects {
1003 if first {
1004 first = false;
1005 } else {
1006 write(sep.clone())?;
1007 }
1008
1009 write(object.str(vm)?)?;
1010 }
1011
1012 let end = options.end.unwrap_or_else(|| vm.ctx.new_str("\n"));
1013 write(end)?;
1014
1015 if options.flush.into() {
1016 vm.call_method(&file, "flush", ())?;
1017 }
1018
1019 Ok(())
1020 }
1021
1022 #[pyfunction]
1023 fn repr(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
1024 obj.repr(vm)
1025 }
1026
1027 #[pyfunction]
1028 pub fn reversed(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
1029 if let Some(reversed_method) = vm.get_method(obj.clone(), identifier!(vm, __reversed__)) {
1030 reversed_method?.call((), vm)
1031 } else {
1032 vm.get_method_or_type_error(obj.clone(), identifier!(vm, __getitem__), || {
1033 "argument to reversed() must be a sequence".to_owned()
1034 })?;
1035 let len = obj.length(vm)?;
1036 let obj_iterator = PyReverseSequenceIterator::new(obj, len);
1037 Ok(obj_iterator.into_pyobject(vm))
1038 }
1039 }
1040
1041 #[derive(FromArgs)]
1042 pub struct RoundArgs {
1043 number: PyObjectRef,
1044 #[pyarg(any, optional)]
1045 ndigits: OptionalOption<PyObjectRef>,
1046 }
1047
1048 #[pyfunction]
1049 fn round(RoundArgs { number, ndigits }: RoundArgs, vm: &VirtualMachine) -> PyResult {
1050 let meth = vm
1051 .get_special_method(&number, identifier!(vm, __round__))?
1052 .ok_or_else(|| {
1053 vm.new_type_error(format!(
1054 "type {} doesn't define __round__",
1055 number.class().name()
1056 ))
1057 })?;
1058 match ndigits.flatten() {
1059 Some(obj) => {
1060 let ndigits = obj.try_index(vm)?;
1061 meth.invoke((ndigits,), vm)
1062 }
1063 None => {
1064 meth.invoke((), vm)
1066 }
1067 }
1068 }
1069
1070 #[pyfunction]
1071 fn setattr(
1072 obj: PyObjectRef,
1073 attr: PyObjectRef,
1074 value: PyObjectRef,
1075 vm: &VirtualMachine,
1076 ) -> PyResult<()> {
1077 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
1078 vm.new_type_error(format!(
1079 "attribute name must be string, not '{}'",
1080 attr.class().name()
1081 ))
1082 })?;
1083 obj.set_attr(attr, value, vm)?;
1084 Ok(())
1085 }
1086
1087 #[pyfunction]
1090 fn sorted(iterable: PyObjectRef, opts: SortOptions, vm: &VirtualMachine) -> PyResult<PyList> {
1091 let items: Vec<_> = iterable.try_to_value(vm)?;
1092 let lst = PyList::from(items);
1093 lst.sort(opts, vm)?;
1094 Ok(lst)
1095 }
1096
1097 #[derive(FromArgs)]
1098 pub struct SumArgs {
1099 #[pyarg(positional)]
1100 iterable: ArgIterable,
1101 #[pyarg(any, optional)]
1102 start: OptionalArg<PyObjectRef>,
1103 }
1104
1105 #[pyfunction]
1106 fn sum(SumArgs { iterable, start }: SumArgs, vm: &VirtualMachine) -> PyResult {
1107 let mut sum = start
1109 .into_option()
1110 .unwrap_or_else(|| vm.ctx.new_int(0).into());
1111
1112 match_class!(match sum {
1113 PyStr =>
1114 return Err(vm.new_type_error(
1115 "sum() can't sum strings [use ''.join(seq) instead]".to_owned()
1116 )),
1117 PyBytes =>
1118 return Err(vm.new_type_error(
1119 "sum() can't sum bytes [use b''.join(seq) instead]".to_owned()
1120 )),
1121 PyByteArray =>
1122 return Err(vm.new_type_error(
1123 "sum() can't sum bytearray [use b''.join(seq) instead]".to_owned()
1124 )),
1125 _ => (),
1126 });
1127
1128 for item in iterable.iter(vm)? {
1129 sum = vm._add(&sum, &*item?)?;
1130 }
1131 Ok(sum)
1132 }
1133
1134 #[derive(FromArgs)]
1135 struct ImportArgs {
1136 #[pyarg(any)]
1137 name: PyStrRef,
1138 #[pyarg(any, default)]
1139 globals: Option<PyObjectRef>,
1140 #[allow(dead_code)]
1141 #[pyarg(any, default)]
1142 locals: Option<PyObjectRef>,
1143 #[pyarg(any, default)]
1144 fromlist: Option<PyObjectRef>,
1145 #[pyarg(any, default)]
1146 level: i32,
1147 }
1148
1149 #[pyfunction]
1150 fn __import__(args: ImportArgs, vm: &VirtualMachine) -> PyResult {
1151 crate::import::import_module_level(&args.name, args.globals, args.fromlist, args.level, vm)
1152 }
1153
1154 #[pyfunction]
1155 fn vars(obj: OptionalArg, vm: &VirtualMachine) -> PyResult {
1156 if let OptionalArg::Present(obj) = obj {
1157 obj.get_attr(identifier!(vm, __dict__), vm)
1158 .map_err(|_| vm.new_type_error("vars() argument must have __dict__ attribute"))
1159 } else {
1160 Ok(vm.current_locals()?.into())
1161 }
1162 }
1163
1164 #[pyfunction]
1165 pub fn __build_class__(
1166 function: PyRef<PyFunction>,
1167 name: PyStrRef,
1168 bases: PosArgs,
1169 mut kwargs: KwArgs,
1170 vm: &VirtualMachine,
1171 ) -> PyResult {
1172 let name_obj: PyObjectRef = name.clone().into();
1173
1174 let mut new_bases: Option<Vec<PyObjectRef>> = None;
1176 let bases = PyTuple::new_ref(bases.into_vec(), &vm.ctx);
1177 for (i, base) in bases.iter().enumerate() {
1178 if base.fast_isinstance(vm.ctx.types.type_type) {
1179 if let Some(bases) = &mut new_bases {
1180 bases.push(base.clone());
1181 }
1182 continue;
1183 }
1184 let mro_entries =
1185 vm.get_attribute_opt(base.clone(), identifier!(vm, __mro_entries__))?;
1186 let entries = match mro_entries {
1187 Some(meth) => meth.call((bases.clone(),), vm)?,
1188 None => {
1189 if let Some(bases) = &mut new_bases {
1190 bases.push(base.clone());
1191 }
1192 continue;
1193 }
1194 };
1195 let entries: PyTupleRef = entries
1196 .downcast()
1197 .map_err(|_| vm.new_type_error("__mro_entries__ must return a tuple"))?;
1198 let new_bases = new_bases.get_or_insert_with(|| bases[..i].to_vec());
1199 new_bases.extend_from_slice(&entries);
1200 }
1201
1202 let new_bases = new_bases.map(|v| PyTuple::new_ref(v, &vm.ctx));
1203 let (orig_bases, bases) = match new_bases {
1204 Some(new) => (Some(bases), new),
1205 None => (None, bases),
1206 };
1207
1208 let metaclass = kwargs
1210 .pop_kwarg("metaclass")
1211 .map(|metaclass| {
1212 metaclass
1213 .downcast_exact::<PyType>(vm)
1214 .map(|m| m.into_pyref())
1215 })
1216 .unwrap_or_else(|| {
1217 Ok(if bases.is_empty() {
1219 vm.ctx.types.type_type.to_owned()
1220 } else {
1221 bases.first().unwrap().class().to_owned()
1222 })
1223 });
1224
1225 let (metaclass, meta_name) = match metaclass {
1226 Ok(mut metaclass) => {
1227 for base in bases.iter() {
1228 let base_class = base.class();
1229 if metaclass.fast_issubclass(base_class) {
1231 continue;
1232 }
1233 if base_class.fast_issubclass(&metaclass) {
1235 metaclass = base_class.to_owned();
1236 continue;
1237 }
1238 return Err(vm.new_type_error(
1240 "metaclass conflict: the metaclass of a derived class must be a (non-strict) \
1241 subclass of the metaclasses of all its bases",
1242 ));
1243 }
1244 let meta_name = metaclass.slot_name();
1245 (metaclass.to_owned().into(), meta_name.to_owned())
1246 }
1247 Err(obj) => (obj, "<metaclass>".to_owned()),
1248 };
1249
1250 let bases: PyObjectRef = bases.into();
1251
1252 let namespace = vm
1254 .get_attribute_opt(metaclass.clone(), identifier!(vm, __prepare__))?
1255 .map_or(Ok(vm.ctx.new_dict().into()), |prepare| {
1256 let args = FuncArgs::new(vec![name_obj.clone(), bases.clone()], kwargs.clone());
1257 prepare.call(args, vm)
1258 })?;
1259
1260 let namespace = ArgMapping::try_from_object(vm, namespace.clone()).map_err(|_| {
1262 vm.new_type_error(format!(
1263 "{}.__prepare__() must return a mapping, not {}",
1264 meta_name,
1265 namespace.class()
1266 ))
1267 })?;
1268
1269 if let Ok(type_params) = function
1271 .as_object()
1272 .get_attr(identifier!(vm, __type_params__), vm)
1273 && let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>()
1274 && !type_params_tuple.is_empty()
1275 {
1276 namespace
1278 .as_object()
1279 .set_item(vm.ctx.intern_str(".type_params"), type_params, vm)?;
1280 }
1281
1282 let classcell = function.invoke_with_locals(().into(), Some(namespace.clone()), vm)?;
1283 let classcell = <Option<PyCellRef>>::try_from_object(vm, classcell)?;
1284
1285 if let Some(orig_bases) = orig_bases {
1286 namespace.as_object().set_item(
1287 identifier!(vm, __orig_bases__),
1288 orig_bases.into(),
1289 vm,
1290 )?;
1291 }
1292
1293 namespace
1295 .as_object()
1296 .del_item(vm.ctx.intern_str(".type_params"), vm)
1297 .ok();
1298
1299 let args = FuncArgs::new(vec![name_obj, bases, namespace.into()], kwargs);
1300 let class = metaclass.call(args, vm)?;
1301
1302 if let Ok(type_params) = function
1304 .as_object()
1305 .get_attr(identifier!(vm, __type_params__), vm)
1306 && let Some(type_params_tuple) = type_params.downcast_ref::<PyTuple>()
1307 && !type_params_tuple.is_empty()
1308 {
1309 class.set_attr(identifier!(vm, __type_params__), type_params.clone(), vm)?;
1310 class.set_attr(identifier!(vm, __parameters__), type_params, vm)?;
1312 }
1313
1314 if let Some(ref classcell) = classcell
1316 && class.fast_isinstance(vm.ctx.types.type_type)
1317 {
1318 let cell_value = classcell.get().ok_or_else(|| {
1319 vm.new_runtime_error(format!(
1320 "__class__ not set defining {:?} as {:?}. Was __classcell__ propagated to type.__new__?",
1321 name, class
1322 ))
1323 })?;
1324
1325 if !cell_value.is(&class) {
1326 return Err(vm.new_type_error(format!(
1327 "__class__ set to {:?} defining {:?} as {:?}",
1328 cell_value, name, class
1329 )));
1330 }
1331 }
1332
1333 Ok(class)
1334 }
1335}
1336
1337pub fn init_module(vm: &VirtualMachine, module: &Py<PyModule>) {
1338 let ctx = &vm.ctx;
1339
1340 crate::protocol::VecBuffer::make_static_type();
1341
1342 module.__init_methods(vm).unwrap();
1343 builtins::module_exec(vm, module).unwrap();
1344
1345 let debug_mode: bool = vm.state.config.settings.optimize == 0;
1346 let exception_group = crate::exception_group::exception_group();
1348
1349 extend_module!(vm, module, {
1350 "__debug__" => ctx.new_bool(debug_mode),
1351
1352 "bool" => ctx.types.bool_type.to_owned(),
1353 "bytearray" => ctx.types.bytearray_type.to_owned(),
1354 "bytes" => ctx.types.bytes_type.to_owned(),
1355 "classmethod" => ctx.types.classmethod_type.to_owned(),
1356 "complex" => ctx.types.complex_type.to_owned(),
1357 "dict" => ctx.types.dict_type.to_owned(),
1358 "enumerate" => ctx.types.enumerate_type.to_owned(),
1359 "float" => ctx.types.float_type.to_owned(),
1360 "frozenset" => ctx.types.frozenset_type.to_owned(),
1361 "filter" => ctx.types.filter_type.to_owned(),
1362 "int" => ctx.types.int_type.to_owned(),
1363 "list" => ctx.types.list_type.to_owned(),
1364 "map" => ctx.types.map_type.to_owned(),
1365 "memoryview" => ctx.types.memoryview_type.to_owned(),
1366 "object" => ctx.types.object_type.to_owned(),
1367 "property" => ctx.types.property_type.to_owned(),
1368 "range" => ctx.types.range_type.to_owned(),
1369 "set" => ctx.types.set_type.to_owned(),
1370 "slice" => ctx.types.slice_type.to_owned(),
1371 "staticmethod" => ctx.types.staticmethod_type.to_owned(),
1372 "str" => ctx.types.str_type.to_owned(),
1373 "super" => ctx.types.super_type.to_owned(),
1374 "tuple" => ctx.types.tuple_type.to_owned(),
1375 "type" => ctx.types.type_type.to_owned(),
1376 "zip" => ctx.types.zip_type.to_owned(),
1377
1378 "None" => ctx.none(),
1380 "True" => ctx.new_bool(true),
1381 "False" => ctx.new_bool(false),
1382 "NotImplemented" => ctx.not_implemented(),
1383 "Ellipsis" => vm.ctx.ellipsis.clone(),
1384
1385 "BaseException" => ctx.exceptions.base_exception_type.to_owned(),
1388 "BaseExceptionGroup" => ctx.exceptions.base_exception_group.to_owned(),
1389 "ExceptionGroup" => exception_group.to_owned(),
1390 "SystemExit" => ctx.exceptions.system_exit.to_owned(),
1391 "KeyboardInterrupt" => ctx.exceptions.keyboard_interrupt.to_owned(),
1392 "GeneratorExit" => ctx.exceptions.generator_exit.to_owned(),
1393 "Exception" => ctx.exceptions.exception_type.to_owned(),
1394 "StopIteration" => ctx.exceptions.stop_iteration.to_owned(),
1395 "StopAsyncIteration" => ctx.exceptions.stop_async_iteration.to_owned(),
1396 "ArithmeticError" => ctx.exceptions.arithmetic_error.to_owned(),
1397 "FloatingPointError" => ctx.exceptions.floating_point_error.to_owned(),
1398 "OverflowError" => ctx.exceptions.overflow_error.to_owned(),
1399 "ZeroDivisionError" => ctx.exceptions.zero_division_error.to_owned(),
1400 "AssertionError" => ctx.exceptions.assertion_error.to_owned(),
1401 "AttributeError" => ctx.exceptions.attribute_error.to_owned(),
1402 "BufferError" => ctx.exceptions.buffer_error.to_owned(),
1403 "EOFError" => ctx.exceptions.eof_error.to_owned(),
1404 "ImportError" => ctx.exceptions.import_error.to_owned(),
1405 "ModuleNotFoundError" => ctx.exceptions.module_not_found_error.to_owned(),
1406 "LookupError" => ctx.exceptions.lookup_error.to_owned(),
1407 "IndexError" => ctx.exceptions.index_error.to_owned(),
1408 "KeyError" => ctx.exceptions.key_error.to_owned(),
1409 "MemoryError" => ctx.exceptions.memory_error.to_owned(),
1410 "NameError" => ctx.exceptions.name_error.to_owned(),
1411 "UnboundLocalError" => ctx.exceptions.unbound_local_error.to_owned(),
1412 "OSError" => ctx.exceptions.os_error.to_owned(),
1413 "IOError" => ctx.exceptions.os_error.to_owned(),
1415 "EnvironmentError" => ctx.exceptions.os_error.to_owned(),
1416 "BlockingIOError" => ctx.exceptions.blocking_io_error.to_owned(),
1417 "ChildProcessError" => ctx.exceptions.child_process_error.to_owned(),
1418 "ConnectionError" => ctx.exceptions.connection_error.to_owned(),
1419 "BrokenPipeError" => ctx.exceptions.broken_pipe_error.to_owned(),
1420 "ConnectionAbortedError" => ctx.exceptions.connection_aborted_error.to_owned(),
1421 "ConnectionRefusedError" => ctx.exceptions.connection_refused_error.to_owned(),
1422 "ConnectionResetError" => ctx.exceptions.connection_reset_error.to_owned(),
1423 "FileExistsError" => ctx.exceptions.file_exists_error.to_owned(),
1424 "FileNotFoundError" => ctx.exceptions.file_not_found_error.to_owned(),
1425 "InterruptedError" => ctx.exceptions.interrupted_error.to_owned(),
1426 "IsADirectoryError" => ctx.exceptions.is_a_directory_error.to_owned(),
1427 "NotADirectoryError" => ctx.exceptions.not_a_directory_error.to_owned(),
1428 "PermissionError" => ctx.exceptions.permission_error.to_owned(),
1429 "ProcessLookupError" => ctx.exceptions.process_lookup_error.to_owned(),
1430 "TimeoutError" => ctx.exceptions.timeout_error.to_owned(),
1431 "ReferenceError" => ctx.exceptions.reference_error.to_owned(),
1432 "RuntimeError" => ctx.exceptions.runtime_error.to_owned(),
1433 "NotImplementedError" => ctx.exceptions.not_implemented_error.to_owned(),
1434 "RecursionError" => ctx.exceptions.recursion_error.to_owned(),
1435 "SyntaxError" => ctx.exceptions.syntax_error.to_owned(),
1436 "_IncompleteInputError" => ctx.exceptions.incomplete_input_error.to_owned(),
1437 "IndentationError" => ctx.exceptions.indentation_error.to_owned(),
1438 "TabError" => ctx.exceptions.tab_error.to_owned(),
1439 "SystemError" => ctx.exceptions.system_error.to_owned(),
1440 "TypeError" => ctx.exceptions.type_error.to_owned(),
1441 "ValueError" => ctx.exceptions.value_error.to_owned(),
1442 "UnicodeError" => ctx.exceptions.unicode_error.to_owned(),
1443 "UnicodeDecodeError" => ctx.exceptions.unicode_decode_error.to_owned(),
1444 "UnicodeEncodeError" => ctx.exceptions.unicode_encode_error.to_owned(),
1445 "UnicodeTranslateError" => ctx.exceptions.unicode_translate_error.to_owned(),
1446
1447 "Warning" => ctx.exceptions.warning.to_owned(),
1449 "DeprecationWarning" => ctx.exceptions.deprecation_warning.to_owned(),
1450 "PendingDeprecationWarning" => ctx.exceptions.pending_deprecation_warning.to_owned(),
1451 "RuntimeWarning" => ctx.exceptions.runtime_warning.to_owned(),
1452 "SyntaxWarning" => ctx.exceptions.syntax_warning.to_owned(),
1453 "UserWarning" => ctx.exceptions.user_warning.to_owned(),
1454 "FutureWarning" => ctx.exceptions.future_warning.to_owned(),
1455 "ImportWarning" => ctx.exceptions.import_warning.to_owned(),
1456 "UnicodeWarning" => ctx.exceptions.unicode_warning.to_owned(),
1457 "BytesWarning" => ctx.exceptions.bytes_warning.to_owned(),
1458 "ResourceWarning" => ctx.exceptions.resource_warning.to_owned(),
1459 "EncodingWarning" => ctx.exceptions.encoding_warning.to_owned(),
1460 });
1461
1462 #[cfg(feature = "jit")]
1463 extend_module!(vm, module, {
1464 "JitError" => ctx.exceptions.jit_error.to_owned(),
1465 });
1466
1467 #[cfg(windows)]
1468 extend_module!(vm, module, {
1469 "WindowsError" => ctx.exceptions.os_error.to_owned(),
1471 });
1472}