1use crate::{builtins::PyModule, class::PyClassImpl, Py, VirtualMachine};
5pub(crate) use builtins::{__module_def, DOC};
6pub use builtins::{ascii, print, reversed};
7
8#[pymodule]
9mod builtins {
10 use crate::{
11 builtins::{
12 enumerate::PyReverseSequenceIterator,
13 function::{PyCellRef, PyFunction},
14 int::PyIntRef,
15 iter::PyCallableIterator,
16 list::{PyList, SortOptions},
17 PyByteArray, PyBytes, PyDictRef, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType,
18 },
19 common::{hash::PyHash, str::to_ascii},
20 function::{
21 ArgBytesLike, ArgCallable, ArgIndex, ArgIntoBool, ArgIterable, ArgMapping,
22 ArgStrOrBytesLike, Either, FsPath, FuncArgs, KwArgs, OptionalArg, OptionalOption,
23 PosArgs,
24 },
25 protocol::{PyIter, PyIterReturn},
26 py_io,
27 readline::{Readline, ReadlineResult},
28 stdlib::sys,
29 types::PyComparisonOp,
30 AsObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
31 };
32 use num_traits::{Signed, ToPrimitive};
33
34 #[cfg(not(feature = "rustpython-compiler"))]
35 const CODEGEN_NOT_SUPPORTED: &str =
36 "can't compile() to bytecode when the `codegen` feature of rustpython is disabled";
37
38 #[pyfunction]
39 fn abs(x: PyObjectRef, vm: &VirtualMachine) -> PyResult {
40 vm._abs(&x)
41 }
42
43 #[pyfunction]
44 fn all(iterable: ArgIterable<ArgIntoBool>, vm: &VirtualMachine) -> PyResult<bool> {
45 for item in iterable.iter(vm)? {
46 if !*item? {
47 return Ok(false);
48 }
49 }
50 Ok(true)
51 }
52
53 #[pyfunction]
54 fn any(iterable: ArgIterable<ArgIntoBool>, vm: &VirtualMachine) -> PyResult<bool> {
55 for item in iterable.iter(vm)? {
56 if *item? {
57 return Ok(true);
58 }
59 }
60 Ok(false)
61 }
62
63 #[pyfunction]
64 pub fn ascii(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<ascii::AsciiString> {
65 let repr = obj.repr(vm)?;
66 let ascii = to_ascii(repr.as_str());
67 Ok(ascii)
68 }
69
70 #[pyfunction]
71 fn bin(x: PyIntRef) -> String {
72 let x = x.as_bigint();
73 if x.is_negative() {
74 format!("-0b{:b}", x.abs())
75 } else {
76 format!("0b{x:b}")
77 }
78 }
79
80 #[pyfunction]
81 fn callable(obj: PyObjectRef) -> bool {
82 obj.is_callable()
83 }
84
85 #[pyfunction]
86 fn chr(i: PyIntRef, vm: &VirtualMachine) -> PyResult<String> {
87 let value = i
88 .try_to_primitive::<isize>(vm)?
89 .to_u32()
90 .and_then(char::from_u32)
91 .ok_or_else(|| vm.new_value_error("chr() arg not in range(0x110000)".to_owned()))?;
92 Ok(value.to_string())
93 }
94
95 #[derive(FromArgs)]
96 #[allow(dead_code)]
97 struct CompileArgs {
98 source: PyObjectRef,
99 filename: FsPath,
100 mode: PyStrRef,
101 #[pyarg(any, optional)]
102 flags: OptionalArg<PyIntRef>,
103 #[pyarg(any, optional)]
104 dont_inherit: OptionalArg<bool>,
105 #[pyarg(any, optional)]
106 optimize: OptionalArg<PyIntRef>,
107 #[pyarg(any, optional)]
108 _feature_version: OptionalArg<i32>,
109 }
110
111 #[cfg(any(feature = "rustpython-parser", feature = "rustpython-codegen"))]
112 #[pyfunction]
113 fn compile(args: CompileArgs, vm: &VirtualMachine) -> PyResult {
114 #[cfg(feature = "rustpython-ast")]
115 {
116 use crate::{class::PyClassImpl, stdlib::ast};
117
118 if args._feature_version.is_present() {
119 }
121
122 let mode_str = args.mode.as_str();
123
124 let optimize: i32 = args.optimize.map_or(Ok(-1), |v| v.try_to_primitive(vm))?;
125 let optimize: u8 = if optimize == -1 {
126 vm.state.settings.optimize
127 } else {
128 optimize.try_into().map_err(|_| {
129 vm.new_value_error("compile() optimize value invalid".to_owned())
130 })?
131 };
132
133 if args
134 .source
135 .fast_isinstance(&ast::NodeAst::make_class(&vm.ctx))
136 {
137 #[cfg(not(feature = "rustpython-codegen"))]
138 {
139 return Err(vm.new_type_error(CODEGEN_NOT_SUPPORTED.to_owned()));
140 }
141 #[cfg(feature = "rustpython-codegen")]
142 {
143 let mode = mode_str
144 .parse::<crate::compiler::Mode>()
145 .map_err(|err| vm.new_value_error(err.to_string()))?;
146 return ast::compile(
147 vm,
148 args.source,
149 args.filename.as_str(),
150 mode,
151 Some(optimize),
152 );
153 }
154 }
155
156 #[cfg(not(feature = "rustpython-parser"))]
157 {
158 const PARSER_NOT_SUPPORTED: &str =
159 "can't compile() source code when the `parser` feature of rustpython is disabled";
160 Err(vm.new_type_error(PARSER_NOT_SUPPORTED.to_owned()))
161 }
162 #[cfg(feature = "rustpython-parser")]
163 {
164 use crate::convert::ToPyException;
165 use num_traits::Zero;
166 use rustpython_parser as parser;
167
168 let source = ArgStrOrBytesLike::try_from_object(vm, args.source)?;
169 let source = source.borrow_bytes();
170
171 let source = std::str::from_utf8(&source)
173 .map_err(|e| vm.new_unicode_decode_error(e.to_string()))?;
174
175 let flags = args.flags.map_or(Ok(0), |v| v.try_to_primitive(vm))?;
176
177 if !(flags & !ast::PY_COMPILE_FLAGS_MASK).is_zero() {
178 return Err(vm.new_value_error("compile() unrecognized flags".to_owned()));
179 }
180
181 if (flags & ast::PY_COMPILE_FLAG_AST_ONLY).is_zero() {
182 #[cfg(not(feature = "rustpython-compiler"))]
183 {
184 Err(vm.new_value_error(CODEGEN_NOT_SUPPORTED.to_owned()))
185 }
186 #[cfg(feature = "rustpython-compiler")]
187 {
188 let mode = mode_str
189 .parse::<crate::compiler::Mode>()
190 .map_err(|err| vm.new_value_error(err.to_string()))?;
191
192 let mut opts = vm.compile_opts();
193 opts.optimize = optimize;
194
195 let code = vm
196 .compile_with_opts(
197 source,
198 mode,
199 args.filename.as_str().to_owned(),
200 opts,
201 )
202 .map_err(|err| (err, Some(source)).to_pyexception(vm))?;
203 Ok(code.into())
204 }
205 } else {
206 let mode = mode_str
207 .parse::<parser::Mode>()
208 .map_err(|err| vm.new_value_error(err.to_string()))?;
209 ast::parse(vm, source, mode).map_err(|e| (e, Some(source)).to_pyexception(vm))
210 }
211 }
212 }
213 }
214
215 #[pyfunction]
216 fn delattr(obj: PyObjectRef, attr: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
217 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
218 vm.new_type_error(format!(
219 "attribute name must be string, not '{}'",
220 attr.class().name()
221 ))
222 })?;
223 obj.del_attr(attr, vm)
224 }
225
226 #[pyfunction]
227 fn dir(obj: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult<PyList> {
228 vm.dir(obj.into_option())
229 }
230
231 #[pyfunction]
232 fn divmod(a: PyObjectRef, b: PyObjectRef, vm: &VirtualMachine) -> PyResult {
233 vm._divmod(&a, &b)
234 }
235
236 #[derive(FromArgs)]
237 struct ScopeArgs {
238 #[pyarg(any, default)]
239 globals: Option<PyDictRef>,
240 #[pyarg(any, default)]
241 locals: Option<ArgMapping>,
242 }
243
244 impl ScopeArgs {
245 fn make_scope(self, vm: &VirtualMachine) -> PyResult<crate::scope::Scope> {
246 let (globals, locals) = match self.globals {
247 Some(globals) => {
248 if !globals.contains_key(identifier!(vm, __builtins__), vm) {
249 let builtins_dict = vm.builtins.dict().into();
250 globals.set_item(identifier!(vm, __builtins__), builtins_dict, vm)?;
251 }
252 (
253 globals.clone(),
254 self.locals.unwrap_or_else(|| {
255 ArgMapping::try_from_object(vm, globals.into()).unwrap()
256 }),
257 )
258 }
259 None => (
260 vm.current_globals().clone(),
261 if let Some(locals) = self.locals {
262 locals
263 } else {
264 vm.current_locals()?
265 },
266 ),
267 };
268
269 let scope = crate::scope::Scope::with_builtins(Some(locals), globals, vm);
270 Ok(scope)
271 }
272 }
273
274 #[pyfunction]
275 fn eval(
276 source: Either<ArgStrOrBytesLike, PyRef<crate::builtins::PyCode>>,
277 scope: ScopeArgs,
278 vm: &VirtualMachine,
279 ) -> PyResult {
280 let code = match source {
282 Either::A(either) => {
283 let source: &[u8] = &either.borrow_bytes();
284 if source.contains(&0) {
285 return Err(vm.new_exception_msg(
286 vm.ctx.exceptions.syntax_error.to_owned(),
287 "source code string cannot contain null bytes".to_owned(),
288 ));
289 }
290
291 let source = std::str::from_utf8(source).map_err(|err| {
292 let msg = format!(
293 "(unicode error) 'utf-8' codec can't decode byte 0x{:x?} in position {}: invalid start byte",
294 source[err.valid_up_to()],
295 err.valid_up_to()
296 );
297
298 vm.new_exception_msg(vm.ctx.exceptions.syntax_error.to_owned(), msg)
299 })?;
300 Ok(Either::A(vm.ctx.new_str(source.trim_start())))
301 }
302 Either::B(code) => Ok(Either::B(code)),
303 }?;
304 run_code(vm, code, scope, crate::compiler::Mode::Eval, "eval")
305 }
306
307 #[pyfunction]
308 fn exec(
309 source: Either<PyStrRef, PyRef<crate::builtins::PyCode>>,
310 scope: ScopeArgs,
311 vm: &VirtualMachine,
312 ) -> PyResult {
313 run_code(vm, source, scope, crate::compiler::Mode::Exec, "exec")
314 }
315
316 fn run_code(
317 vm: &VirtualMachine,
318 source: Either<PyStrRef, PyRef<crate::builtins::PyCode>>,
319 scope: ScopeArgs,
320 #[allow(unused_variables)] mode: crate::compiler::Mode,
321 func: &str,
322 ) -> PyResult {
323 let scope = scope.make_scope(vm)?;
324
325 let code_obj = match source {
327 #[cfg(feature = "rustpython-compiler")]
328 Either::A(string) => vm
329 .compile(string.as_str(), mode, "<string>".to_owned())
330 .map_err(|err| vm.new_syntax_error(&err, Some(string.as_str())))?,
331 #[cfg(not(feature = "rustpython-compiler"))]
332 Either::A(_) => return Err(vm.new_type_error(CODEGEN_NOT_SUPPORTED.to_owned())),
333 Either::B(code_obj) => code_obj,
334 };
335
336 if !code_obj.freevars.is_empty() {
337 return Err(vm.new_type_error(format!(
338 "code object passed to {func}() may not contain free variables"
339 )));
340 }
341
342 vm.run_code_obj(code_obj, scope)
344 }
345
346 #[pyfunction]
347 fn format(
348 value: PyObjectRef,
349 format_spec: OptionalArg<PyStrRef>,
350 vm: &VirtualMachine,
351 ) -> PyResult<PyStrRef> {
352 vm.format(&value, format_spec.unwrap_or(vm.ctx.new_str("")))
353 }
354
355 #[pyfunction]
356 fn getattr(
357 obj: PyObjectRef,
358 attr: PyObjectRef,
359 default: OptionalArg<PyObjectRef>,
360 vm: &VirtualMachine,
361 ) -> PyResult {
362 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
363 vm.new_type_error(format!(
364 "attribute name must be string, not '{}'",
365 attr.class().name()
366 ))
367 })?;
368
369 if let OptionalArg::Present(default) = default {
370 Ok(vm.get_attribute_opt(obj, attr)?.unwrap_or(default))
371 } else {
372 obj.get_attr(attr, vm)
373 }
374 }
375
376 #[pyfunction]
377 fn globals(vm: &VirtualMachine) -> PyDictRef {
378 vm.current_globals().clone()
379 }
380
381 #[pyfunction]
382 fn hasattr(obj: PyObjectRef, attr: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
383 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
384 vm.new_type_error(format!(
385 "attribute name must be string, not '{}'",
386 attr.class().name()
387 ))
388 })?;
389 Ok(vm.get_attribute_opt(obj, attr)?.is_some())
390 }
391
392 #[pyfunction]
393 fn hash(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyHash> {
394 obj.hash(vm)
395 }
396
397 #[pyfunction]
398 fn breakpoint(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
399 match vm
400 .sys_module
401 .get_attr(vm.ctx.intern_str("breakpointhook"), vm)
402 {
403 Ok(hook) => hook.as_ref().call(args, vm),
404 Err(_) => Err(vm.new_runtime_error("lost sys.breakpointhook".to_owned())),
405 }
406 }
407
408 #[pyfunction]
409 fn hex(number: ArgIndex) -> String {
410 let n = number.as_bigint();
411 format!("{n:#x}")
412 }
413
414 #[pyfunction]
415 fn id(obj: PyObjectRef) -> usize {
416 obj.get_id()
417 }
418
419 #[pyfunction]
420 fn input(prompt: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult {
421 let stdin = sys::get_stdin(vm)?;
422 let stdout = sys::get_stdout(vm)?;
423 let stderr = sys::get_stderr(vm)?;
424
425 let _ = vm.call_method(&stderr, "flush", ());
426
427 let fd_matches = |obj, expected| {
428 vm.call_method(obj, "fileno", ())
429 .and_then(|o| i64::try_from_object(vm, o))
430 .ok()
431 .map_or(false, |fd| fd == expected)
432 };
433
434 if fd_matches(&stdin, 0) && fd_matches(&stdout, 1) && atty::is(atty::Stream::Stdin) {
436 let prompt = prompt.as_ref().map_or("", |s| s.as_str());
437 let mut readline = Readline::new(());
438 match readline.readline(prompt) {
439 ReadlineResult::Line(s) => Ok(vm.ctx.new_str(s).into()),
440 ReadlineResult::Eof => {
441 Err(vm.new_exception_empty(vm.ctx.exceptions.eof_error.to_owned()))
442 }
443 ReadlineResult::Interrupt => {
444 Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.to_owned()))
445 }
446 ReadlineResult::Io(e) => Err(vm.new_os_error(e.to_string())),
447 ReadlineResult::Other(e) => Err(vm.new_runtime_error(e.to_string())),
448 }
449 } else {
450 if let OptionalArg::Present(prompt) = prompt {
451 vm.call_method(&stdout, "write", (prompt,))?;
452 }
453 let _ = vm.call_method(&stdout, "flush", ());
454 py_io::file_readline(&stdin, None, vm)
455 }
456 }
457
458 #[pyfunction]
459 fn isinstance(obj: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
460 obj.is_instance(&typ, vm)
461 }
462
463 #[pyfunction]
464 fn issubclass(subclass: PyObjectRef, typ: PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
465 subclass.is_subclass(&typ, vm)
466 }
467
468 #[pyfunction]
469 fn iter(
470 iter_target: PyObjectRef,
471 sentinel: OptionalArg<PyObjectRef>,
472 vm: &VirtualMachine,
473 ) -> PyResult<PyIter> {
474 if let OptionalArg::Present(sentinel) = sentinel {
475 let callable = ArgCallable::try_from_object(vm, iter_target)?;
476 let iterator = PyCallableIterator::new(callable, sentinel)
477 .into_ref(&vm.ctx)
478 .into();
479 Ok(PyIter::new(iterator))
480 } else {
481 iter_target.get_iter(vm)
482 }
483 }
484
485 #[pyfunction]
486 fn aiter(iter_target: PyObjectRef, vm: &VirtualMachine) -> PyResult {
487 iter_target.get_aiter(vm)
488 }
489
490 #[pyfunction]
491 fn len(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
492 obj.length(vm)
493 }
494
495 #[pyfunction]
496 fn locals(vm: &VirtualMachine) -> PyResult<ArgMapping> {
497 vm.current_locals()
498 }
499
500 fn min_or_max(
501 mut args: FuncArgs,
502 vm: &VirtualMachine,
503 func_name: &str,
504 op: PyComparisonOp,
505 ) -> PyResult {
506 let default = args.take_keyword("default");
507 let key_func = args.take_keyword("key");
508
509 if let Some(err) = args.check_kwargs_empty(vm) {
510 return Err(err);
511 }
512
513 let candidates = match args.args.len().cmp(&1) {
514 std::cmp::Ordering::Greater => {
515 if default.is_some() {
516 return Err(vm.new_type_error(format!(
517 "Cannot specify a default for {func_name}() with multiple positional arguments"
518 )));
519 }
520 args.args
521 }
522 std::cmp::Ordering::Equal => args.args[0].try_to_value(vm)?,
523 std::cmp::Ordering::Less => {
524 return Err(
526 vm.new_type_error(format!("{func_name} expected at least 1 argument, got 0"))
527 );
528 }
529 };
530
531 let mut candidates_iter = candidates.into_iter();
532 let mut x = match candidates_iter.next() {
533 Some(x) => x,
534 None => {
535 return default.ok_or_else(|| {
536 vm.new_value_error(format!("{func_name}() arg is an empty sequence"))
537 })
538 }
539 };
540
541 let key_func = key_func.filter(|f| !vm.is_none(f));
542 if let Some(ref key_func) = key_func {
543 let mut x_key = key_func.call((x.clone(),), vm)?;
544 for y in candidates_iter {
545 let y_key = key_func.call((y.clone(),), vm)?;
546 if y_key.rich_compare_bool(&x_key, op, vm)? {
547 x = y;
548 x_key = y_key;
549 }
550 }
551 } else {
552 for y in candidates_iter {
553 if y.rich_compare_bool(&x, op, vm)? {
554 x = y;
555 }
556 }
557 }
558
559 Ok(x)
560 }
561
562 #[pyfunction]
563 fn max(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
564 min_or_max(args, vm, "max", PyComparisonOp::Gt)
565 }
566
567 #[pyfunction]
568 fn min(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
569 min_or_max(args, vm, "min", PyComparisonOp::Lt)
570 }
571
572 #[pyfunction]
573 fn next(
574 iterator: PyObjectRef,
575 default_value: OptionalArg<PyObjectRef>,
576 vm: &VirtualMachine,
577 ) -> PyResult<PyIterReturn> {
578 if !PyIter::check(&iterator) {
579 return Err(vm.new_type_error(format!(
580 "{} object is not an iterator",
581 iterator.class().name()
582 )));
583 }
584 PyIter::new(iterator).next(vm).map(|iret| match iret {
585 PyIterReturn::Return(obj) => PyIterReturn::Return(obj),
586 PyIterReturn::StopIteration(v) => {
587 default_value.map_or(PyIterReturn::StopIteration(v), PyIterReturn::Return)
588 }
589 })
590 }
591
592 #[pyfunction]
593 fn oct(number: ArgIndex, vm: &VirtualMachine) -> PyResult {
594 let n = number.as_bigint();
595 let s = if n.is_negative() {
596 format!("-0o{:o}", n.abs())
597 } else {
598 format!("0o{n:o}")
599 };
600
601 Ok(vm.ctx.new_str(s).into())
602 }
603
604 #[pyfunction]
605 fn ord(string: Either<ArgBytesLike, PyStrRef>, vm: &VirtualMachine) -> PyResult<u32> {
606 match string {
607 Either::A(bytes) => bytes.with_ref(|bytes| {
608 let bytes_len = bytes.len();
609 if bytes_len != 1 {
610 return Err(vm.new_type_error(format!(
611 "ord() expected a character, but string of length {bytes_len} found"
612 )));
613 }
614 Ok(u32::from(bytes[0]))
615 }),
616 Either::B(string) => {
617 let string = string.as_str();
618 let string_len = string.chars().count();
619 if string_len != 1 {
620 return Err(vm.new_type_error(format!(
621 "ord() expected a character, but string of length {string_len} found"
622 )));
623 }
624 match string.chars().next() {
625 Some(character) => Ok(character as u32),
626 None => Err(vm.new_type_error(
627 "ord() could not guess the integer representing this character".to_owned(),
628 )),
629 }
630 }
631 }
632 }
633
634 #[derive(FromArgs)]
635 struct PowArgs {
636 base: PyObjectRef,
637 exp: PyObjectRef,
638 #[pyarg(any, optional, name = "mod")]
639 modulus: Option<PyObjectRef>,
640 }
641
642 #[pyfunction]
643 fn pow(args: PowArgs, vm: &VirtualMachine) -> PyResult {
644 let PowArgs {
645 base: x,
646 exp: y,
647 modulus,
648 } = args;
649 let modulus = modulus.as_ref().map_or(vm.ctx.none.as_object(), |m| m);
650 vm._pow(&x, &y, modulus)
651 }
652
653 #[pyfunction]
654 pub fn exit(exit_code_arg: OptionalArg<PyObjectRef>, vm: &VirtualMachine) -> PyResult {
655 let code = exit_code_arg.unwrap_or_else(|| vm.ctx.new_int(0).into());
656 Err(vm.new_exception(vm.ctx.exceptions.system_exit.to_owned(), vec![code]))
657 }
658
659 #[derive(Debug, Default, FromArgs)]
660 pub struct PrintOptions {
661 #[pyarg(named, default)]
662 sep: Option<PyStrRef>,
663 #[pyarg(named, default)]
664 end: Option<PyStrRef>,
665 #[pyarg(named, default = "ArgIntoBool::FALSE")]
666 flush: ArgIntoBool,
667 #[pyarg(named, default)]
668 file: Option<PyObjectRef>,
669 }
670
671 #[pyfunction]
672 pub fn print(objects: PosArgs, options: PrintOptions, vm: &VirtualMachine) -> PyResult<()> {
673 let file = match options.file {
674 Some(f) => f,
675 None => sys::get_stdout(vm)?,
676 };
677 let write = |obj: PyStrRef| vm.call_method(&file, "write", (obj,));
678
679 let sep = options
680 .sep
681 .unwrap_or_else(|| PyStr::from(" ").into_ref(&vm.ctx));
682
683 let mut first = true;
684 for object in objects {
685 if first {
686 first = false;
687 } else {
688 write(sep.clone())?;
689 }
690
691 write(object.str(vm)?)?;
692 }
693
694 let end = options
695 .end
696 .unwrap_or_else(|| PyStr::from("\n").into_ref(&vm.ctx));
697 write(end)?;
698
699 if *options.flush {
700 vm.call_method(&file, "flush", ())?;
701 }
702
703 Ok(())
704 }
705
706 #[pyfunction]
707 fn repr(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
708 obj.repr(vm)
709 }
710
711 #[pyfunction]
712 pub fn reversed(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
713 if let Some(reversed_method) = vm.get_method(obj.clone(), identifier!(vm, __reversed__)) {
714 reversed_method?.call((), vm)
715 } else {
716 vm.get_method_or_type_error(obj.clone(), identifier!(vm, __getitem__), || {
717 "argument to reversed() must be a sequence".to_owned()
718 })?;
719 let len = obj.length(vm)?;
720 let obj_iterator = PyReverseSequenceIterator::new(obj, len);
721 Ok(obj_iterator.into_pyobject(vm))
722 }
723 }
724
725 #[derive(FromArgs)]
726 pub struct RoundArgs {
727 number: PyObjectRef,
728 #[pyarg(any, optional)]
729 ndigits: OptionalOption<PyObjectRef>,
730 }
731
732 #[pyfunction]
733 fn round(RoundArgs { number, ndigits }: RoundArgs, vm: &VirtualMachine) -> PyResult {
734 let meth = vm
735 .get_special_method(&number, identifier!(vm, __round__))?
736 .ok_or_else(|| {
737 vm.new_type_error(format!(
738 "type {} doesn't define __round__",
739 number.class().name()
740 ))
741 })?;
742 match ndigits.flatten() {
743 Some(obj) => {
744 let ndigits = obj.try_index(vm)?;
745 meth.invoke((ndigits,), vm)
746 }
747 None => {
748 meth.invoke((), vm)
750 }
751 }
752 }
753
754 #[pyfunction]
755 fn setattr(
756 obj: PyObjectRef,
757 attr: PyObjectRef,
758 value: PyObjectRef,
759 vm: &VirtualMachine,
760 ) -> PyResult<()> {
761 let attr = attr.try_to_ref::<PyStr>(vm).map_err(|_e| {
762 vm.new_type_error(format!(
763 "attribute name must be string, not '{}'",
764 attr.class().name()
765 ))
766 })?;
767 obj.set_attr(attr, value, vm)?;
768 Ok(())
769 }
770
771 #[pyfunction]
774 fn sorted(iterable: PyObjectRef, opts: SortOptions, vm: &VirtualMachine) -> PyResult<PyList> {
775 let items: Vec<_> = iterable.try_to_value(vm)?;
776 let lst = PyList::from(items);
777 lst.sort(opts, vm)?;
778 Ok(lst)
779 }
780
781 #[derive(FromArgs)]
782 pub struct SumArgs {
783 #[pyarg(positional)]
784 iterable: ArgIterable,
785 #[pyarg(any, optional)]
786 start: OptionalArg<PyObjectRef>,
787 }
788
789 #[pyfunction]
790 fn sum(SumArgs { iterable, start }: SumArgs, vm: &VirtualMachine) -> PyResult {
791 let mut sum = start
793 .into_option()
794 .unwrap_or_else(|| vm.ctx.new_int(0).into());
795
796 match_class!(match sum {
797 PyStr =>
798 return Err(vm.new_type_error(
799 "sum() can't sum strings [use ''.join(seq) instead]".to_owned()
800 )),
801 PyBytes =>
802 return Err(vm.new_type_error(
803 "sum() can't sum bytes [use b''.join(seq) instead]".to_owned()
804 )),
805 PyByteArray =>
806 return Err(vm.new_type_error(
807 "sum() can't sum bytearray [use b''.join(seq) instead]".to_owned()
808 )),
809 _ => (),
810 });
811
812 for item in iterable.iter(vm)? {
813 sum = vm._add(&sum, &*item?)?;
814 }
815 Ok(sum)
816 }
817
818 #[pyfunction]
819 fn __import__(args: FuncArgs, vm: &VirtualMachine) -> PyResult {
820 vm.import_func.call(args, vm)
821 }
822
823 #[pyfunction]
824 fn vars(obj: OptionalArg, vm: &VirtualMachine) -> PyResult {
825 if let OptionalArg::Present(obj) = obj {
826 obj.get_attr(identifier!(vm, __dict__), vm).map_err(|_| {
827 vm.new_type_error("vars() argument must have __dict__ attribute".to_owned())
828 })
829 } else {
830 Ok(vm.current_locals()?.into())
831 }
832 }
833
834 #[pyfunction]
835 pub fn __build_class__(
836 function: PyRef<PyFunction>,
837 qualified_name: PyStrRef,
838 bases: PosArgs,
839 mut kwargs: KwArgs,
840 vm: &VirtualMachine,
841 ) -> PyResult {
842 let name = qualified_name.as_str().split('.').next_back().unwrap();
843 let name_obj = vm.ctx.new_str(name);
844
845 let mut new_bases: Option<Vec<PyObjectRef>> = None;
847 let bases = PyTuple::new_ref(bases.into_vec(), &vm.ctx);
848 for (i, base) in bases.iter().enumerate() {
849 if base.fast_isinstance(vm.ctx.types.type_type) {
850 if let Some(bases) = &mut new_bases {
851 bases.push(base.clone());
852 }
853 continue;
854 }
855 let mro_entries =
856 vm.get_attribute_opt(base.clone(), identifier!(vm, __mro_entries__))?;
857 let entries = match mro_entries {
858 Some(meth) => meth.call((bases.clone(),), vm)?,
859 None => {
860 if let Some(bases) = &mut new_bases {
861 bases.push(base.clone());
862 }
863 continue;
864 }
865 };
866 let entries: PyTupleRef = entries
867 .downcast()
868 .map_err(|_| vm.new_type_error("__mro_entries__ must return a tuple".to_owned()))?;
869 let new_bases = new_bases.get_or_insert_with(|| bases[..i].to_vec());
870 new_bases.extend_from_slice(&entries);
871 }
872
873 let new_bases = new_bases.map(|v| PyTuple::new_ref(v, &vm.ctx));
874 let (orig_bases, bases) = match new_bases {
875 Some(new) => (Some(bases), new),
876 None => (None, bases),
877 };
878
879 let metaclass = kwargs
881 .pop_kwarg("metaclass")
882 .map(|metaclass| {
883 metaclass
884 .downcast_exact::<PyType>(vm)
885 .map(|m| m.into_pyref())
886 })
887 .unwrap_or_else(|| Ok(vm.ctx.types.type_type.to_owned()));
888
889 let (metaclass, meta_name) = match metaclass {
890 Ok(mut metaclass) => {
891 for base in bases.iter() {
892 let base_class = base.class();
893 if base_class.fast_issubclass(&metaclass) {
894 metaclass = base.class().to_owned();
895 } else if !metaclass.fast_issubclass(base_class) {
896 return Err(vm.new_type_error(
897 "metaclass conflict: the metaclass of a derived class must be a (non-strict) \
898 subclass of the metaclasses of all its bases"
899 .to_owned(),
900 ));
901 }
902 }
903 let meta_name = metaclass.slot_name();
904 (metaclass.to_owned().into(), meta_name.to_owned())
905 }
906 Err(obj) => (obj, "<metaclass>".to_owned()),
907 };
908
909 let bases: PyObjectRef = bases.into();
910
911 let namespace = vm
913 .get_attribute_opt(metaclass.clone(), identifier!(vm, __prepare__))?
914 .map_or(Ok(vm.ctx.new_dict().into()), |prepare| {
915 let args =
916 FuncArgs::new(vec![name_obj.clone().into(), bases.clone()], kwargs.clone());
917 prepare.call(args, vm)
918 })?;
919
920 let namespace = ArgMapping::try_from_object(vm, namespace.clone()).map_err(|_| {
922 vm.new_type_error(format!(
923 "{}.__prepare__() must return a mapping, not {}",
924 meta_name,
925 namespace.class()
926 ))
927 })?;
928
929 let classcell = function.invoke_with_locals(().into(), Some(namespace.clone()), vm)?;
930 let classcell = <Option<PyCellRef>>::try_from_object(vm, classcell)?;
931
932 if let Some(orig_bases) = orig_bases {
933 namespace.as_object().set_item(
934 identifier!(vm, __orig_bases__),
935 orig_bases.into(),
936 vm,
937 )?;
938 }
939
940 let args = FuncArgs::new(vec![name_obj.into(), bases, namespace.into()], kwargs);
941 let class = metaclass.call(args, vm)?;
942
943 if let Some(ref classcell) = classcell {
944 let classcell = classcell.get().ok_or_else(|| {
945 vm.new_type_error(format!(
946 "__class__ not set defining {meta_name:?} as {class:?}. Was __classcell__ propagated to type.__new__?"
947 ))
948 })?;
949
950 if !classcell.is(&class) {
951 return Err(vm.new_type_error(format!(
952 "__class__ set to {classcell:?} defining {meta_name:?} as {class:?}"
953 )));
954 }
955 }
956
957 Ok(class)
958 }
959}
960
961pub fn init_module(vm: &VirtualMachine, module: &Py<PyModule>) {
962 let ctx = &vm.ctx;
963
964 crate::protocol::VecBuffer::make_class(&vm.ctx);
965
966 builtins::extend_module(vm, module).unwrap();
967
968 let debug_mode: bool = vm.state.settings.optimize == 0;
969 extend_module!(vm, module, {
970 "__debug__" => ctx.new_bool(debug_mode),
971
972 "bool" => ctx.types.bool_type.to_owned(),
973 "bytearray" => ctx.types.bytearray_type.to_owned(),
974 "bytes" => ctx.types.bytes_type.to_owned(),
975 "classmethod" => ctx.types.classmethod_type.to_owned(),
976 "complex" => ctx.types.complex_type.to_owned(),
977 "dict" => ctx.types.dict_type.to_owned(),
978 "enumerate" => ctx.types.enumerate_type.to_owned(),
979 "float" => ctx.types.float_type.to_owned(),
980 "frozenset" => ctx.types.frozenset_type.to_owned(),
981 "filter" => ctx.types.filter_type.to_owned(),
982 "int" => ctx.types.int_type.to_owned(),
983 "list" => ctx.types.list_type.to_owned(),
984 "map" => ctx.types.map_type.to_owned(),
985 "memoryview" => ctx.types.memoryview_type.to_owned(),
986 "object" => ctx.types.object_type.to_owned(),
987 "property" => ctx.types.property_type.to_owned(),
988 "range" => ctx.types.range_type.to_owned(),
989 "set" => ctx.types.set_type.to_owned(),
990 "slice" => ctx.types.slice_type.to_owned(),
991 "staticmethod" => ctx.types.staticmethod_type.to_owned(),
992 "str" => ctx.types.str_type.to_owned(),
993 "super" => ctx.types.super_type.to_owned(),
994 "tuple" => ctx.types.tuple_type.to_owned(),
995 "type" => ctx.types.type_type.to_owned(),
996 "zip" => ctx.types.zip_type.to_owned(),
997
998 "None" => ctx.none(),
1000 "True" => ctx.new_bool(true),
1001 "False" => ctx.new_bool(false),
1002 "NotImplemented" => ctx.not_implemented(),
1003 "Ellipsis" => vm.ctx.ellipsis.clone(),
1004
1005 "BaseException" => ctx.exceptions.base_exception_type.to_owned(),
1008 "BaseExceptionGroup" => ctx.exceptions.base_exception_group.to_owned(),
1009 "ExceptionGroup" => ctx.exceptions.exception_group.to_owned(),
1010 "SystemExit" => ctx.exceptions.system_exit.to_owned(),
1011 "KeyboardInterrupt" => ctx.exceptions.keyboard_interrupt.to_owned(),
1012 "GeneratorExit" => ctx.exceptions.generator_exit.to_owned(),
1013 "Exception" => ctx.exceptions.exception_type.to_owned(),
1014 "StopIteration" => ctx.exceptions.stop_iteration.to_owned(),
1015 "StopAsyncIteration" => ctx.exceptions.stop_async_iteration.to_owned(),
1016 "ArithmeticError" => ctx.exceptions.arithmetic_error.to_owned(),
1017 "FloatingPointError" => ctx.exceptions.floating_point_error.to_owned(),
1018 "OverflowError" => ctx.exceptions.overflow_error.to_owned(),
1019 "ZeroDivisionError" => ctx.exceptions.zero_division_error.to_owned(),
1020 "AssertionError" => ctx.exceptions.assertion_error.to_owned(),
1021 "AttributeError" => ctx.exceptions.attribute_error.to_owned(),
1022 "BufferError" => ctx.exceptions.buffer_error.to_owned(),
1023 "EOFError" => ctx.exceptions.eof_error.to_owned(),
1024 "ImportError" => ctx.exceptions.import_error.to_owned(),
1025 "ModuleNotFoundError" => ctx.exceptions.module_not_found_error.to_owned(),
1026 "LookupError" => ctx.exceptions.lookup_error.to_owned(),
1027 "IndexError" => ctx.exceptions.index_error.to_owned(),
1028 "KeyError" => ctx.exceptions.key_error.to_owned(),
1029 "MemoryError" => ctx.exceptions.memory_error.to_owned(),
1030 "NameError" => ctx.exceptions.name_error.to_owned(),
1031 "UnboundLocalError" => ctx.exceptions.unbound_local_error.to_owned(),
1032 "OSError" => ctx.exceptions.os_error.to_owned(),
1033 "IOError" => ctx.exceptions.os_error.to_owned(),
1035 "EnvironmentError" => ctx.exceptions.os_error.to_owned(),
1036 "BlockingIOError" => ctx.exceptions.blocking_io_error.to_owned(),
1037 "ChildProcessError" => ctx.exceptions.child_process_error.to_owned(),
1038 "ConnectionError" => ctx.exceptions.connection_error.to_owned(),
1039 "BrokenPipeError" => ctx.exceptions.broken_pipe_error.to_owned(),
1040 "ConnectionAbortedError" => ctx.exceptions.connection_aborted_error.to_owned(),
1041 "ConnectionRefusedError" => ctx.exceptions.connection_refused_error.to_owned(),
1042 "ConnectionResetError" => ctx.exceptions.connection_reset_error.to_owned(),
1043 "FileExistsError" => ctx.exceptions.file_exists_error.to_owned(),
1044 "FileNotFoundError" => ctx.exceptions.file_not_found_error.to_owned(),
1045 "InterruptedError" => ctx.exceptions.interrupted_error.to_owned(),
1046 "IsADirectoryError" => ctx.exceptions.is_a_directory_error.to_owned(),
1047 "NotADirectoryError" => ctx.exceptions.not_a_directory_error.to_owned(),
1048 "PermissionError" => ctx.exceptions.permission_error.to_owned(),
1049 "ProcessLookupError" => ctx.exceptions.process_lookup_error.to_owned(),
1050 "TimeoutError" => ctx.exceptions.timeout_error.to_owned(),
1051 "ReferenceError" => ctx.exceptions.reference_error.to_owned(),
1052 "RuntimeError" => ctx.exceptions.runtime_error.to_owned(),
1053 "NotImplementedError" => ctx.exceptions.not_implemented_error.to_owned(),
1054 "RecursionError" => ctx.exceptions.recursion_error.to_owned(),
1055 "SyntaxError" => ctx.exceptions.syntax_error.to_owned(),
1056 "IndentationError" => ctx.exceptions.indentation_error.to_owned(),
1057 "TabError" => ctx.exceptions.tab_error.to_owned(),
1058 "SystemError" => ctx.exceptions.system_error.to_owned(),
1059 "TypeError" => ctx.exceptions.type_error.to_owned(),
1060 "ValueError" => ctx.exceptions.value_error.to_owned(),
1061 "UnicodeError" => ctx.exceptions.unicode_error.to_owned(),
1062 "UnicodeDecodeError" => ctx.exceptions.unicode_decode_error.to_owned(),
1063 "UnicodeEncodeError" => ctx.exceptions.unicode_encode_error.to_owned(),
1064 "UnicodeTranslateError" => ctx.exceptions.unicode_translate_error.to_owned(),
1065
1066 "Warning" => ctx.exceptions.warning.to_owned(),
1068 "DeprecationWarning" => ctx.exceptions.deprecation_warning.to_owned(),
1069 "PendingDeprecationWarning" => ctx.exceptions.pending_deprecation_warning.to_owned(),
1070 "RuntimeWarning" => ctx.exceptions.runtime_warning.to_owned(),
1071 "SyntaxWarning" => ctx.exceptions.syntax_warning.to_owned(),
1072 "UserWarning" => ctx.exceptions.user_warning.to_owned(),
1073 "FutureWarning" => ctx.exceptions.future_warning.to_owned(),
1074 "ImportWarning" => ctx.exceptions.import_warning.to_owned(),
1075 "UnicodeWarning" => ctx.exceptions.unicode_warning.to_owned(),
1076 "BytesWarning" => ctx.exceptions.bytes_warning.to_owned(),
1077 "ResourceWarning" => ctx.exceptions.resource_warning.to_owned(),
1078 "EncodingWarning" => ctx.exceptions.encoding_warning.to_owned(),
1079 });
1080
1081 #[cfg(feature = "jit")]
1082 extend_module!(vm, module, {
1083 "JitError" => ctx.exceptions.jit_error.to_owned(),
1084 });
1085}