pyo3/err/
downcast_error.rs1#![allow(deprecated)]
2
3use std::borrow::Cow;
4
5use crate::{
6 exceptions,
7 types::{PyAnyMethods, PyStringMethods, PyType, PyTypeMethods},
8 Borrowed, Bound, IntoPyObject, Py, PyAny, PyErr, PyErrArguments, Python,
9};
10
11#[derive(Debug)]
13#[deprecated(since = "0.27.0", note = "replaced with `CastError`")]
14pub struct DowncastError<'a, 'py> {
15 from: Borrowed<'a, 'py, PyAny>,
16 to: Cow<'static, str>,
17}
18
19impl<'a, 'py> DowncastError<'a, 'py> {
20 pub fn new(from: &'a Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
23 Self {
24 from: from.as_borrowed(),
25 to: to.into(),
26 }
27 }
28}
29
30#[derive(Debug)]
32#[deprecated(since = "0.27.0", note = "replaced with `CastIntoError`")]
33pub struct DowncastIntoError<'py> {
34 from: Bound<'py, PyAny>,
35 to: Cow<'static, str>,
36}
37
38impl<'py> DowncastIntoError<'py> {
39 pub fn new(from: Bound<'py, PyAny>, to: impl Into<Cow<'static, str>>) -> Self {
42 Self {
43 from,
44 to: to.into(),
45 }
46 }
47
48 pub fn into_inner(self) -> Bound<'py, PyAny> {
53 self.from
54 }
55}
56
57struct DowncastErrorArguments {
58 from: Py<PyType>,
59 to: Cow<'static, str>,
60}
61
62impl PyErrArguments for DowncastErrorArguments {
63 fn arguments(self, py: Python<'_>) -> Py<PyAny> {
64 let from = self.from.bind(py).qualname();
65 let from = from
66 .as_ref()
67 .map(|name| name.to_string_lossy())
68 .unwrap_or(Cow::Borrowed("<failed to extract type name>"));
69 format!("'{}' object cannot be converted to '{}'", from, self.to)
70 .into_pyobject(py)
71 .unwrap()
72 .into_any()
73 .unbind()
74 }
75}
76
77impl std::convert::From<DowncastError<'_, '_>> for PyErr {
79 fn from(err: DowncastError<'_, '_>) -> PyErr {
80 let args = DowncastErrorArguments {
81 from: err.from.get_type().into(),
82 to: err.to,
83 };
84
85 exceptions::PyTypeError::new_err(args)
86 }
87}
88
89impl std::error::Error for DowncastError<'_, '_> {}
90
91impl std::fmt::Display for DowncastError<'_, '_> {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
93 display_downcast_error(f, &self.from, &self.to)
94 }
95}
96
97impl std::convert::From<DowncastIntoError<'_>> for PyErr {
99 fn from(err: DowncastIntoError<'_>) -> PyErr {
100 let args = DowncastErrorArguments {
101 from: err.from.get_type().into(),
102 to: err.to,
103 };
104
105 exceptions::PyTypeError::new_err(args)
106 }
107}
108
109impl std::error::Error for DowncastIntoError<'_> {}
110
111impl std::fmt::Display for DowncastIntoError<'_> {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
113 display_downcast_error(f, &self.from, &self.to)
114 }
115}
116
117fn display_downcast_error(
118 f: &mut std::fmt::Formatter<'_>,
119 from: &Bound<'_, PyAny>,
120 to: &str,
121) -> std::fmt::Result {
122 write!(
123 f,
124 "'{}' object cannot be converted to '{}'",
125 from.get_type().qualname().map_err(|_| std::fmt::Error)?,
126 to
127 )
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_display_downcast_error() {
136 Python::attach(|py| {
137 let obj = py.None().into_bound(py);
138 let err = DowncastError::new(&obj, "int");
139 assert_eq!(
140 err.to_string(),
141 "'NoneType' object cannot be converted to 'int'"
142 );
143 })
144 }
145
146 #[test]
147 fn test_display_downcast_into_error() {
148 Python::attach(|py| {
149 let obj = py.None().into_bound(py);
150 let err = DowncastIntoError::new(obj, "int");
151 assert_eq!(
152 err.to_string(),
153 "'NoneType' object cannot be converted to 'int'"
154 );
155 })
156 }
157
158 #[test]
159 fn test_pyerr_from_downcast_error() {
160 Python::attach(|py| {
161 let obj = py.None().into_bound(py);
162 let err = DowncastError::new(&obj, "int");
163 let py_err: PyErr = err.into();
164 assert_eq!(
165 py_err.to_string(),
166 "TypeError: 'NoneType' object cannot be converted to 'int'"
167 );
168 })
169 }
170
171 #[test]
172 fn test_pyerr_from_downcast_into_error() {
173 Python::attach(|py| {
174 let obj = py.None().into_bound(py);
175 let err = DowncastIntoError::new(obj, "int");
176 let py_err: PyErr = err.into();
177 assert_eq!(
178 py_err.to_string(),
179 "TypeError: 'NoneType' object cannot be converted to 'int'"
180 );
181 })
182 }
183}