-
Notifications
You must be signed in to change notification settings - Fork 196
/
tools.rs
122 lines (107 loc) · 3.1 KB
/
tools.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::borrow::Cow;
use pyo3::exceptions::PyKeyError;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyString};
use pyo3::{ffi, intern, FromPyObject};
pub trait SchemaDict<'py> {
fn get_as<T>(&'py self, key: &PyString) -> PyResult<Option<T>>
where
T: FromPyObject<'py>;
fn get_as_req<T>(&'py self, key: &PyString) -> PyResult<T>
where
T: FromPyObject<'py>;
}
impl<'py> SchemaDict<'py> for PyDict {
fn get_as<T>(&'py self, key: &PyString) -> PyResult<Option<T>>
where
T: FromPyObject<'py>,
{
match self.get_item(key)? {
Some(t) => Ok(Some(<T>::extract(t)?)),
None => Ok(None),
}
}
fn get_as_req<T>(&'py self, key: &PyString) -> PyResult<T>
where
T: FromPyObject<'py>,
{
match self.get_item(key)? {
Some(t) => <T>::extract(t),
None => py_err!(PyKeyError; "{}", key),
}
}
}
impl<'py> SchemaDict<'py> for Option<&PyDict> {
fn get_as<T>(&'py self, key: &PyString) -> PyResult<Option<T>>
where
T: FromPyObject<'py>,
{
match self {
Some(d) => d.get_as(key),
None => Ok(None),
}
}
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn get_as_req<T>(&'py self, key: &PyString) -> PyResult<T>
where
T: FromPyObject<'py>,
{
match self {
Some(d) => d.get_as_req(key),
None => py_err!(PyKeyError; "{}", key),
}
}
}
macro_rules! py_error_type {
($error_type:ty; $msg:expr) => {
<$error_type>::new_err($msg)
};
($error_type:ty; $msg:expr, $( $msg_args:expr ),+ ) => {
<$error_type>::new_err(format!($msg, $( $msg_args ),+))
};
}
pub(crate) use py_error_type;
macro_rules! py_err {
($error_type:ty; $msg:expr) => {
Err(crate::tools::py_error_type!($error_type; $msg))
};
($error_type:ty; $msg:expr, $( $msg_args:expr ),+ ) => {
Err(crate::tools::py_error_type!($error_type; $msg, $( $msg_args ),+))
};
}
pub(crate) use py_err;
pub fn function_name(f: &PyAny) -> PyResult<String> {
match f.getattr(intern!(f.py(), "__name__")) {
Ok(name) => name.extract(),
_ => f.repr()?.extract(),
}
}
pub fn safe_repr(v: &PyAny) -> Cow<str> {
if let Ok(s) = v.repr() {
s.to_string_lossy()
} else if let Ok(name) = v.get_type().name() {
format!("<unprintable {name} object>").into()
} else {
"<unprintable object>".into()
}
}
/// Extract an i64 from a python object more quickly, see
/// https://github.com/PyO3/pyo3/pull/3742#discussion_r1451763928
#[cfg(not(any(target_pointer_width = "32", windows, PyPy)))]
pub fn extract_i64(obj: &PyAny) -> Option<i64> {
let val = unsafe { ffi::PyLong_AsLong(obj.as_ptr()) };
if val == -1 && PyErr::occurred(obj.py()) {
unsafe { ffi::PyErr_Clear() };
None
} else {
Some(val)
}
}
#[cfg(any(target_pointer_width = "32", windows, PyPy))]
pub fn extract_i64(v: &PyAny) -> Option<i64> {
if v.is_instance_of::<pyo3::types::PyInt>() {
v.extract().ok()
} else {
None
}
}