1use self::types::{PyBaseException, PyBaseExceptionRef};
2use crate::common::lock::PyRwLock;
3use crate::object::{Traverse, TraverseFn};
4use crate::{
5 builtins::{
6 traceback::PyTracebackRef, PyNone, PyStr, PyStrRef, PyTuple, PyTupleRef, PyType, PyTypeRef,
7 },
8 class::{PyClassImpl, StaticType},
9 convert::{ToPyException, ToPyObject},
10 function::{ArgIterable, FuncArgs, IntoFuncArgs},
11 py_io::{self, Write},
12 stdlib::sys,
13 suggestion::offer_suggestions,
14 types::{Callable, Constructor, Initializer, Representable},
15 AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
16};
17use crossbeam_utils::atomic::AtomicCell;
18use itertools::Itertools;
19use std::{
20 collections::HashSet,
21 io::{self, BufRead, BufReader},
22};
23
24unsafe impl Traverse for PyBaseException {
25 fn traverse(&self, tracer_fn: &mut TraverseFn) {
26 self.traceback.traverse(tracer_fn);
27 self.cause.traverse(tracer_fn);
28 self.context.traverse(tracer_fn);
29 self.args.traverse(tracer_fn);
30 }
31}
32
33impl std::fmt::Debug for PyBaseException {
34 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
35 f.write_str("PyBaseException")
37 }
38}
39
40impl PyPayload for PyBaseException {
41 fn class(ctx: &Context) -> &'static Py<PyType> {
42 ctx.exceptions.base_exception_type
43 }
44}
45
46impl VirtualMachine {
47 pub fn print_exception(&self, exc: PyBaseExceptionRef) {
52 let vm = self;
53 let write_fallback = |exc, errstr| {
54 if let Ok(stderr) = sys::get_stderr(vm) {
55 let mut stderr = py_io::PyWriter(stderr, vm);
56 let _ = writeln!(stderr, "{errstr}");
58 let _ = self.write_exception(&mut stderr, exc);
59 } else {
60 eprintln!("{errstr}\nlost sys.stderr");
61 let _ = self.write_exception(&mut py_io::IoWriter(io::stderr()), exc);
62 }
63 };
64 if let Ok(excepthook) = vm.sys_module.get_attr("excepthook", vm) {
65 let (exc_type, exc_val, exc_tb) = vm.split_exception(exc.clone());
66 if let Err(eh_exc) = excepthook.call((exc_type, exc_val, exc_tb), vm) {
67 write_fallback(&eh_exc, "Error in sys.excepthook:");
68 write_fallback(&exc, "Original exception was:");
69 }
70 } else {
71 write_fallback(&exc, "missing sys.excepthook");
72 }
73 }
74
75 pub fn write_exception<W: Write>(
76 &self,
77 output: &mut W,
78 exc: &PyBaseExceptionRef,
79 ) -> Result<(), W::Error> {
80 let seen = &mut HashSet::<usize>::new();
81 self.write_exception_recursive(output, exc, seen)
82 }
83
84 fn write_exception_recursive<W: Write>(
85 &self,
86 output: &mut W,
87 exc: &PyBaseExceptionRef,
88 seen: &mut HashSet<usize>,
89 ) -> Result<(), W::Error> {
90 seen.insert(exc.get_id());
94
95 #[allow(clippy::manual_map)]
96 if let Some((cause_or_context, msg)) = if let Some(cause) = exc.cause() {
97 Some((
100 cause,
101 "\nThe above exception was the direct cause of the following exception:\n",
102 ))
103 } else if let Some(context) = exc.context() {
104 Some((
110 context,
111 "\nDuring handling of the above exception, another exception occurred:\n",
112 ))
113 } else {
114 None
115 } {
116 if !seen.contains(&cause_or_context.get_id()) {
117 self.write_exception_recursive(output, &cause_or_context, seen)?;
118 writeln!(output, "{msg}")?;
119 } else {
120 seen.insert(cause_or_context.get_id());
121 }
122 }
123
124 self.write_exception_inner(output, exc)
125 }
126
127 pub fn write_exception_inner<W: Write>(
129 &self,
130 output: &mut W,
131 exc: &PyBaseExceptionRef,
132 ) -> Result<(), W::Error> {
133 let vm = self;
134 if let Some(tb) = exc.traceback.read().clone() {
135 writeln!(output, "Traceback (most recent call last):")?;
136 for tb in tb.iter() {
137 write_traceback_entry(output, &tb)?;
138 }
139 }
140
141 let varargs = exc.args();
142 let args_repr = vm.exception_args_as_string(varargs, true);
143
144 let exc_class = exc.class();
145
146 if exc_class.fast_issubclass(vm.ctx.exceptions.syntax_error) {
147 return self.write_syntaxerror(output, exc, exc_class, &args_repr);
148 }
149
150 let exc_name = exc_class.name();
151 match args_repr.len() {
152 0 => write!(output, "{exc_name}"),
153 1 => write!(output, "{}: {}", exc_name, args_repr[0]),
154 _ => write!(
155 output,
156 "{}: ({})",
157 exc_name,
158 args_repr.into_iter().format(", "),
159 ),
160 }?;
161
162 match offer_suggestions(exc, vm) {
163 Some(suggestions) => writeln!(output, ". Did you mean: '{suggestions}'?"),
164 None => writeln!(output),
165 }
166 }
167
168 fn write_syntaxerror<W: Write>(
174 &self,
175 output: &mut W,
176 exc: &PyBaseExceptionRef,
177 exc_type: &Py<PyType>,
178 args_repr: &[PyRef<PyStr>],
179 ) -> Result<(), W::Error> {
180 let vm = self;
181 debug_assert!(exc_type.fast_issubclass(vm.ctx.exceptions.syntax_error));
182
183 let getattr = |attr: &'static str| exc.as_object().get_attr(attr, vm).ok();
184
185 let maybe_lineno = getattr("lineno").map(|obj| {
186 obj.str(vm)
187 .unwrap_or_else(|_| vm.ctx.new_str("<lineno str() failed>"))
188 });
189 let maybe_filename = getattr("filename").and_then(|obj| obj.str(vm).ok());
190
191 let maybe_text = getattr("text").map(|obj| {
192 obj.str(vm)
193 .unwrap_or_else(|_| vm.ctx.new_str("<text str() failed>"))
194 });
195
196 let mut filename_suffix = String::new();
197
198 if let Some(lineno) = maybe_lineno {
199 writeln!(
200 output,
201 r##" File "{}", line {}"##,
202 maybe_filename
203 .as_ref()
204 .map(|s| s.as_str())
205 .unwrap_or("<string>"),
206 lineno
207 )?;
208 } else if let Some(filename) = maybe_filename {
209 filename_suffix = format!(" ({})", filename);
210 }
211
212 if let Some(text) = maybe_text {
213 let rtext = text.as_str().trim_end_matches('\n');
215 let ltext = rtext.trim_start_matches([' ', '\n', '\x0c']); let spaces = (rtext.len() - ltext.len()) as isize;
217
218 writeln!(output, " {}", ltext)?;
219
220 let maybe_offset: Option<isize> =
221 getattr("offset").and_then(|obj| obj.try_to_value::<isize>(vm).ok());
222
223 if let Some(offset) = maybe_offset {
224 let maybe_end_offset: Option<isize> =
225 getattr("end_offset").and_then(|obj| obj.try_to_value::<isize>(vm).ok());
226
227 let mut end_offset = match maybe_end_offset {
228 Some(0) | None => offset,
229 Some(end_offset) => end_offset,
230 };
231
232 if offset == end_offset || end_offset == -1 {
233 end_offset = offset + 1;
234 }
235
236 let colno = offset - 1 - spaces;
238 let end_colno = end_offset - 1 - spaces;
239 if colno >= 0 {
240 let caretspace = ltext.chars().collect::<Vec<_>>()[..colno as usize]
241 .iter()
242 .map(|c| if c.is_whitespace() { *c } else { ' ' })
243 .collect::<String>();
244
245 let mut error_width = end_colno - colno;
246 if error_width < 1 {
247 error_width = 1;
248 }
249
250 writeln!(
251 output,
252 " {}{}",
253 caretspace,
254 "^".repeat(error_width as usize)
255 )?;
256 }
257 }
258 }
259
260 let exc_name = exc_type.name();
261
262 match args_repr.len() {
263 0 => write!(output, "{exc_name}{filename_suffix}"),
264 1 => write!(output, "{}: {}{}", exc_name, args_repr[0], filename_suffix),
265 _ => write!(
266 output,
267 "{}: ({}){}",
268 exc_name,
269 args_repr.iter().format(", "),
270 filename_suffix
271 ),
272 }?;
273
274 match offer_suggestions(exc, vm) {
275 Some(suggestions) => writeln!(output, ". Did you mean: '{suggestions}'?"),
276 None => writeln!(output),
277 }
278 }
279
280 fn exception_args_as_string(&self, varargs: PyTupleRef, str_single: bool) -> Vec<PyStrRef> {
281 let vm = self;
282 match varargs.len() {
283 0 => vec![],
284 1 => {
285 let args0_repr = if str_single {
286 varargs[0]
287 .str(vm)
288 .unwrap_or_else(|_| PyStr::from("<element str() failed>").into_ref(&vm.ctx))
289 } else {
290 varargs[0].repr(vm).unwrap_or_else(|_| {
291 PyStr::from("<element repr() failed>").into_ref(&vm.ctx)
292 })
293 };
294 vec![args0_repr]
295 }
296 _ => varargs
297 .iter()
298 .map(|vararg| {
299 vararg.repr(vm).unwrap_or_else(|_| {
300 PyStr::from("<element repr() failed>").into_ref(&vm.ctx)
301 })
302 })
303 .collect(),
304 }
305 }
306
307 pub fn split_exception(
308 &self,
309 exc: PyBaseExceptionRef,
310 ) -> (PyObjectRef, PyObjectRef, PyObjectRef) {
311 let tb = exc.traceback().to_pyobject(self);
312 let class = exc.class().to_owned();
313 (class.into(), exc.into(), tb)
314 }
315
316 pub fn normalize_exception(
318 &self,
319 exc_type: PyObjectRef,
320 exc_val: PyObjectRef,
321 exc_tb: PyObjectRef,
322 ) -> PyResult<PyBaseExceptionRef> {
323 let ctor = ExceptionCtor::try_from_object(self, exc_type)?;
324 let exc = ctor.instantiate_value(exc_val, self)?;
325 if let Some(tb) = Option::<PyTracebackRef>::try_from_object(self, exc_tb)? {
326 exc.set_traceback(Some(tb));
327 }
328 Ok(exc)
329 }
330
331 pub fn invoke_exception(
332 &self,
333 cls: PyTypeRef,
334 args: Vec<PyObjectRef>,
335 ) -> PyResult<PyBaseExceptionRef> {
336 let res = PyType::call(&cls, args.into_args(self), self)?;
338 PyBaseExceptionRef::try_from_object(self, res)
339 }
340}
341
342fn print_source_line<W: Write>(
343 output: &mut W,
344 filename: &str,
345 lineno: usize,
346) -> Result<(), W::Error> {
347 let file = match std::fs::File::open(filename) {
350 Ok(file) => file,
351 Err(_) => return Ok(()),
352 };
353 let file = BufReader::new(file);
354
355 for (i, line) in file.lines().enumerate() {
356 if i + 1 == lineno {
357 if let Ok(line) = line {
358 writeln!(output, " {}", line.trim_start())?;
360 }
361 return Ok(());
362 }
363 }
364
365 Ok(())
366}
367
368fn write_traceback_entry<W: Write>(
370 output: &mut W,
371 tb_entry: &PyTracebackRef,
372) -> Result<(), W::Error> {
373 let filename = tb_entry.frame.code.source_path.as_str();
374 writeln!(
375 output,
376 r##" File "{}", line {}, in {}"##,
377 filename, tb_entry.lineno, tb_entry.frame.code.obj_name
378 )?;
379 print_source_line(output, filename, tb_entry.lineno.to_usize())?;
380
381 Ok(())
382}
383
384#[derive(Clone)]
385pub enum ExceptionCtor {
386 Class(PyTypeRef),
387 Instance(PyBaseExceptionRef),
388}
389
390impl TryFromObject for ExceptionCtor {
391 fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
392 obj.downcast::<PyType>()
393 .and_then(|cls| {
394 if cls.fast_issubclass(vm.ctx.exceptions.base_exception_type) {
395 Ok(Self::Class(cls))
396 } else {
397 Err(cls.into())
398 }
399 })
400 .or_else(|obj| obj.downcast::<PyBaseException>().map(Self::Instance))
401 .map_err(|obj| {
402 vm.new_type_error(format!(
403 "exceptions must be classes or instances deriving from BaseException, not {}",
404 obj.class().name()
405 ))
406 })
407 }
408}
409
410impl ExceptionCtor {
411 pub fn instantiate(self, vm: &VirtualMachine) -> PyResult<PyBaseExceptionRef> {
412 match self {
413 Self::Class(cls) => vm.invoke_exception(cls, vec![]),
414 Self::Instance(exc) => Ok(exc),
415 }
416 }
417
418 pub fn instantiate_value(
419 self,
420 value: PyObjectRef,
421 vm: &VirtualMachine,
422 ) -> PyResult<PyBaseExceptionRef> {
423 let exc_inst = value.clone().downcast::<PyBaseException>().ok();
424 match (self, exc_inst) {
425 (Self::Instance(_exc_a), Some(_exc_b)) => {
427 Err(vm
428 .new_type_error("instance exception may not have a separate value".to_owned()))
429 }
430 (Self::Instance(exc), None) => Ok(exc),
432 (Self::Class(cls), Some(exc)) if exc.fast_isinstance(&cls) => Ok(exc),
434 (Self::Class(cls), _) => {
436 let args = match_class!(match value {
437 PyNone => vec![],
438 tup @ PyTuple => tup.to_vec(),
439 exc @ PyBaseException => exc.args().to_vec(),
440 obj => vec![obj],
441 });
442 vm.invoke_exception(cls, args)
443 }
444 }
445 }
446}
447
448#[derive(Debug, Clone)]
449pub struct ExceptionZoo {
450 pub base_exception_type: &'static Py<PyType>,
451 pub base_exception_group: &'static Py<PyType>,
452 pub exception_group: &'static Py<PyType>,
453 pub system_exit: &'static Py<PyType>,
454 pub keyboard_interrupt: &'static Py<PyType>,
455 pub generator_exit: &'static Py<PyType>,
456 pub exception_type: &'static Py<PyType>,
457 pub stop_iteration: &'static Py<PyType>,
458 pub stop_async_iteration: &'static Py<PyType>,
459 pub arithmetic_error: &'static Py<PyType>,
460 pub floating_point_error: &'static Py<PyType>,
461 pub overflow_error: &'static Py<PyType>,
462 pub zero_division_error: &'static Py<PyType>,
463 pub assertion_error: &'static Py<PyType>,
464 pub attribute_error: &'static Py<PyType>,
465 pub buffer_error: &'static Py<PyType>,
466 pub eof_error: &'static Py<PyType>,
467 pub import_error: &'static Py<PyType>,
468 pub module_not_found_error: &'static Py<PyType>,
469 pub lookup_error: &'static Py<PyType>,
470 pub index_error: &'static Py<PyType>,
471 pub key_error: &'static Py<PyType>,
472 pub memory_error: &'static Py<PyType>,
473 pub name_error: &'static Py<PyType>,
474 pub unbound_local_error: &'static Py<PyType>,
475 pub os_error: &'static Py<PyType>,
476 pub blocking_io_error: &'static Py<PyType>,
477 pub child_process_error: &'static Py<PyType>,
478 pub connection_error: &'static Py<PyType>,
479 pub broken_pipe_error: &'static Py<PyType>,
480 pub connection_aborted_error: &'static Py<PyType>,
481 pub connection_refused_error: &'static Py<PyType>,
482 pub connection_reset_error: &'static Py<PyType>,
483 pub file_exists_error: &'static Py<PyType>,
484 pub file_not_found_error: &'static Py<PyType>,
485 pub interrupted_error: &'static Py<PyType>,
486 pub is_a_directory_error: &'static Py<PyType>,
487 pub not_a_directory_error: &'static Py<PyType>,
488 pub permission_error: &'static Py<PyType>,
489 pub process_lookup_error: &'static Py<PyType>,
490 pub timeout_error: &'static Py<PyType>,
491 pub reference_error: &'static Py<PyType>,
492 pub runtime_error: &'static Py<PyType>,
493 pub not_implemented_error: &'static Py<PyType>,
494 pub recursion_error: &'static Py<PyType>,
495 pub syntax_error: &'static Py<PyType>,
496 pub indentation_error: &'static Py<PyType>,
497 pub tab_error: &'static Py<PyType>,
498 pub system_error: &'static Py<PyType>,
499 pub type_error: &'static Py<PyType>,
500 pub value_error: &'static Py<PyType>,
501 pub unicode_error: &'static Py<PyType>,
502 pub unicode_decode_error: &'static Py<PyType>,
503 pub unicode_encode_error: &'static Py<PyType>,
504 pub unicode_translate_error: &'static Py<PyType>,
505
506 #[cfg(feature = "jit")]
507 pub jit_error: &'static Py<PyType>,
508
509 pub warning: &'static Py<PyType>,
510 pub deprecation_warning: &'static Py<PyType>,
511 pub pending_deprecation_warning: &'static Py<PyType>,
512 pub runtime_warning: &'static Py<PyType>,
513 pub syntax_warning: &'static Py<PyType>,
514 pub user_warning: &'static Py<PyType>,
515 pub future_warning: &'static Py<PyType>,
516 pub import_warning: &'static Py<PyType>,
517 pub unicode_warning: &'static Py<PyType>,
518 pub bytes_warning: &'static Py<PyType>,
519 pub resource_warning: &'static Py<PyType>,
520 pub encoding_warning: &'static Py<PyType>,
521}
522
523macro_rules! extend_exception {
524 (
525 $exc_struct:ident,
526 $ctx:expr,
527 $class:expr
528 ) => {
529 extend_exception!($exc_struct, $ctx, $class, {});
530 };
531 (
532 $exc_struct:ident,
533 $ctx:expr,
534 $class:expr,
535 { $($name:expr => $value:expr),* $(,)* }
536 ) => {
537 $exc_struct::extend_class($ctx, $class);
538 extend_class!($ctx, $class, {
539 $($name => $value,)*
540 });
541 };
542}
543
544impl PyBaseException {
545 pub(crate) fn new(args: Vec<PyObjectRef>, vm: &VirtualMachine) -> PyBaseException {
546 PyBaseException {
547 traceback: PyRwLock::new(None),
548 cause: PyRwLock::new(None),
549 context: PyRwLock::new(None),
550 suppress_context: AtomicCell::new(false),
551 args: PyRwLock::new(PyTuple::new_ref(args, &vm.ctx)),
552 }
553 }
554
555 pub fn get_arg(&self, idx: usize) -> Option<PyObjectRef> {
556 self.args.read().get(idx).cloned()
557 }
558}
559
560#[pyclass(
561 with(PyRef, Constructor, Initializer, Representable),
562 flags(BASETYPE, HAS_DICT)
563)]
564impl PyBaseException {
565 #[pygetset]
566 pub fn args(&self) -> PyTupleRef {
567 self.args.read().clone()
568 }
569
570 #[pygetset(setter)]
571 fn set_args(&self, args: ArgIterable, vm: &VirtualMachine) -> PyResult<()> {
572 let args = args.iter(vm)?.collect::<PyResult<Vec<_>>>()?;
573 *self.args.write() = PyTuple::new_ref(args, &vm.ctx);
574 Ok(())
575 }
576
577 #[pygetset(magic)]
578 pub fn traceback(&self) -> Option<PyTracebackRef> {
579 self.traceback.read().clone()
580 }
581
582 #[pygetset(magic, setter)]
583 pub fn set_traceback(&self, traceback: Option<PyTracebackRef>) {
584 *self.traceback.write() = traceback;
585 }
586
587 #[pygetset(magic)]
588 pub fn cause(&self) -> Option<PyRef<Self>> {
589 self.cause.read().clone()
590 }
591
592 #[pygetset(magic, setter)]
593 pub fn set_cause(&self, cause: Option<PyRef<Self>>) {
594 let mut c = self.cause.write();
595 self.set_suppress_context(true);
596 *c = cause;
597 }
598
599 #[pygetset(magic)]
600 pub fn context(&self) -> Option<PyRef<Self>> {
601 self.context.read().clone()
602 }
603
604 #[pygetset(magic, setter)]
605 pub fn set_context(&self, context: Option<PyRef<Self>>) {
606 *self.context.write() = context;
607 }
608
609 #[pygetset(name = "__suppress_context__")]
610 pub(super) fn get_suppress_context(&self) -> bool {
611 self.suppress_context.load()
612 }
613
614 #[pygetset(name = "__suppress_context__", setter)]
615 fn set_suppress_context(&self, suppress_context: bool) {
616 self.suppress_context.store(suppress_context);
617 }
618
619 #[pymethod(magic)]
620 pub(super) fn str(&self, vm: &VirtualMachine) -> PyStrRef {
621 let str_args = vm.exception_args_as_string(self.args(), true);
622 match str_args.into_iter().exactly_one() {
623 Err(i) if i.len() == 0 => vm.ctx.empty_str.to_owned(),
624 Ok(s) => s,
625 Err(i) => PyStr::from(format!("({})", i.format(", "))).into_ref(&vm.ctx),
626 }
627 }
628}
629
630#[pyclass]
631impl PyRef<PyBaseException> {
632 #[pymethod]
633 fn with_traceback(self, tb: Option<PyTracebackRef>) -> PyResult<Self> {
634 *self.traceback.write() = tb;
635 Ok(self)
636 }
637
638 #[pymethod(magic)]
639 fn reduce(self, vm: &VirtualMachine) -> PyTupleRef {
640 if let Some(dict) = self.as_object().dict().filter(|x| !x.is_empty()) {
641 vm.new_tuple((self.class().to_owned(), self.args(), dict))
642 } else {
643 vm.new_tuple((self.class().to_owned(), self.args()))
644 }
645 }
646}
647
648impl Constructor for PyBaseException {
649 type Args = FuncArgs;
650
651 fn py_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
652 PyBaseException::new(args.args, vm)
653 .into_ref_with_type(vm, cls)
654 .map(Into::into)
655 }
656}
657
658impl Initializer for PyBaseException {
659 type Args = FuncArgs;
660
661 fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
662 *zelf.args.write() = PyTuple::new_ref(args.args, &vm.ctx);
663 Ok(())
664 }
665}
666
667impl Representable for PyBaseException {
668 #[inline]
669 fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
670 let repr_args = vm.exception_args_as_string(zelf.args(), false);
671 let cls = zelf.class();
672 Ok(format!("{}({})", cls.name(), repr_args.iter().format(", ")))
673 }
674}
675
676impl ExceptionZoo {
677 pub(crate) fn init() -> Self {
678 use self::types::*;
679
680 let base_exception_type = PyBaseException::init_builtin_type();
681
682 let base_exception_group = PyBaseExceptionGroup::init_builtin_type();
684 let exception_group = PyExceptionGroup::init_builtin_type();
685 let system_exit = PySystemExit::init_builtin_type();
686 let keyboard_interrupt = PyKeyboardInterrupt::init_builtin_type();
687 let generator_exit = PyGeneratorExit::init_builtin_type();
688
689 let exception_type = PyException::init_builtin_type();
690 let stop_iteration = PyStopIteration::init_builtin_type();
691 let stop_async_iteration = PyStopAsyncIteration::init_builtin_type();
692 let arithmetic_error = PyArithmeticError::init_builtin_type();
693 let floating_point_error = PyFloatingPointError::init_builtin_type();
694 let overflow_error = PyOverflowError::init_builtin_type();
695 let zero_division_error = PyZeroDivisionError::init_builtin_type();
696
697 let assertion_error = PyAssertionError::init_builtin_type();
698 let attribute_error = PyAttributeError::init_builtin_type();
699 let buffer_error = PyBufferError::init_builtin_type();
700 let eof_error = PyEOFError::init_builtin_type();
701
702 let import_error = PyImportError::init_builtin_type();
703 let module_not_found_error = PyModuleNotFoundError::init_builtin_type();
704
705 let lookup_error = PyLookupError::init_builtin_type();
706 let index_error = PyIndexError::init_builtin_type();
707 let key_error = PyKeyError::init_builtin_type();
708
709 let memory_error = PyMemoryError::init_builtin_type();
710
711 let name_error = PyNameError::init_builtin_type();
712 let unbound_local_error = PyUnboundLocalError::init_builtin_type();
713
714 let os_error = PyOSError::init_builtin_type();
716 let blocking_io_error = PyBlockingIOError::init_builtin_type();
717 let child_process_error = PyChildProcessError::init_builtin_type();
718
719 let connection_error = PyConnectionError::init_builtin_type();
720 let broken_pipe_error = PyBrokenPipeError::init_builtin_type();
721 let connection_aborted_error = PyConnectionAbortedError::init_builtin_type();
722 let connection_refused_error = PyConnectionRefusedError::init_builtin_type();
723 let connection_reset_error = PyConnectionResetError::init_builtin_type();
724
725 let file_exists_error = PyFileExistsError::init_builtin_type();
726 let file_not_found_error = PyFileNotFoundError::init_builtin_type();
727 let interrupted_error = PyInterruptedError::init_builtin_type();
728 let is_a_directory_error = PyIsADirectoryError::init_builtin_type();
729 let not_a_directory_error = PyNotADirectoryError::init_builtin_type();
730 let permission_error = PyPermissionError::init_builtin_type();
731 let process_lookup_error = PyProcessLookupError::init_builtin_type();
732 let timeout_error = PyTimeoutError::init_builtin_type();
733
734 let reference_error = PyReferenceError::init_builtin_type();
735
736 let runtime_error = PyRuntimeError::init_builtin_type();
737 let not_implemented_error = PyNotImplementedError::init_builtin_type();
738 let recursion_error = PyRecursionError::init_builtin_type();
739
740 let syntax_error = PySyntaxError::init_builtin_type();
741 let indentation_error = PyIndentationError::init_builtin_type();
742 let tab_error = PyTabError::init_builtin_type();
743
744 let system_error = PySystemError::init_builtin_type();
745 let type_error = PyTypeError::init_builtin_type();
746 let value_error = PyValueError::init_builtin_type();
747 let unicode_error = PyUnicodeError::init_builtin_type();
748 let unicode_decode_error = PyUnicodeDecodeError::init_builtin_type();
749 let unicode_encode_error = PyUnicodeEncodeError::init_builtin_type();
750 let unicode_translate_error = PyUnicodeTranslateError::init_builtin_type();
751
752 #[cfg(feature = "jit")]
753 let jit_error = PyJitError::init_builtin_type();
754
755 let warning = PyWarning::init_builtin_type();
756 let deprecation_warning = PyDeprecationWarning::init_builtin_type();
757 let pending_deprecation_warning = PyPendingDeprecationWarning::init_builtin_type();
758 let runtime_warning = PyRuntimeWarning::init_builtin_type();
759 let syntax_warning = PySyntaxWarning::init_builtin_type();
760 let user_warning = PyUserWarning::init_builtin_type();
761 let future_warning = PyFutureWarning::init_builtin_type();
762 let import_warning = PyImportWarning::init_builtin_type();
763 let unicode_warning = PyUnicodeWarning::init_builtin_type();
764 let bytes_warning = PyBytesWarning::init_builtin_type();
765 let resource_warning = PyResourceWarning::init_builtin_type();
766 let encoding_warning = PyEncodingWarning::init_builtin_type();
767
768 Self {
769 base_exception_type,
770 base_exception_group,
771 exception_group,
772 system_exit,
773 keyboard_interrupt,
774 generator_exit,
775 exception_type,
776 stop_iteration,
777 stop_async_iteration,
778 arithmetic_error,
779 floating_point_error,
780 overflow_error,
781 zero_division_error,
782 assertion_error,
783 attribute_error,
784 buffer_error,
785 eof_error,
786 import_error,
787 module_not_found_error,
788 lookup_error,
789 index_error,
790 key_error,
791 memory_error,
792 name_error,
793 unbound_local_error,
794 os_error,
795 blocking_io_error,
796 child_process_error,
797 connection_error,
798 broken_pipe_error,
799 connection_aborted_error,
800 connection_refused_error,
801 connection_reset_error,
802 file_exists_error,
803 file_not_found_error,
804 interrupted_error,
805 is_a_directory_error,
806 not_a_directory_error,
807 permission_error,
808 process_lookup_error,
809 timeout_error,
810 reference_error,
811 runtime_error,
812 not_implemented_error,
813 recursion_error,
814 syntax_error,
815 indentation_error,
816 tab_error,
817 system_error,
818 type_error,
819 value_error,
820 unicode_error,
821 unicode_decode_error,
822 unicode_encode_error,
823 unicode_translate_error,
824
825 #[cfg(feature = "jit")]
826 jit_error,
827
828 warning,
829 deprecation_warning,
830 pending_deprecation_warning,
831 runtime_warning,
832 syntax_warning,
833 user_warning,
834 future_warning,
835 import_warning,
836 unicode_warning,
837 bytes_warning,
838 resource_warning,
839 encoding_warning,
840 }
841 }
842
843 #[allow(clippy::redundant_clone)]
845 pub fn extend(ctx: &Context) {
846 use self::types::*;
847
848 let excs = &ctx.exceptions;
849
850 PyBaseException::extend_class(ctx, excs.base_exception_type);
851
852 extend_exception!(PyBaseExceptionGroup, ctx, excs.base_exception_group, {
854 "message" => ctx.new_readonly_getset("message", excs.base_exception_group, make_arg_getter(0)),
855 "exceptions" => ctx.new_readonly_getset("exceptions", excs.base_exception_group, make_arg_getter(1)),
856 });
857 extend_exception!(PyExceptionGroup, ctx, excs.exception_group);
858 extend_exception!(PySystemExit, ctx, excs.system_exit, {
859 "code" => ctx.new_readonly_getset("code", excs.system_exit, system_exit_code),
860 });
861 extend_exception!(PyKeyboardInterrupt, ctx, excs.keyboard_interrupt);
862 extend_exception!(PyGeneratorExit, ctx, excs.generator_exit);
863
864 extend_exception!(PyException, ctx, excs.exception_type);
865
866 extend_exception!(PyStopIteration, ctx, excs.stop_iteration, {
867 "value" => ctx.none(),
868 });
869 extend_exception!(PyStopAsyncIteration, ctx, excs.stop_async_iteration);
870
871 extend_exception!(PyArithmeticError, ctx, excs.arithmetic_error);
872 extend_exception!(PyFloatingPointError, ctx, excs.floating_point_error);
873 extend_exception!(PyOverflowError, ctx, excs.overflow_error);
874 extend_exception!(PyZeroDivisionError, ctx, excs.zero_division_error);
875
876 extend_exception!(PyAssertionError, ctx, excs.assertion_error);
877 extend_exception!(PyAttributeError, ctx, excs.attribute_error, {
878 "name" => ctx.none(),
879 "obj" => ctx.none(),
880 });
881 extend_exception!(PyBufferError, ctx, excs.buffer_error);
882 extend_exception!(PyEOFError, ctx, excs.eof_error);
883
884 extend_exception!(PyImportError, ctx, excs.import_error, {
885 "msg" => ctx.new_readonly_getset("msg", excs.import_error, make_arg_getter(0)),
886 "name" => ctx.none(),
887 "path" => ctx.none(),
888 });
889 extend_exception!(PyModuleNotFoundError, ctx, excs.module_not_found_error);
890
891 extend_exception!(PyLookupError, ctx, excs.lookup_error);
892 extend_exception!(PyIndexError, ctx, excs.index_error);
893
894 extend_exception!(PyKeyError, ctx, excs.key_error);
895
896 extend_exception!(PyMemoryError, ctx, excs.memory_error);
897 extend_exception!(PyNameError, ctx, excs.name_error, {
898 "name" => ctx.none(),
899 });
900 extend_exception!(PyUnboundLocalError, ctx, excs.unbound_local_error);
901
902 let errno_getter =
904 ctx.new_readonly_getset("errno", excs.os_error, |exc: PyBaseExceptionRef| {
905 let args = exc.args();
906 args.first()
907 .filter(|_| args.len() > 1 && args.len() <= 5)
908 .cloned()
909 });
910 let strerror_getter =
911 ctx.new_readonly_getset("strerror", excs.os_error, |exc: PyBaseExceptionRef| {
912 let args = exc.args();
913 args.get(1)
914 .filter(|_| args.len() >= 2 && args.len() <= 5)
915 .cloned()
916 });
917 extend_exception!(PyOSError, ctx, excs.os_error, {
918 "errno" => errno_getter.clone(),
920 "strerror" => strerror_getter.clone(),
922 "filename" => ctx.none(),
924 "filename2" => ctx.none(),
926 });
927 #[cfg(windows)]
928 excs.os_error.set_str_attr("winerror", ctx.none(), ctx);
929
930 extend_exception!(PyBlockingIOError, ctx, excs.blocking_io_error);
931 extend_exception!(PyChildProcessError, ctx, excs.child_process_error);
932
933 extend_exception!(PyConnectionError, ctx, excs.connection_error);
934 extend_exception!(PyBrokenPipeError, ctx, excs.broken_pipe_error);
935 extend_exception!(PyConnectionAbortedError, ctx, excs.connection_aborted_error);
936 extend_exception!(PyConnectionRefusedError, ctx, excs.connection_refused_error);
937 extend_exception!(PyConnectionResetError, ctx, excs.connection_reset_error);
938
939 extend_exception!(PyFileExistsError, ctx, excs.file_exists_error);
940 extend_exception!(PyFileNotFoundError, ctx, excs.file_not_found_error);
941 extend_exception!(PyInterruptedError, ctx, excs.interrupted_error);
942 extend_exception!(PyIsADirectoryError, ctx, excs.is_a_directory_error);
943 extend_exception!(PyNotADirectoryError, ctx, excs.not_a_directory_error);
944 extend_exception!(PyPermissionError, ctx, excs.permission_error);
945 extend_exception!(PyProcessLookupError, ctx, excs.process_lookup_error);
946 extend_exception!(PyTimeoutError, ctx, excs.timeout_error);
947
948 extend_exception!(PyReferenceError, ctx, excs.reference_error);
949 extend_exception!(PyRuntimeError, ctx, excs.runtime_error);
950 extend_exception!(PyNotImplementedError, ctx, excs.not_implemented_error);
951 extend_exception!(PyRecursionError, ctx, excs.recursion_error);
952
953 extend_exception!(PySyntaxError, ctx, excs.syntax_error, {
954 "msg" => ctx.new_readonly_getset("msg", excs.syntax_error, make_arg_getter(0)),
955 "filename" => ctx.none(),
957 "lineno" => ctx.none(),
958 "end_lineno" => ctx.none(),
959 "offset" => ctx.none(),
960 "end_offset" => ctx.none(),
961 "text" => ctx.none(),
962 });
963 extend_exception!(PyIndentationError, ctx, excs.indentation_error);
964 extend_exception!(PyTabError, ctx, excs.tab_error);
965
966 extend_exception!(PySystemError, ctx, excs.system_error);
967 extend_exception!(PyTypeError, ctx, excs.type_error);
968 extend_exception!(PyValueError, ctx, excs.value_error);
969 extend_exception!(PyUnicodeError, ctx, excs.unicode_error, {
970 "encoding" => ctx.new_readonly_getset("encoding", excs.unicode_error, make_arg_getter(0)),
971 "object" => ctx.new_readonly_getset("object", excs.unicode_error, make_arg_getter(1)),
972 "start" => ctx.new_readonly_getset("start", excs.unicode_error, make_arg_getter(2)),
973 "end" => ctx.new_readonly_getset("end", excs.unicode_error, make_arg_getter(3)),
974 "reason" => ctx.new_readonly_getset("reason", excs.unicode_error, make_arg_getter(4)),
975 });
976 extend_exception!(PyUnicodeDecodeError, ctx, excs.unicode_decode_error);
977 extend_exception!(PyUnicodeEncodeError, ctx, excs.unicode_encode_error);
978 extend_exception!(PyUnicodeTranslateError, ctx, excs.unicode_translate_error, {
979 "encoding" => ctx.new_readonly_getset("encoding", excs.unicode_translate_error, none_getter),
980 "object" => ctx.new_readonly_getset("object", excs.unicode_translate_error, make_arg_getter(0)),
981 "start" => ctx.new_readonly_getset("start", excs.unicode_translate_error, make_arg_getter(1)),
982 "end" => ctx.new_readonly_getset("end", excs.unicode_translate_error, make_arg_getter(2)),
983 "reason" => ctx.new_readonly_getset("reason", excs.unicode_translate_error, make_arg_getter(3)),
984 });
985
986 #[cfg(feature = "jit")]
987 extend_exception!(PyJitError, ctx, excs.jit_error);
988
989 extend_exception!(PyWarning, ctx, excs.warning);
990 extend_exception!(PyDeprecationWarning, ctx, excs.deprecation_warning);
991 extend_exception!(
992 PyPendingDeprecationWarning,
993 ctx,
994 excs.pending_deprecation_warning
995 );
996 extend_exception!(PyRuntimeWarning, ctx, excs.runtime_warning);
997 extend_exception!(PySyntaxWarning, ctx, excs.syntax_warning);
998 extend_exception!(PyUserWarning, ctx, excs.user_warning);
999 extend_exception!(PyFutureWarning, ctx, excs.future_warning);
1000 extend_exception!(PyImportWarning, ctx, excs.import_warning);
1001 extend_exception!(PyUnicodeWarning, ctx, excs.unicode_warning);
1002 extend_exception!(PyBytesWarning, ctx, excs.bytes_warning);
1003 extend_exception!(PyResourceWarning, ctx, excs.resource_warning);
1004 extend_exception!(PyEncodingWarning, ctx, excs.encoding_warning);
1005 }
1006}
1007
1008fn none_getter(_obj: PyObjectRef, vm: &VirtualMachine) -> PyRef<PyNone> {
1009 vm.ctx.none.clone()
1010}
1011
1012fn make_arg_getter(idx: usize) -> impl Fn(PyBaseExceptionRef) -> Option<PyObjectRef> {
1013 move |exc| exc.get_arg(idx)
1014}
1015
1016fn system_exit_code(exc: PyBaseExceptionRef) -> Option<PyObjectRef> {
1017 exc.args.read().first().map(|code| {
1018 match_class!(match code {
1019 ref tup @ PyTuple => match tup.as_slice() {
1020 [x] => x.clone(),
1021 _ => code.clone(),
1022 },
1023 other => other.clone(),
1024 })
1025 })
1026}
1027
1028#[cfg(feature = "serde")]
1029pub struct SerializeException<'vm, 's> {
1030 vm: &'vm VirtualMachine,
1031 exc: &'s PyBaseExceptionRef,
1032}
1033
1034#[cfg(feature = "serde")]
1035impl<'vm, 's> SerializeException<'vm, 's> {
1036 pub fn new(vm: &'vm VirtualMachine, exc: &'s PyBaseExceptionRef) -> Self {
1037 SerializeException { vm, exc }
1038 }
1039}
1040
1041#[cfg(feature = "serde")]
1042pub struct SerializeExceptionOwned<'vm> {
1043 vm: &'vm VirtualMachine,
1044 exc: PyBaseExceptionRef,
1045}
1046
1047#[cfg(feature = "serde")]
1048impl serde::Serialize for SerializeExceptionOwned<'_> {
1049 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1050 let Self { vm, exc } = self;
1051 SerializeException::new(vm, exc).serialize(s)
1052 }
1053}
1054
1055#[cfg(feature = "serde")]
1056impl serde::Serialize for SerializeException<'_, '_> {
1057 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1058 use serde::ser::*;
1059
1060 let mut struc = s.serialize_struct("PyBaseException", 7)?;
1061 struc.serialize_field("exc_type", &*self.exc.class().name())?;
1062 let tbs = {
1063 struct Tracebacks(PyTracebackRef);
1064 impl serde::Serialize for Tracebacks {
1065 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1066 let mut s = s.serialize_seq(None)?;
1067 for tb in self.0.iter() {
1068 s.serialize_element(&**tb)?;
1069 }
1070 s.end()
1071 }
1072 }
1073 self.exc.traceback().map(Tracebacks)
1074 };
1075 struc.serialize_field("traceback", &tbs)?;
1076 struc.serialize_field(
1077 "cause",
1078 &self
1079 .exc
1080 .cause()
1081 .map(|exc| SerializeExceptionOwned { vm: self.vm, exc }),
1082 )?;
1083 struc.serialize_field(
1084 "context",
1085 &self
1086 .exc
1087 .context()
1088 .map(|exc| SerializeExceptionOwned { vm: self.vm, exc }),
1089 )?;
1090 struc.serialize_field("suppress_context", &self.exc.get_suppress_context())?;
1091
1092 let args = {
1093 struct Args<'vm>(&'vm VirtualMachine, PyTupleRef);
1094 impl serde::Serialize for Args<'_> {
1095 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
1096 s.collect_seq(
1097 self.1
1098 .iter()
1099 .map(|arg| crate::py_serde::PyObjectSerializer::new(self.0, arg)),
1100 )
1101 }
1102 }
1103 Args(self.vm, self.exc.args())
1104 };
1105 struc.serialize_field("args", &args)?;
1106
1107 let rendered = {
1108 let mut rendered = String::new();
1109 self.vm
1110 .write_exception(&mut rendered, self.exc)
1111 .map_err(S::Error::custom)?;
1112 rendered
1113 };
1114 struc.serialize_field("rendered", &rendered)?;
1115
1116 struc.end()
1117 }
1118}
1119
1120pub fn cstring_error(vm: &VirtualMachine) -> PyBaseExceptionRef {
1121 vm.new_value_error("embedded null character".to_owned())
1122}
1123
1124impl ToPyException for std::ffi::NulError {
1125 fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1126 cstring_error(vm)
1127 }
1128}
1129
1130#[cfg(windows)]
1131impl<C> ToPyException for widestring::error::ContainsNul<C> {
1132 fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
1133 cstring_error(vm)
1134 }
1135}
1136
1137#[cfg(any(unix, windows, target_os = "wasi"))]
1138pub(crate) fn errno_to_exc_type(errno: i32, vm: &VirtualMachine) -> Option<&'static Py<PyType>> {
1139 use crate::stdlib::errno::errors;
1140 let excs = &vm.ctx.exceptions;
1141 match errno {
1142 errors::EWOULDBLOCK => Some(excs.blocking_io_error),
1143 errors::EALREADY => Some(excs.blocking_io_error),
1144 errors::EINPROGRESS => Some(excs.blocking_io_error),
1145 errors::EPIPE => Some(excs.broken_pipe_error),
1146 #[cfg(not(target_os = "wasi"))]
1147 errors::ESHUTDOWN => Some(excs.broken_pipe_error),
1148 errors::ECHILD => Some(excs.child_process_error),
1149 errors::ECONNABORTED => Some(excs.connection_aborted_error),
1150 errors::ECONNREFUSED => Some(excs.connection_refused_error),
1151 errors::ECONNRESET => Some(excs.connection_reset_error),
1152 errors::EEXIST => Some(excs.file_exists_error),
1153 errors::ENOENT => Some(excs.file_not_found_error),
1154 errors::EISDIR => Some(excs.is_a_directory_error),
1155 errors::ENOTDIR => Some(excs.not_a_directory_error),
1156 errors::EINTR => Some(excs.interrupted_error),
1157 errors::EACCES => Some(excs.permission_error),
1158 errors::EPERM => Some(excs.permission_error),
1159 errors::ESRCH => Some(excs.process_lookup_error),
1160 errors::ETIMEDOUT => Some(excs.timeout_error),
1161 _ => None,
1162 }
1163}
1164
1165#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
1166pub(crate) fn errno_to_exc_type(_errno: i32, _vm: &VirtualMachine) -> Option<&'static Py<PyType>> {
1167 None
1168}
1169
1170pub(super) mod types {
1171 use crate::common::lock::PyRwLock;
1172 #[cfg_attr(target_arch = "wasm32", allow(unused_imports))]
1173 use crate::{
1174 builtins::{
1175 traceback::PyTracebackRef, tuple::IntoPyTuple, PyInt, PyStrRef, PyTupleRef, PyTypeRef,
1176 },
1177 convert::ToPyResult,
1178 function::FuncArgs,
1179 types::{Constructor, Initializer},
1180 AsObject, PyObjectRef, PyRef, PyResult, VirtualMachine,
1181 };
1182 use crossbeam_utils::atomic::AtomicCell;
1183 use itertools::Itertools;
1184
1185 pub type PyBaseExceptionRef = PyRef<PyBaseException>;
1190
1191 #[pyclass(module = false, name = "BaseException", traverse = "manual")]
1194 pub struct PyBaseException {
1195 pub(super) traceback: PyRwLock<Option<PyTracebackRef>>,
1196 pub(super) cause: PyRwLock<Option<PyRef<Self>>>,
1197 pub(super) context: PyRwLock<Option<PyRef<Self>>>,
1198 pub(super) suppress_context: AtomicCell<bool>,
1199 pub(super) args: PyRwLock<PyTupleRef>,
1200 }
1201
1202 #[pyexception(name, base = "PyBaseException", ctx = "system_exit", impl)]
1203 #[derive(Debug)]
1204 pub struct PySystemExit {}
1205
1206 #[pyexception(name, base = "PyBaseException", ctx = "base_exception_group", impl)]
1207 #[derive(Debug)]
1208 pub struct PyBaseExceptionGroup {}
1209
1210 #[pyexception(name, base = "PyBaseExceptionGroup", ctx = "exception_group", impl)]
1211 #[derive(Debug)]
1212 pub struct PyExceptionGroup {}
1213
1214 #[pyexception(name, base = "PyBaseException", ctx = "generator_exit", impl)]
1215 #[derive(Debug)]
1216 pub struct PyGeneratorExit {}
1217
1218 #[pyexception(name, base = "PyBaseException", ctx = "keyboard_interrupt", impl)]
1219 #[derive(Debug)]
1220 pub struct PyKeyboardInterrupt {}
1221
1222 #[pyexception(name, base = "PyBaseException", ctx = "exception_type", impl)]
1223 #[derive(Debug)]
1224 pub struct PyException {}
1225
1226 #[pyexception(name, base = "PyException", ctx = "stop_iteration")]
1227 #[derive(Debug)]
1228 pub struct PyStopIteration {}
1229
1230 #[pyexception]
1231 impl PyStopIteration {
1232 #[pyslot]
1233 #[pymethod(name = "__init__")]
1234 pub(crate) fn slot_init(
1235 zelf: PyObjectRef,
1236 args: ::rustpython_vm::function::FuncArgs,
1237 vm: &::rustpython_vm::VirtualMachine,
1238 ) -> ::rustpython_vm::PyResult<()> {
1239 zelf.set_attr("value", vm.unwrap_or_none(args.args.first().cloned()), vm)?;
1240 Ok(())
1241 }
1242 }
1243
1244 #[pyexception(name, base = "PyException", ctx = "stop_async_iteration", impl)]
1245 #[derive(Debug)]
1246 pub struct PyStopAsyncIteration {}
1247
1248 #[pyexception(name, base = "PyException", ctx = "arithmetic_error", impl)]
1249 #[derive(Debug)]
1250 pub struct PyArithmeticError {}
1251
1252 #[pyexception(name, base = "PyArithmeticError", ctx = "floating_point_error", impl)]
1253 #[derive(Debug)]
1254 pub struct PyFloatingPointError {}
1255
1256 #[pyexception(name, base = "PyArithmeticError", ctx = "overflow_error", impl)]
1257 #[derive(Debug)]
1258 pub struct PyOverflowError {}
1259
1260 #[pyexception(name, base = "PyArithmeticError", ctx = "zero_division_error", impl)]
1261 #[derive(Debug)]
1262 pub struct PyZeroDivisionError {}
1263
1264 #[pyexception(name, base = "PyException", ctx = "assertion_error", impl)]
1265 #[derive(Debug)]
1266 pub struct PyAssertionError {}
1267
1268 #[pyexception(name, base = "PyException", ctx = "attribute_error", impl)]
1269 #[derive(Debug)]
1270 pub struct PyAttributeError {}
1271
1272 #[pyexception(name, base = "PyException", ctx = "buffer_error", impl)]
1273 #[derive(Debug)]
1274 pub struct PyBufferError {}
1275
1276 #[pyexception(name, base = "PyException", ctx = "eof_error", impl)]
1277 #[derive(Debug)]
1278 pub struct PyEOFError {}
1279
1280 #[pyexception(name, base = "PyException", ctx = "import_error")]
1281 #[derive(Debug)]
1282 pub struct PyImportError {}
1283
1284 #[pyexception]
1285 impl PyImportError {
1286 #[pyslot]
1287 #[pymethod(name = "__init__")]
1288 pub(crate) fn slot_init(
1289 zelf: PyObjectRef,
1290 args: ::rustpython_vm::function::FuncArgs,
1291 vm: &::rustpython_vm::VirtualMachine,
1292 ) -> ::rustpython_vm::PyResult<()> {
1293 zelf.set_attr(
1294 "name",
1295 vm.unwrap_or_none(args.kwargs.get("name").cloned()),
1296 vm,
1297 )?;
1298 zelf.set_attr(
1299 "path",
1300 vm.unwrap_or_none(args.kwargs.get("path").cloned()),
1301 vm,
1302 )?;
1303 Ok(())
1304 }
1305 #[pymethod(magic)]
1306 fn reduce(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
1307 let obj = exc.as_object().to_owned();
1308 let mut result: Vec<PyObjectRef> = vec![
1309 obj.class().to_owned().into(),
1310 vm.new_tuple((exc.get_arg(0).unwrap(),)).into(),
1311 ];
1312
1313 if let Some(dict) = obj.dict().filter(|x| !x.is_empty()) {
1314 result.push(dict.into());
1315 }
1316
1317 result.into_pytuple(vm)
1318 }
1319 }
1320
1321 #[pyexception(name, base = "PyImportError", ctx = "module_not_found_error", impl)]
1322 #[derive(Debug)]
1323 pub struct PyModuleNotFoundError {}
1324
1325 #[pyexception(name, base = "PyException", ctx = "lookup_error", impl)]
1326 #[derive(Debug)]
1327 pub struct PyLookupError {}
1328
1329 #[pyexception(name, base = "PyLookupError", ctx = "index_error", impl)]
1330 #[derive(Debug)]
1331 pub struct PyIndexError {}
1332
1333 #[pyexception(name, base = "PyLookupError", ctx = "key_error")]
1334 #[derive(Debug)]
1335 pub struct PyKeyError {}
1336
1337 #[pyexception]
1338 impl PyKeyError {
1339 #[pymethod(magic)]
1340 fn str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStrRef {
1341 let args = exc.args();
1342 if args.len() == 1 {
1343 vm.exception_args_as_string(args, false)
1344 .into_iter()
1345 .exactly_one()
1346 .unwrap()
1347 } else {
1348 exc.str(vm)
1349 }
1350 }
1351 }
1352
1353 #[pyexception(name, base = "PyException", ctx = "memory_error", impl)]
1354 #[derive(Debug)]
1355 pub struct PyMemoryError {}
1356
1357 #[pyexception(name, base = "PyException", ctx = "name_error", impl)]
1358 #[derive(Debug)]
1359 pub struct PyNameError {}
1360
1361 #[pyexception(name, base = "PyNameError", ctx = "unbound_local_error", impl)]
1362 #[derive(Debug)]
1363 pub struct PyUnboundLocalError {}
1364
1365 #[pyexception(name, base = "PyException", ctx = "os_error")]
1366 #[derive(Debug)]
1367 pub struct PyOSError {}
1368
1369 #[pyexception]
1371 impl PyOSError {
1372 #[cfg(not(target_arch = "wasm32"))]
1373 fn optional_new(args: Vec<PyObjectRef>, vm: &VirtualMachine) -> Option<PyBaseExceptionRef> {
1374 let len = args.len();
1375 if (2..=5).contains(&len) {
1376 let errno = &args[0];
1377 errno
1378 .payload_if_subclass::<PyInt>(vm)
1379 .and_then(|errno| errno.try_to_primitive::<i32>(vm).ok())
1380 .and_then(|errno| super::errno_to_exc_type(errno, vm))
1381 .and_then(|typ| vm.invoke_exception(typ.to_owned(), args.to_vec()).ok())
1382 } else {
1383 None
1384 }
1385 }
1386 #[cfg(not(target_arch = "wasm32"))]
1387 #[pyslot]
1388 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1389 if *cls.name() == *vm.ctx.exceptions.os_error.name() {
1393 match Self::optional_new(args.args.to_vec(), vm) {
1394 Some(error) => error.to_pyresult(vm),
1395 None => PyBaseException::slot_new(cls, args, vm),
1396 }
1397 } else {
1398 PyBaseException::slot_new(cls, args, vm)
1399 }
1400 }
1401 #[cfg(target_arch = "wasm32")]
1402 #[pyslot]
1403 fn slot_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
1404 PyBaseException::slot_new(cls, args, vm)
1405 }
1406 #[pyslot]
1407 #[pymethod(name = "__init__")]
1408 fn slot_init(zelf: PyObjectRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult<()> {
1409 let len = args.args.len();
1410 let mut new_args = args;
1411 if (3..=5).contains(&len) {
1412 zelf.set_attr("filename", new_args.args[2].clone(), vm)?;
1413 #[cfg(windows)]
1414 if let Some(winerror) = new_args.args.get(3) {
1415 zelf.set_attr("winerror", winerror.clone(), vm)?;
1416 }
1417 if let Some(filename2) = new_args.args.get(4) {
1418 zelf.set_attr("filename2", filename2.clone(), vm)?;
1419 }
1420
1421 new_args.args.truncate(2);
1422 }
1423 PyBaseException::slot_init(zelf, new_args, vm)
1424 }
1425
1426 #[pymethod(magic)]
1427 fn str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
1428 let args = exc.args();
1429 let obj = exc.as_object().to_owned();
1430
1431 if args.len() == 2 {
1432 let errno = exc.get_arg(0).unwrap().str(vm)?;
1434 let msg = exc.get_arg(1).unwrap().str(vm)?;
1435
1436 let s = match obj.get_attr("filename", vm) {
1437 Ok(filename) => match obj.get_attr("filename2", vm) {
1438 Ok(filename2) if !vm.is_none(&filename2) => format!(
1439 "[Errno {}] {}: '{}' -> '{}'",
1440 errno,
1441 msg,
1442 filename.str(vm)?,
1443 filename2.str(vm)?
1444 ),
1445 _ => format!("[Errno {}] {}: '{}'", errno, msg, filename.str(vm)?),
1446 },
1447 Err(_) => {
1448 format!("[Errno {errno}] {msg}")
1449 }
1450 };
1451 Ok(vm.ctx.new_str(s))
1452 } else {
1453 Ok(exc.str(vm))
1454 }
1455 }
1456
1457 #[pymethod(magic)]
1458 fn reduce(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyTupleRef {
1459 let args = exc.args();
1460 let obj = exc.as_object().to_owned();
1461 let mut result: Vec<PyObjectRef> = vec![obj.class().to_owned().into()];
1462
1463 if args.len() >= 2 && args.len() <= 5 {
1464 let errno = exc.get_arg(0).unwrap();
1466 let msg = exc.get_arg(1).unwrap();
1467
1468 if let Ok(filename) = obj.get_attr("filename", vm) {
1469 if !vm.is_none(&filename) {
1470 let mut args_reduced: Vec<PyObjectRef> = vec![errno, msg, filename];
1471
1472 if let Ok(filename2) = obj.get_attr("filename2", vm) {
1473 if !vm.is_none(&filename2) {
1474 args_reduced.push(filename2);
1475 }
1476 }
1477 result.push(args_reduced.into_pytuple(vm).into());
1478 } else {
1479 result.push(vm.new_tuple((errno, msg)).into());
1480 }
1481 } else {
1482 result.push(vm.new_tuple((errno, msg)).into());
1483 }
1484 } else {
1485 result.push(args.into());
1486 }
1487
1488 if let Some(dict) = obj.dict().filter(|x| !x.is_empty()) {
1489 result.push(dict.into());
1490 }
1491 result.into_pytuple(vm)
1492 }
1493 }
1494
1495 #[pyexception(name, base = "PyOSError", ctx = "blocking_io_error", impl)]
1496 #[derive(Debug)]
1497 pub struct PyBlockingIOError {}
1498
1499 #[pyexception(name, base = "PyOSError", ctx = "child_process_error", impl)]
1500 #[derive(Debug)]
1501 pub struct PyChildProcessError {}
1502
1503 #[pyexception(name, base = "PyOSError", ctx = "connection_error", impl)]
1504 #[derive(Debug)]
1505 pub struct PyConnectionError {}
1506
1507 #[pyexception(name, base = "PyConnectionError", ctx = "broken_pipe_error", impl)]
1508 #[derive(Debug)]
1509 pub struct PyBrokenPipeError {}
1510
1511 #[pyexception(
1512 name,
1513 base = "PyConnectionError",
1514 ctx = "connection_aborted_error",
1515 impl
1516 )]
1517 #[derive(Debug)]
1518 pub struct PyConnectionAbortedError {}
1519
1520 #[pyexception(
1521 name,
1522 base = "PyConnectionError",
1523 ctx = "connection_refused_error",
1524 impl
1525 )]
1526 #[derive(Debug)]
1527 pub struct PyConnectionRefusedError {}
1528
1529 #[pyexception(name, base = "PyConnectionError", ctx = "connection_reset_error", impl)]
1530 #[derive(Debug)]
1531 pub struct PyConnectionResetError {}
1532
1533 #[pyexception(name, base = "PyOSError", ctx = "file_exists_error", impl)]
1534 #[derive(Debug)]
1535 pub struct PyFileExistsError {}
1536
1537 #[pyexception(name, base = "PyOSError", ctx = "file_not_found_error", impl)]
1538 #[derive(Debug)]
1539 pub struct PyFileNotFoundError {}
1540
1541 #[pyexception(name, base = "PyOSError", ctx = "interrupted_error", impl)]
1542 #[derive(Debug)]
1543 pub struct PyInterruptedError {}
1544
1545 #[pyexception(name, base = "PyOSError", ctx = "is_a_directory_error", impl)]
1546 #[derive(Debug)]
1547 pub struct PyIsADirectoryError {}
1548
1549 #[pyexception(name, base = "PyOSError", ctx = "not_a_directory_error", impl)]
1550 #[derive(Debug)]
1551 pub struct PyNotADirectoryError {}
1552
1553 #[pyexception(name, base = "PyOSError", ctx = "permission_error", impl)]
1554 #[derive(Debug)]
1555 pub struct PyPermissionError {}
1556
1557 #[pyexception(name, base = "PyOSError", ctx = "process_lookup_error", impl)]
1558 #[derive(Debug)]
1559 pub struct PyProcessLookupError {}
1560
1561 #[pyexception(name, base = "PyOSError", ctx = "timeout_error", impl)]
1562 #[derive(Debug)]
1563 pub struct PyTimeoutError {}
1564
1565 #[pyexception(name, base = "PyException", ctx = "reference_error", impl)]
1566 #[derive(Debug)]
1567 pub struct PyReferenceError {}
1568
1569 #[pyexception(name, base = "PyException", ctx = "runtime_error", impl)]
1570 #[derive(Debug)]
1571 pub struct PyRuntimeError {}
1572
1573 #[pyexception(name, base = "PyRuntimeError", ctx = "not_implemented_error", impl)]
1574 #[derive(Debug)]
1575 pub struct PyNotImplementedError {}
1576
1577 #[pyexception(name, base = "PyRuntimeError", ctx = "recursion_error", impl)]
1578 #[derive(Debug)]
1579 pub struct PyRecursionError {}
1580
1581 #[pyexception(name, base = "PyException", ctx = "syntax_error")]
1582 #[derive(Debug)]
1583 pub struct PySyntaxError {}
1584
1585 #[pyexception]
1586 impl PySyntaxError {
1587 #[pymethod(magic)]
1588 fn str(exc: PyBaseExceptionRef, vm: &VirtualMachine) -> PyStrRef {
1589 fn basename(filename: &str) -> &str {
1590 let splitted = if cfg!(windows) {
1591 filename.rsplit(&['/', '\\']).next()
1592 } else {
1593 filename.rsplit('/').next()
1594 };
1595 splitted.unwrap_or(filename)
1596 }
1597
1598 let maybe_lineno = exc.as_object().get_attr("lineno", vm).ok().map(|obj| {
1599 obj.str(vm)
1600 .unwrap_or_else(|_| vm.ctx.new_str("<lineno str() failed>"))
1601 });
1602 let maybe_filename = exc.as_object().get_attr("filename", vm).ok().map(|obj| {
1603 obj.str(vm)
1604 .unwrap_or_else(|_| vm.ctx.new_str("<filename str() failed>"))
1605 });
1606
1607 let args = exc.args();
1608
1609 let msg = if args.len() == 1 {
1610 vm.exception_args_as_string(args, false)
1611 .into_iter()
1612 .exactly_one()
1613 .unwrap()
1614 } else {
1615 return exc.str(vm);
1616 };
1617
1618 let msg_with_location_info: String = match (maybe_lineno, maybe_filename) {
1619 (Some(lineno), Some(filename)) => {
1620 format!("{} ({}, line {})", msg, basename(filename.as_str()), lineno)
1621 }
1622 (Some(lineno), None) => {
1623 format!("{} (line {})", msg, lineno)
1624 }
1625 (None, Some(filename)) => {
1626 format!("{} ({})", msg, basename(filename.as_str()))
1627 }
1628 (None, None) => msg.to_string(),
1629 };
1630
1631 vm.ctx.new_str(msg_with_location_info)
1632 }
1633 }
1634
1635 #[pyexception(name, base = "PySyntaxError", ctx = "indentation_error", impl)]
1636 #[derive(Debug)]
1637 pub struct PyIndentationError {}
1638
1639 #[pyexception(name, base = "PyIndentationError", ctx = "tab_error", impl)]
1640 #[derive(Debug)]
1641 pub struct PyTabError {}
1642
1643 #[pyexception(name, base = "PyException", ctx = "system_error", impl)]
1644 #[derive(Debug)]
1645 pub struct PySystemError {}
1646
1647 #[pyexception(name, base = "PyException", ctx = "type_error", impl)]
1648 #[derive(Debug)]
1649 pub struct PyTypeError {}
1650
1651 #[pyexception(name, base = "PyException", ctx = "value_error", impl)]
1652 #[derive(Debug)]
1653 pub struct PyValueError {}
1654
1655 #[pyexception(name, base = "PyValueError", ctx = "unicode_error", impl)]
1656 #[derive(Debug)]
1657 pub struct PyUnicodeError {}
1658
1659 #[pyexception(name, base = "PyUnicodeError", ctx = "unicode_decode_error", impl)]
1660 #[derive(Debug)]
1661 pub struct PyUnicodeDecodeError {}
1662
1663 #[pyexception(name, base = "PyUnicodeError", ctx = "unicode_encode_error", impl)]
1664 #[derive(Debug)]
1665 pub struct PyUnicodeEncodeError {}
1666
1667 #[pyexception(name, base = "PyUnicodeError", ctx = "unicode_translate_error", impl)]
1668 #[derive(Debug)]
1669 pub struct PyUnicodeTranslateError {}
1670
1671 #[cfg(feature = "jit")]
1673 #[pyexception(name, base = "PyException", ctx = "jit_error", impl)]
1674 #[derive(Debug)]
1675 pub struct PyJitError {}
1676
1677 #[pyexception(name, base = "PyException", ctx = "warning", impl)]
1679 #[derive(Debug)]
1680 pub struct PyWarning {}
1681
1682 #[pyexception(name, base = "PyWarning", ctx = "deprecation_warning", impl)]
1683 #[derive(Debug)]
1684 pub struct PyDeprecationWarning {}
1685
1686 #[pyexception(name, base = "PyWarning", ctx = "pending_deprecation_warning", impl)]
1687 #[derive(Debug)]
1688 pub struct PyPendingDeprecationWarning {}
1689
1690 #[pyexception(name, base = "PyWarning", ctx = "runtime_warning", impl)]
1691 #[derive(Debug)]
1692 pub struct PyRuntimeWarning {}
1693
1694 #[pyexception(name, base = "PyWarning", ctx = "syntax_warning", impl)]
1695 #[derive(Debug)]
1696 pub struct PySyntaxWarning {}
1697
1698 #[pyexception(name, base = "PyWarning", ctx = "user_warning", impl)]
1699 #[derive(Debug)]
1700 pub struct PyUserWarning {}
1701
1702 #[pyexception(name, base = "PyWarning", ctx = "future_warning", impl)]
1703 #[derive(Debug)]
1704 pub struct PyFutureWarning {}
1705
1706 #[pyexception(name, base = "PyWarning", ctx = "import_warning", impl)]
1707 #[derive(Debug)]
1708 pub struct PyImportWarning {}
1709
1710 #[pyexception(name, base = "PyWarning", ctx = "unicode_warning", impl)]
1711 #[derive(Debug)]
1712 pub struct PyUnicodeWarning {}
1713
1714 #[pyexception(name, base = "PyWarning", ctx = "bytes_warning", impl)]
1715 #[derive(Debug)]
1716 pub struct PyBytesWarning {}
1717
1718 #[pyexception(name, base = "PyWarning", ctx = "resource_warning", impl)]
1719 #[derive(Debug)]
1720 pub struct PyResourceWarning {}
1721
1722 #[pyexception(name, base = "PyWarning", ctx = "encoding_warning", impl)]
1723 #[derive(Debug)]
1724 pub struct PyEncodingWarning {}
1725}