1use crate::{ffi, Bound, PyResult, Python};
13use std::ffi::CStr;
14use std::ops;
15
16#[doc(hidden)]
18#[macro_export]
19macro_rules! impl_exception_boilerplate {
20 ($name: ident) => {
21 impl $name {
22 #[inline]
26 #[allow(dead_code, reason = "user may not call this function")]
27 pub fn new_err<A>(args: A) -> $crate::PyErr
28 where
29 A: $crate::PyErrArguments + ::std::marker::Send + ::std::marker::Sync + 'static,
30 {
31 $crate::PyErr::new::<$name, A>(args)
32 }
33 }
34
35 impl $crate::ToPyErr for $name {}
36 };
37}
38
39#[macro_export]
66macro_rules! import_exception {
67 ($module: expr, $name: ident) => {
68 #[repr(transparent)]
75 #[allow(non_camel_case_types, reason = "matches imported exception name, e.g. `socket.herror`")]
76 pub struct $name($crate::PyAny);
77
78 $crate::impl_exception_boilerplate!($name);
79
80 $crate::pyobject_native_type_core!(
81 $name,
82 $name::type_object_raw,
83 stringify!($name),
84 stringify!($module),
85 #module=::std::option::Option::Some(stringify!($module))
86 );
87
88 impl $name {
89 fn type_object_raw(py: $crate::Python<'_>) -> *mut $crate::ffi::PyTypeObject {
90 use $crate::types::PyTypeMethods;
91 static TYPE_OBJECT: $crate::impl_::exceptions::ImportedExceptionTypeObject =
92 $crate::impl_::exceptions::ImportedExceptionTypeObject::new(stringify!($module), stringify!($name));
93 TYPE_OBJECT.get(py).as_type_ptr()
94 }
95 }
96 };
97}
98
99#[macro_export]
101#[deprecated(since = "0.27.0", note = "renamed to `import_exception!` instead")]
102macro_rules! import_exception_bound {
103 ($module: expr, $name: ident) => {
104 $crate::import_exception!($module, $name);
105 };
106}
107
108#[macro_export]
175macro_rules! create_exception {
176 ($module: expr, $name: ident, $base: ty) => {
177 #[repr(transparent)]
178 pub struct $name($crate::PyAny);
179
180 $crate::impl_exception_boilerplate!($name);
181
182 $crate::create_exception_type_object!($module, $name, $base, None);
183 };
184 ($module: expr, $name: ident, $base: ty, $doc: expr) => {
185 #[repr(transparent)]
186 #[doc = $doc]
187 pub struct $name($crate::PyAny);
188
189 $crate::impl_exception_boilerplate!($name);
190
191 $crate::create_exception_type_object!($module, $name, $base, Some($doc));
192 };
193}
194
195#[doc(hidden)]
198#[macro_export]
199macro_rules! create_exception_type_object {
200 ($module: expr, $name: ident, $base: ty, None) => {
201 $crate::create_exception_type_object!($module, $name, $base, ::std::option::Option::None);
202 };
203 ($module: expr, $name: ident, $base: ty, Some($doc: expr)) => {
204 $crate::create_exception_type_object!(
205 $module,
206 $name,
207 $base,
208 ::std::option::Option::Some($crate::ffi::c_str!($doc))
209 );
210 };
211 ($module: expr, $name: ident, $base: ty, $doc: expr) => {
212 $crate::pyobject_native_type_named!($name);
213
214 unsafe impl $crate::type_object::PyTypeInfo for $name {
216 const NAME: &'static str = stringify!($name);
217 const MODULE: ::std::option::Option<&'static str> =
218 ::std::option::Option::Some(stringify!($module));
219 $crate::create_exception_type_hint!($module, $name);
220
221 #[inline]
222 #[allow(clippy::redundant_closure_call)]
223 fn type_object_raw(py: $crate::Python<'_>) -> *mut $crate::ffi::PyTypeObject {
224 use $crate::sync::PyOnceLock;
225 static TYPE_OBJECT: PyOnceLock<$crate::Py<$crate::types::PyType>> =
226 PyOnceLock::new();
227
228 TYPE_OBJECT
229 .get_or_init(py, || {
230 $crate::PyErr::new_type(
231 py,
232 $crate::ffi::c_str!(concat!(
233 stringify!($module),
234 ".",
235 stringify!($name)
236 )),
237 $doc,
238 ::std::option::Option::Some(&py.get_type::<$base>()),
239 ::std::option::Option::None,
240 )
241 .expect("Failed to initialize new exception type.")
242 })
243 .as_ptr()
244 .cast()
245 }
246 }
247
248 impl $name {
249 #[doc(hidden)]
250 pub const _PYO3_DEF: $crate::impl_::pymodule::AddTypeToModule<Self> =
251 $crate::impl_::pymodule::AddTypeToModule::new();
252
253 #[allow(dead_code)]
254 #[doc(hidden)]
255 pub const _PYO3_INTROSPECTION_ID: &'static str =
256 concat!(stringify!($module), stringify!($name));
257 }
258 };
259}
260
261#[cfg(not(feature = "experimental-inspect"))]
263#[doc(hidden)]
264#[macro_export]
265macro_rules! create_exception_type_hint(
266 ($module: expr, $name: ident) => {};
267);
268
269#[cfg(feature = "experimental-inspect")]
270#[doc(hidden)]
271#[macro_export]
272macro_rules! create_exception_type_hint(
273 ($module: expr, $name: ident) => {
274 const TYPE_HINT: $crate::inspect::PyStaticExpr = $crate::inspect::PyStaticExpr::PyClass($crate::inspect::PyClassNameStaticExpr::new(
275 &$crate::type_hint_identifier!(stringify!($module), stringify!($name)),
276 Self::_PYO3_INTROSPECTION_ID
277 ));
278 };
279);
280
281macro_rules! impl_native_exception (
282 ($name:ident, $exc_name:ident, $python_name:expr, $doc:expr, $layout:path $(, #checkfunction=$checkfunction:path)?) => (
283 #[doc = $doc]
284 #[repr(transparent)]
285 #[allow(clippy::upper_case_acronyms, reason = "Python exception names")]
286 pub struct $name($crate::PyAny);
287
288 $crate::impl_exception_boilerplate!($name);
289 $crate::pyobject_native_type!($name, $layout, |_py| unsafe { $crate::ffi::$exc_name as *mut $crate::ffi::PyTypeObject }, "builtins", $python_name $(, #checkfunction=$checkfunction)?);
290 $crate::pyobject_subclassable_native_type!($name, $layout);
291 );
292 ($name:ident, $exc_name:ident, $python_name:expr, $doc:expr) => (
293 impl_native_exception!($name, $exc_name, $python_name, $doc, $crate::ffi::PyBaseExceptionObject);
294 )
295);
296
297#[cfg(windows)]
298macro_rules! impl_windows_native_exception (
299 ($name:ident, $exc_name:ident, $python_name:expr, $doc:expr, $layout:path) => (
300 #[cfg(windows)]
301 #[doc = $doc]
302 #[repr(transparent)]
303 #[allow(clippy::upper_case_acronyms, reason = "Python exception names")]
304 pub struct $name($crate::PyAny);
305
306 $crate::impl_exception_boilerplate!($name);
307 $crate::pyobject_native_type!($name, $layout, |_py| unsafe { $crate::ffi::$exc_name as *mut $crate::ffi::PyTypeObject }, "builtins", $python_name);
308 );
309 ($name:ident, $exc_name:ident, $python_name:expr, $doc:expr) => (
310 impl_windows_native_exception!($name, $exc_name, $python_name, $doc, $crate::ffi::PyBaseExceptionObject);
311 )
312);
313
314macro_rules! native_doc(
315 ($name: literal, $alt: literal) => (
316 concat!(
317"Represents Python's [`", $name, "`](https://docs.python.org/3/library/exceptions.html#", $name, ") exception.
318
319", $alt
320 )
321 );
322 ($name: literal) => (
323 concat!(
324"
325Represents Python's [`", $name, "`](https://docs.python.org/3/library/exceptions.html#", $name, ") exception.
326
327# Example: Raising ", $name, " from Rust
328
329This exception can be sent to Python code by converting it into a
330[`PyErr`](crate::PyErr), where Python code can then catch it.
331```
332use pyo3::prelude::*;
333use pyo3::exceptions::Py", $name, ";
334
335#[pyfunction]
336fn always_throws() -> PyResult<()> {
337 let message = \"I'm ", $name ,", and I was raised from Rust.\";
338 Err(Py", $name, "::new_err(message))
339}
340#
341# Python::attach(|py| {
342# let fun = pyo3::wrap_pyfunction!(always_throws, py).unwrap();
343# let err = fun.call0().expect_err(\"called a function that should always return an error but the return value was Ok\");
344# assert!(err.is_instance_of::<Py", $name, ">(py))
345# });
346```
347
348Python code:
349 ```python
350 from my_module import always_throws
351
352try:
353 always_throws()
354except ", $name, " as e:
355 print(f\"Caught an exception: {e}\")
356```
357
358# Example: Catching ", $name, " in Rust
359
360```
361use pyo3::prelude::*;
362use pyo3::exceptions::Py", $name, ";
363use pyo3::ffi::c_str;
364
365Python::attach(|py| {
366 let result: PyResult<()> = py.run(c_str!(\"raise ", $name, "\"), None, None);
367
368 let error_type = match result {
369 Ok(_) => \"Not an error\",
370 Err(error) if error.is_instance_of::<Py", $name, ">(py) => \"" , $name, "\",
371 Err(_) => \"Some other error\",
372 };
373
374 assert_eq!(error_type, \"", $name, "\");
375});
376```
377"
378 )
379 );
380);
381
382impl_native_exception!(
383 PyBaseException,
384 PyExc_BaseException,
385 "BaseException",
386 native_doc!("BaseException"),
387 ffi::PyBaseExceptionObject,
388 #checkfunction=ffi::PyExceptionInstance_Check
389);
390impl_native_exception!(
391 PyException,
392 PyExc_Exception,
393 "Exception",
394 native_doc!("Exception")
395);
396impl_native_exception!(
397 PyStopAsyncIteration,
398 PyExc_StopAsyncIteration,
399 "StopAsyncIteration",
400 native_doc!("StopAsyncIteration")
401);
402impl_native_exception!(
403 PyStopIteration,
404 PyExc_StopIteration,
405 "StopIteration",
406 native_doc!("StopIteration"),
407 ffi::PyStopIterationObject
408);
409impl_native_exception!(
410 PyGeneratorExit,
411 PyExc_GeneratorExit,
412 "GeneratorExit",
413 native_doc!("GeneratorExit")
414);
415impl_native_exception!(
416 PyArithmeticError,
417 PyExc_ArithmeticError,
418 "ArithmeticError",
419 native_doc!("ArithmeticError")
420);
421impl_native_exception!(
422 PyLookupError,
423 PyExc_LookupError,
424 "LookupError",
425 native_doc!("LookupError")
426);
427
428impl_native_exception!(
429 PyAssertionError,
430 PyExc_AssertionError,
431 "AssertionError",
432 native_doc!("AssertionError")
433);
434impl_native_exception!(
435 PyAttributeError,
436 PyExc_AttributeError,
437 "AttributeError",
438 native_doc!("AttributeError")
439);
440impl_native_exception!(
441 PyBufferError,
442 PyExc_BufferError,
443 "BufferError",
444 native_doc!("BufferError")
445);
446impl_native_exception!(
447 PyEOFError,
448 PyExc_EOFError,
449 "EOFError",
450 native_doc!("EOFError")
451);
452impl_native_exception!(
453 PyFloatingPointError,
454 PyExc_FloatingPointError,
455 "FloatingPointError",
456 native_doc!("FloatingPointError")
457);
458#[cfg(not(any(PyPy, GraalPy)))]
459impl_native_exception!(
460 PyOSError,
461 PyExc_OSError,
462 "OSError",
463 native_doc!("OSError"),
464 ffi::PyOSErrorObject
465);
466#[cfg(any(PyPy, GraalPy))]
467impl_native_exception!(PyOSError, PyExc_OSError, "OSError", native_doc!("OSError"));
468impl_native_exception!(
469 PyImportError,
470 PyExc_ImportError,
471 "ImportError",
472 native_doc!("ImportError")
473);
474
475impl_native_exception!(
476 PyModuleNotFoundError,
477 PyExc_ModuleNotFoundError,
478 "ModuleNotFoundError",
479 native_doc!("ModuleNotFoundError")
480);
481
482impl_native_exception!(
483 PyIndexError,
484 PyExc_IndexError,
485 "IndexError",
486 native_doc!("IndexError")
487);
488impl_native_exception!(
489 PyKeyError,
490 PyExc_KeyError,
491 "KeyError",
492 native_doc!("KeyError")
493);
494impl_native_exception!(
495 PyKeyboardInterrupt,
496 PyExc_KeyboardInterrupt,
497 "KeyboardInterrupt",
498 native_doc!("KeyboardInterrupt")
499);
500impl_native_exception!(
501 PyMemoryError,
502 PyExc_MemoryError,
503 "MemoryError",
504 native_doc!("MemoryError")
505);
506impl_native_exception!(
507 PyNameError,
508 PyExc_NameError,
509 "NameError",
510 native_doc!("NameError")
511);
512impl_native_exception!(
513 PyOverflowError,
514 PyExc_OverflowError,
515 "OverflowError",
516 native_doc!("OverflowError")
517);
518impl_native_exception!(
519 PyRuntimeError,
520 PyExc_RuntimeError,
521 "RuntimeError",
522 native_doc!("RuntimeError")
523);
524impl_native_exception!(
525 PyRecursionError,
526 PyExc_RecursionError,
527 "RecursionError",
528 native_doc!("RecursionError")
529);
530impl_native_exception!(
531 PyNotImplementedError,
532 PyExc_NotImplementedError,
533 "NotImplementedError",
534 native_doc!("NotImplementedError")
535);
536#[cfg(not(any(PyPy, GraalPy)))]
537impl_native_exception!(
538 PySyntaxError,
539 PyExc_SyntaxError,
540 "SyntaxError",
541 native_doc!("SyntaxError"),
542 ffi::PySyntaxErrorObject
543);
544#[cfg(any(PyPy, GraalPy))]
545impl_native_exception!(
546 PySyntaxError,
547 PyExc_SyntaxError,
548 "SyntaxError",
549 native_doc!("SyntaxError")
550);
551impl_native_exception!(
552 PyReferenceError,
553 PyExc_ReferenceError,
554 "ReferenceError",
555 native_doc!("ReferenceError")
556);
557impl_native_exception!(
558 PySystemError,
559 PyExc_SystemError,
560 "SystemError",
561 native_doc!("SystemError")
562);
563#[cfg(not(any(PyPy, GraalPy)))]
564impl_native_exception!(
565 PySystemExit,
566 PyExc_SystemExit,
567 "SystemExit",
568 native_doc!("SystemExit"),
569 ffi::PySystemExitObject
570);
571#[cfg(any(PyPy, GraalPy))]
572impl_native_exception!(
573 PySystemExit,
574 PyExc_SystemExit,
575 "SystemExit",
576 native_doc!("SystemExit")
577);
578impl_native_exception!(
579 PyTypeError,
580 PyExc_TypeError,
581 "TypeError",
582 native_doc!("TypeError")
583);
584impl_native_exception!(
585 PyUnboundLocalError,
586 PyExc_UnboundLocalError,
587 "UnboundLocalError",
588 native_doc!("UnboundLocalError")
589);
590#[cfg(not(any(PyPy, GraalPy)))]
591impl_native_exception!(
592 PyUnicodeError,
593 PyExc_UnicodeError,
594 "UnicodeError",
595 native_doc!("UnicodeError"),
596 ffi::PyUnicodeErrorObject
597);
598#[cfg(any(PyPy, GraalPy))]
599impl_native_exception!(
600 PyUnicodeError,
601 PyExc_UnicodeError,
602 "UnicodeError",
603 native_doc!("UnicodeError")
604);
605impl_native_exception!(
607 PyUnicodeDecodeError,
608 PyExc_UnicodeDecodeError,
609 "UnicodeDecodeError",
610 native_doc!("UnicodeDecodeError", "")
611);
612impl_native_exception!(
613 PyUnicodeEncodeError,
614 PyExc_UnicodeEncodeError,
615 "UnicodeEncodeError",
616 native_doc!("UnicodeEncodeError", "")
617);
618impl_native_exception!(
619 PyUnicodeTranslateError,
620 PyExc_UnicodeTranslateError,
621 "UnicodeTranslateError",
622 native_doc!("UnicodeTranslateError", "")
623);
624#[cfg(Py_3_11)]
625impl_native_exception!(
626 PyBaseExceptionGroup,
627 PyExc_BaseExceptionGroup,
628 "BaseExceptionGroup",
629 native_doc!("BaseExceptionGroup", "")
630);
631impl_native_exception!(
632 PyValueError,
633 PyExc_ValueError,
634 "ValueError",
635 native_doc!("ValueError")
636);
637impl_native_exception!(
638 PyZeroDivisionError,
639 PyExc_ZeroDivisionError,
640 "ZeroDivisionError",
641 native_doc!("ZeroDivisionError")
642);
643
644impl_native_exception!(
645 PyBlockingIOError,
646 PyExc_BlockingIOError,
647 "BlockingIOError",
648 native_doc!("BlockingIOError")
649);
650impl_native_exception!(
651 PyBrokenPipeError,
652 PyExc_BrokenPipeError,
653 "BrokenPipeError",
654 native_doc!("BrokenPipeError")
655);
656impl_native_exception!(
657 PyChildProcessError,
658 PyExc_ChildProcessError,
659 "ChildProcessError",
660 native_doc!("ChildProcessError")
661);
662impl_native_exception!(
663 PyConnectionError,
664 PyExc_ConnectionError,
665 "ConnectionError",
666 native_doc!("ConnectionError")
667);
668impl_native_exception!(
669 PyConnectionAbortedError,
670 PyExc_ConnectionAbortedError,
671 "ConnectionAbortedError",
672 native_doc!("ConnectionAbortedError")
673);
674impl_native_exception!(
675 PyConnectionRefusedError,
676 PyExc_ConnectionRefusedError,
677 "ConnectionRefusedError",
678 native_doc!("ConnectionRefusedError")
679);
680impl_native_exception!(
681 PyConnectionResetError,
682 PyExc_ConnectionResetError,
683 "ConnectionResetError",
684 native_doc!("ConnectionResetError")
685);
686impl_native_exception!(
687 PyFileExistsError,
688 PyExc_FileExistsError,
689 "FileExistsError",
690 native_doc!("FileExistsError")
691);
692impl_native_exception!(
693 PyFileNotFoundError,
694 PyExc_FileNotFoundError,
695 "FileNotFoundError",
696 native_doc!("FileNotFoundError")
697);
698impl_native_exception!(
699 PyInterruptedError,
700 PyExc_InterruptedError,
701 "InterruptedError",
702 native_doc!("InterruptedError")
703);
704impl_native_exception!(
705 PyIsADirectoryError,
706 PyExc_IsADirectoryError,
707 "IsADirectoryError",
708 native_doc!("IsADirectoryError")
709);
710impl_native_exception!(
711 PyNotADirectoryError,
712 PyExc_NotADirectoryError,
713 "NotADirectoryError",
714 native_doc!("NotADirectoryError")
715);
716impl_native_exception!(
717 PyPermissionError,
718 PyExc_PermissionError,
719 "PermissionError",
720 native_doc!("PermissionError")
721);
722impl_native_exception!(
723 PyProcessLookupError,
724 PyExc_ProcessLookupError,
725 "ProcessLookupError",
726 native_doc!("ProcessLookupError")
727);
728impl_native_exception!(
729 PyTimeoutError,
730 PyExc_TimeoutError,
731 "TimeoutError",
732 native_doc!("TimeoutError")
733);
734
735impl_native_exception!(
736 PyEnvironmentError,
737 PyExc_EnvironmentError,
738 "EnvironmentError",
739 native_doc!("EnvironmentError")
740);
741impl_native_exception!(PyIOError, PyExc_IOError, "IOError", native_doc!("IOError"));
742
743#[cfg(windows)]
744impl_windows_native_exception!(
745 PyWindowsError,
746 PyExc_WindowsError,
747 "WindowsError",
748 native_doc!("WindowsError")
749);
750
751impl PyUnicodeDecodeError {
752 pub fn new<'py>(
754 py: Python<'py>,
755 encoding: &CStr,
756 input: &[u8],
757 range: ops::Range<usize>,
758 reason: &CStr,
759 ) -> PyResult<Bound<'py, PyUnicodeDecodeError>> {
760 use crate::ffi_ptr_ext::FfiPtrExt;
761 use crate::py_result_ext::PyResultExt;
762 unsafe {
763 ffi::PyUnicodeDecodeError_Create(
764 encoding.as_ptr(),
765 input.as_ptr().cast(),
766 input.len() as ffi::Py_ssize_t,
767 range.start as ffi::Py_ssize_t,
768 range.end as ffi::Py_ssize_t,
769 reason.as_ptr(),
770 )
771 .assume_owned_or_err(py)
772 }
773 .cast_into()
774 }
775
776 pub fn new_utf8<'py>(
798 py: Python<'py>,
799 input: &[u8],
800 err: std::str::Utf8Error,
801 ) -> PyResult<Bound<'py, PyUnicodeDecodeError>> {
802 let pos = err.valid_up_to();
803 PyUnicodeDecodeError::new(py, c"utf-8", input, pos..(pos + 1), c"invalid utf-8")
804 }
805}
806
807impl_native_exception!(PyWarning, PyExc_Warning, "Warning", native_doc!("Warning"));
808impl_native_exception!(
809 PyUserWarning,
810 PyExc_UserWarning,
811 "UserWarning",
812 native_doc!("UserWarning")
813);
814impl_native_exception!(
815 PyDeprecationWarning,
816 PyExc_DeprecationWarning,
817 "DeprecationWarning",
818 native_doc!("DeprecationWarning")
819);
820impl_native_exception!(
821 PyPendingDeprecationWarning,
822 PyExc_PendingDeprecationWarning,
823 "PendingDeprecationWarning",
824 native_doc!("PendingDeprecationWarning")
825);
826impl_native_exception!(
827 PySyntaxWarning,
828 PyExc_SyntaxWarning,
829 "SyntaxWarning",
830 native_doc!("SyntaxWarning")
831);
832impl_native_exception!(
833 PyRuntimeWarning,
834 PyExc_RuntimeWarning,
835 "RuntimeWarning",
836 native_doc!("RuntimeWarning")
837);
838impl_native_exception!(
839 PyFutureWarning,
840 PyExc_FutureWarning,
841 "FutureWarning",
842 native_doc!("FutureWarning")
843);
844impl_native_exception!(
845 PyImportWarning,
846 PyExc_ImportWarning,
847 "ImportWarning",
848 native_doc!("ImportWarning")
849);
850impl_native_exception!(
851 PyUnicodeWarning,
852 PyExc_UnicodeWarning,
853 "UnicodeWarning",
854 native_doc!("UnicodeWarning")
855);
856impl_native_exception!(
857 PyBytesWarning,
858 PyExc_BytesWarning,
859 "BytesWarning",
860 native_doc!("BytesWarning")
861);
862impl_native_exception!(
863 PyResourceWarning,
864 PyExc_ResourceWarning,
865 "ResourceWarning",
866 native_doc!("ResourceWarning")
867);
868
869#[cfg(Py_3_10)]
870impl_native_exception!(
871 PyEncodingWarning,
872 PyExc_EncodingWarning,
873 "EncodingWarning",
874 native_doc!("EncodingWarning")
875);
876
877#[cfg(test)]
878macro_rules! test_exception {
879 ($exc_ty:ident $(, |$py:tt| $constructor:expr )?) => {
880 #[allow(non_snake_case, reason = "test matches exception name")]
881 #[test]
882 fn $exc_ty () {
883 use super::$exc_ty;
884
885 $crate::Python::attach(|py| {
886 let err: $crate::PyErr = {
887 None
888 $(
889 .or(Some({ let $py = py; $constructor }))
890 )?
891 .unwrap_or($exc_ty::new_err("a test exception"))
892 };
893
894 assert!(err.is_instance_of::<$exc_ty>(py));
895
896 let value = err.value(py).as_any().cast::<$exc_ty>().unwrap();
897
898 assert!($crate::PyErr::from(value.clone()).is_instance_of::<$exc_ty>(py));
899 })
900 }
901 };
902}
903
904pub mod asyncio {
907 import_exception!(asyncio, CancelledError);
908 import_exception!(asyncio, InvalidStateError);
909 import_exception!(asyncio, TimeoutError);
910 import_exception!(asyncio, IncompleteReadError);
911 import_exception!(asyncio, LimitOverrunError);
912 import_exception!(asyncio, QueueEmpty);
913 import_exception!(asyncio, QueueFull);
914
915 #[cfg(test)]
916 mod tests {
917 test_exception!(CancelledError);
918 test_exception!(InvalidStateError);
919 test_exception!(TimeoutError);
920 test_exception!(IncompleteReadError, |_| IncompleteReadError::new_err((
921 "partial", "expected"
922 )));
923 test_exception!(LimitOverrunError, |_| LimitOverrunError::new_err((
924 "message", "consumed"
925 )));
926 test_exception!(QueueEmpty);
927 test_exception!(QueueFull);
928 }
929}
930
931pub mod socket {
934 import_exception!(socket, herror);
935 import_exception!(socket, gaierror);
936 import_exception!(socket, timeout);
937
938 #[cfg(test)]
939 mod tests {
940 test_exception!(herror);
941 test_exception!(gaierror);
942 test_exception!(timeout);
943 }
944}
945
946#[cfg(test)]
947mod tests {
948 use super::*;
949 use crate::types::any::PyAnyMethods;
950 use crate::types::{IntoPyDict, PyDict};
951 use crate::PyErr;
952
953 import_exception!(socket, gaierror);
954 import_exception!(email.errors, MessageError);
955
956 #[test]
957 fn test_check_exception() {
958 Python::attach(|py| {
959 let err: PyErr = gaierror::new_err(());
960 let socket = py
961 .import("socket")
962 .map_err(|e| e.display(py))
963 .expect("could not import socket");
964
965 let d = PyDict::new(py);
966 d.set_item("socket", socket)
967 .map_err(|e| e.display(py))
968 .expect("could not setitem");
969
970 d.set_item("exc", err)
971 .map_err(|e| e.display(py))
972 .expect("could not setitem");
973
974 py.run(c"assert isinstance(exc, socket.gaierror)", None, Some(&d))
975 .map_err(|e| e.display(py))
976 .expect("assertion failed");
977 });
978 }
979
980 #[test]
981 fn test_check_exception_nested() {
982 Python::attach(|py| {
983 let err: PyErr = MessageError::new_err(());
984 let email = py
985 .import("email")
986 .map_err(|e| e.display(py))
987 .expect("could not import email");
988
989 let d = PyDict::new(py);
990 d.set_item("email", email)
991 .map_err(|e| e.display(py))
992 .expect("could not setitem");
993 d.set_item("exc", err)
994 .map_err(|e| e.display(py))
995 .expect("could not setitem");
996
997 py.run(
998 c"assert isinstance(exc, email.errors.MessageError)",
999 None,
1000 Some(&d),
1001 )
1002 .map_err(|e| e.display(py))
1003 .expect("assertion failed");
1004 });
1005 }
1006
1007 #[test]
1008 fn custom_exception() {
1009 create_exception!(mymodule, CustomError, PyException);
1010
1011 Python::attach(|py| {
1012 let error_type = py.get_type::<CustomError>();
1013 let ctx = [("CustomError", error_type)].into_py_dict(py).unwrap();
1014 let type_description: String = py
1015 .eval(c"str(CustomError)", None, Some(&ctx))
1016 .unwrap()
1017 .extract()
1018 .unwrap();
1019 assert_eq!(type_description, "<class 'mymodule.CustomError'>");
1020 py.run(
1021 c"assert CustomError('oops').args == ('oops',)",
1022 None,
1023 Some(&ctx),
1024 )
1025 .unwrap();
1026 py.run(c"assert CustomError.__doc__ is None", None, Some(&ctx))
1027 .unwrap();
1028 });
1029 }
1030
1031 #[test]
1032 fn custom_exception_dotted_module() {
1033 create_exception!(mymodule.exceptions, CustomError, PyException);
1034 Python::attach(|py| {
1035 let error_type = py.get_type::<CustomError>();
1036 let ctx = [("CustomError", error_type)].into_py_dict(py).unwrap();
1037 let type_description: String = py
1038 .eval(c"str(CustomError)", None, Some(&ctx))
1039 .unwrap()
1040 .extract()
1041 .unwrap();
1042 assert_eq!(
1043 type_description,
1044 "<class 'mymodule.exceptions.CustomError'>"
1045 );
1046 });
1047 }
1048
1049 #[test]
1050 fn custom_exception_doc() {
1051 create_exception!(mymodule, CustomError, PyException, "Some docs");
1052
1053 Python::attach(|py| {
1054 let error_type = py.get_type::<CustomError>();
1055 let ctx = [("CustomError", error_type)].into_py_dict(py).unwrap();
1056 let type_description: String = py
1057 .eval(c"str(CustomError)", None, Some(&ctx))
1058 .unwrap()
1059 .extract()
1060 .unwrap();
1061 assert_eq!(type_description, "<class 'mymodule.CustomError'>");
1062 py.run(
1063 c"assert CustomError('oops').args == ('oops',)",
1064 None,
1065 Some(&ctx),
1066 )
1067 .unwrap();
1068 py.run(
1069 c"assert CustomError.__doc__ == 'Some docs'",
1070 None,
1071 Some(&ctx),
1072 )
1073 .unwrap();
1074 });
1075 }
1076
1077 #[test]
1078 fn custom_exception_doc_expr() {
1079 create_exception!(
1080 mymodule,
1081 CustomError,
1082 PyException,
1083 concat!("Some", " more ", stringify!(docs))
1084 );
1085
1086 Python::attach(|py| {
1087 let error_type = py.get_type::<CustomError>();
1088 let ctx = [("CustomError", error_type)].into_py_dict(py).unwrap();
1089 let type_description: String = py
1090 .eval(c"str(CustomError)", None, Some(&ctx))
1091 .unwrap()
1092 .extract()
1093 .unwrap();
1094 assert_eq!(type_description, "<class 'mymodule.CustomError'>");
1095 py.run(
1096 c"assert CustomError('oops').args == ('oops',)",
1097 None,
1098 Some(&ctx),
1099 )
1100 .unwrap();
1101 py.run(
1102 c"assert CustomError.__doc__ == 'Some more docs'",
1103 None,
1104 Some(&ctx),
1105 )
1106 .unwrap();
1107 });
1108 }
1109
1110 #[test]
1111 fn native_exception_debug() {
1112 Python::attach(|py| {
1113 let exc = py
1114 .run(c"raise Exception('banana')", None, None)
1115 .expect_err("raising should have given us an error")
1116 .into_value(py)
1117 .into_bound(py);
1118 assert_eq!(
1119 format!("{exc:?}"),
1120 exc.repr().unwrap().extract::<String>().unwrap()
1121 );
1122 });
1123 }
1124
1125 #[test]
1126 fn native_exception_display() {
1127 Python::attach(|py| {
1128 let exc = py
1129 .run(c"raise Exception('banana')", None, None)
1130 .expect_err("raising should have given us an error")
1131 .into_value(py)
1132 .into_bound(py);
1133 assert_eq!(
1134 exc.to_string(),
1135 exc.str().unwrap().extract::<String>().unwrap()
1136 );
1137 });
1138 }
1139
1140 #[test]
1141 fn unicode_decode_error() {
1142 let invalid_utf8 = b"fo\xd8o";
1143 #[expect(invalid_from_utf8)]
1144 let err = std::str::from_utf8(invalid_utf8).expect_err("should be invalid utf8");
1145 Python::attach(|py| {
1146 let decode_err = PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err).unwrap();
1147 assert_eq!(
1148 format!("{decode_err:?}"),
1149 "UnicodeDecodeError('utf-8', b'fo\\xd8o', 2, 3, 'invalid utf-8')"
1150 );
1151
1152 let e: PyErr = decode_err.into();
1154 e.restore(py);
1155
1156 assert_eq!(
1157 PyErr::fetch(py).to_string(),
1158 "UnicodeDecodeError: \'utf-8\' codec can\'t decode byte 0xd8 in position 2: invalid utf-8"
1159 );
1160 });
1161 }
1162 #[cfg(Py_3_11)]
1163 test_exception!(PyBaseExceptionGroup, |_| PyBaseExceptionGroup::new_err((
1164 "msg",
1165 vec![PyValueError::new_err("err")]
1166 )));
1167 test_exception!(PyBaseException);
1168 test_exception!(PyException);
1169 test_exception!(PyStopAsyncIteration);
1170 test_exception!(PyStopIteration);
1171 test_exception!(PyGeneratorExit);
1172 test_exception!(PyArithmeticError);
1173 test_exception!(PyLookupError);
1174 test_exception!(PyAssertionError);
1175 test_exception!(PyAttributeError);
1176 test_exception!(PyBufferError);
1177 test_exception!(PyEOFError);
1178 test_exception!(PyFloatingPointError);
1179 test_exception!(PyOSError);
1180 test_exception!(PyImportError);
1181 test_exception!(PyModuleNotFoundError);
1182 test_exception!(PyIndexError);
1183 test_exception!(PyKeyError);
1184 test_exception!(PyKeyboardInterrupt);
1185 test_exception!(PyMemoryError);
1186 test_exception!(PyNameError);
1187 test_exception!(PyOverflowError);
1188 test_exception!(PyRuntimeError);
1189 test_exception!(PyRecursionError);
1190 test_exception!(PyNotImplementedError);
1191 test_exception!(PySyntaxError);
1192 test_exception!(PyReferenceError);
1193 test_exception!(PySystemError);
1194 test_exception!(PySystemExit);
1195 test_exception!(PyTypeError);
1196 test_exception!(PyUnboundLocalError);
1197 test_exception!(PyUnicodeError);
1198 test_exception!(PyUnicodeDecodeError, |py| {
1199 let invalid_utf8 = b"fo\xd8o";
1200 #[expect(invalid_from_utf8)]
1201 let err = std::str::from_utf8(invalid_utf8).expect_err("should be invalid utf8");
1202 PyErr::from_value(
1203 PyUnicodeDecodeError::new_utf8(py, invalid_utf8, err)
1204 .unwrap()
1205 .into_any(),
1206 )
1207 });
1208 test_exception!(PyUnicodeEncodeError, |py| py
1209 .eval(c"chr(40960).encode('ascii')", None, None)
1210 .unwrap_err());
1211 test_exception!(PyUnicodeTranslateError, |_| {
1212 PyUnicodeTranslateError::new_err(("\u{3042}", 0, 1, "ouch"))
1213 });
1214 test_exception!(PyValueError);
1215 test_exception!(PyZeroDivisionError);
1216 test_exception!(PyBlockingIOError);
1217 test_exception!(PyBrokenPipeError);
1218 test_exception!(PyChildProcessError);
1219 test_exception!(PyConnectionError);
1220 test_exception!(PyConnectionAbortedError);
1221 test_exception!(PyConnectionRefusedError);
1222 test_exception!(PyConnectionResetError);
1223 test_exception!(PyFileExistsError);
1224 test_exception!(PyFileNotFoundError);
1225 test_exception!(PyInterruptedError);
1226 test_exception!(PyIsADirectoryError);
1227 test_exception!(PyNotADirectoryError);
1228 test_exception!(PyPermissionError);
1229 test_exception!(PyProcessLookupError);
1230 test_exception!(PyTimeoutError);
1231 test_exception!(PyEnvironmentError);
1232 test_exception!(PyIOError);
1233 #[cfg(windows)]
1234 test_exception!(PyWindowsError);
1235
1236 test_exception!(PyWarning);
1237 test_exception!(PyUserWarning);
1238 test_exception!(PyDeprecationWarning);
1239 test_exception!(PyPendingDeprecationWarning);
1240 test_exception!(PySyntaxWarning);
1241 test_exception!(PyRuntimeWarning);
1242 test_exception!(PyFutureWarning);
1243 test_exception!(PyImportWarning);
1244 test_exception!(PyUnicodeWarning);
1245 test_exception!(PyBytesWarning);
1246 #[cfg(Py_3_10)]
1247 test_exception!(PyEncodingWarning);
1248}