pyo3/impl_/
frompyobject.rs1use crate::types::any::PyAnyMethods;
2use crate::Bound;
3use crate::{exceptions::PyTypeError, FromPyObject, PyAny, PyErr, PyResult, Python};
4
5#[cold]
6pub fn failed_to_extract_enum(
7 py: Python<'_>,
8 type_name: &str,
9 variant_names: &[&str],
10 error_names: &[&str],
11 errors: &[PyErr],
12) -> PyErr {
13 let mut err_msg = format!(
15 "failed to extract enum {} ('{}')",
16 type_name,
17 error_names.join(" | ")
18 );
19 for ((variant_name, error_name), error) in variant_names.iter().zip(error_names).zip(errors) {
20 use std::fmt::Write;
21 write!(
22 &mut err_msg,
23 "\n- variant {variant_name} ({error_name}): {error_msg}",
24 variant_name = variant_name,
25 error_name = error_name,
26 error_msg = extract_traceback(py, error.clone_ref(py)),
27 )
28 .unwrap();
29 }
30 PyTypeError::new_err(err_msg)
31}
32
33fn extract_traceback(py: Python<'_>, mut error: PyErr) -> String {
35 use std::fmt::Write;
36
37 let mut error_msg = error.to_string();
38 while let Some(cause) = error.cause(py) {
39 write!(&mut error_msg, ", caused by {cause}").unwrap();
40 error = cause
41 }
42 error_msg
43}
44
45pub fn extract_struct_field<'py, T>(
46 obj: &Bound<'py, PyAny>,
47 struct_name: &str,
48 field_name: &str,
49) -> PyResult<T>
50where
51 T: FromPyObject<'py>,
52{
53 match obj.extract() {
54 Ok(value) => Ok(value),
55 Err(err) => Err(failed_to_extract_struct_field(
56 obj.py(),
57 err,
58 struct_name,
59 field_name,
60 )),
61 }
62}
63
64pub fn extract_struct_field_with<'a, 'py, T>(
65 extractor: fn(&'a Bound<'py, PyAny>) -> PyResult<T>,
66 obj: &'a Bound<'py, PyAny>,
67 struct_name: &str,
68 field_name: &str,
69) -> PyResult<T> {
70 match extractor(obj) {
71 Ok(value) => Ok(value),
72 Err(err) => Err(failed_to_extract_struct_field(
73 obj.py(),
74 err,
75 struct_name,
76 field_name,
77 )),
78 }
79}
80
81#[cold]
82fn failed_to_extract_struct_field(
83 py: Python<'_>,
84 inner_err: PyErr,
85 struct_name: &str,
86 field_name: &str,
87) -> PyErr {
88 let new_err = PyTypeError::new_err(format!(
89 "failed to extract field {struct_name}.{field_name}"
90 ));
91 new_err.set_cause(py, ::std::option::Option::Some(inner_err));
92 new_err
93}
94
95pub fn extract_tuple_struct_field<'py, T>(
96 obj: &Bound<'py, PyAny>,
97 struct_name: &str,
98 index: usize,
99) -> PyResult<T>
100where
101 T: FromPyObject<'py>,
102{
103 match obj.extract() {
104 Ok(value) => Ok(value),
105 Err(err) => Err(failed_to_extract_tuple_struct_field(
106 obj.py(),
107 err,
108 struct_name,
109 index,
110 )),
111 }
112}
113
114pub fn extract_tuple_struct_field_with<'a, 'py, T>(
115 extractor: fn(&'a Bound<'py, PyAny>) -> PyResult<T>,
116 obj: &'a Bound<'py, PyAny>,
117 struct_name: &str,
118 index: usize,
119) -> PyResult<T> {
120 match extractor(obj) {
121 Ok(value) => Ok(value),
122 Err(err) => Err(failed_to_extract_tuple_struct_field(
123 obj.py(),
124 err,
125 struct_name,
126 index,
127 )),
128 }
129}
130
131#[cold]
132fn failed_to_extract_tuple_struct_field(
133 py: Python<'_>,
134 inner_err: PyErr,
135 struct_name: &str,
136 index: usize,
137) -> PyErr {
138 let new_err = PyTypeError::new_err(format!("failed to extract field {struct_name}.{index}"));
139 new_err.set_cause(py, ::std::option::Option::Some(inner_err));
140 new_err
141}