(
&self,
output: &mut W,
exc: &Py<PyBaseException>,
seen: &mut HashSet<usize>,
)
| 86 | } |
| 87 | |
| 88 | fn write_exception_recursive<W: Write>( |
| 89 | &self, |
| 90 | output: &mut W, |
| 91 | exc: &Py<PyBaseException>, |
| 92 | seen: &mut HashSet<usize>, |
| 93 | ) -> Result<(), W::Error> { |
| 94 | // This function should not be called directly, |
| 95 | // use `wite_exception` as a public interface. |
| 96 | // It is similar to `print_exception_recursive` from `CPython`. |
| 97 | seen.insert(exc.get_id()); |
| 98 | |
| 99 | #[allow(clippy::manual_map)] |
| 100 | if let Some((cause_or_context, msg)) = if let Some(cause) = exc.__cause__() { |
| 101 | // This can be a special case: `raise e from e`, |
| 102 | // we just ignore it and treat like `raise e` without any extra steps. |
| 103 | Some(( |
| 104 | cause, |
| 105 | "\nThe above exception was the direct cause of the following exception:\n", |
| 106 | )) |
| 107 | } else if let Some(context) = exc.__context__() { |
| 108 | // This can be a special case: |
| 109 | // e = ValueError('e') |
| 110 | // e.__context__ = e |
| 111 | // In this case, we just ignore |
| 112 | // `__context__` part from going into recursion. |
| 113 | Some(( |
| 114 | context, |
| 115 | "\nDuring handling of the above exception, another exception occurred:\n", |
| 116 | )) |
| 117 | } else { |
| 118 | None |
| 119 | } { |
| 120 | if !seen.contains(&cause_or_context.get_id()) { |
| 121 | self.write_exception_recursive(output, &cause_or_context, seen)?; |
| 122 | writeln!(output, "{msg}")?; |
| 123 | } else { |
| 124 | seen.insert(cause_or_context.get_id()); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | self.write_exception_inner(output, exc) |
| 129 | } |
| 130 | |
| 131 | /// Print exception with traceback |
| 132 | pub fn write_exception_inner<W: Write>( |
no test coverage detected