port `PyErr::warn` to `Bound` API (#3842)
* port `PyErr::new_type` * port `PyErr::warn` and `PyErr::warn_explicit`
This commit is contained in:
parent
dc8b948201
commit
05aedc9032
|
@ -52,7 +52,9 @@ use crate::types::{
|
|||
};
|
||||
#[cfg(Py_LIMITED_API)]
|
||||
use crate::{intern, DowncastError};
|
||||
use crate::{Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject};
|
||||
use crate::{
|
||||
Bound, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject,
|
||||
};
|
||||
use chrono::offset::{FixedOffset, Utc};
|
||||
use chrono::{
|
||||
DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike,
|
||||
|
@ -457,9 +459,9 @@ fn naive_datetime_to_py_datetime(
|
|||
|
||||
fn warn_truncated_leap_second(obj: &Bound<'_, PyAny>) {
|
||||
let py = obj.py();
|
||||
if let Err(e) = PyErr::warn(
|
||||
if let Err(e) = PyErr::warn_bound(
|
||||
py,
|
||||
py.get_type::<PyUserWarning>(),
|
||||
&py.get_type::<PyUserWarning>().as_borrowed(),
|
||||
"ignored leap-second, `datetime` does not support leap-seconds",
|
||||
0,
|
||||
) {
|
||||
|
|
120
src/err/mod.rs
120
src/err/mod.rs
|
@ -445,6 +445,30 @@ impl PyErr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Deprecated form of [`PyErr::new_type_bound`]
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`PyErr::new_type` will be replaced by `PyErr::new_type_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn new_type(
|
||||
py: Python<'_>,
|
||||
name: &str,
|
||||
doc: Option<&str>,
|
||||
base: Option<&PyType>,
|
||||
dict: Option<PyObject>,
|
||||
) -> PyResult<Py<PyType>> {
|
||||
Self::new_type_bound(
|
||||
py,
|
||||
name,
|
||||
doc,
|
||||
base.map(PyNativeType::as_borrowed).as_deref(),
|
||||
dict,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new exception type with the given name and docstring.
|
||||
///
|
||||
/// - `base` can be an existing exception type to subclass, or a tuple of classes.
|
||||
|
@ -459,11 +483,11 @@ impl PyErr {
|
|||
/// # Panics
|
||||
///
|
||||
/// This function will panic if `name` or `doc` cannot be converted to [`CString`]s.
|
||||
pub fn new_type(
|
||||
py: Python<'_>,
|
||||
pub fn new_type_bound<'py>(
|
||||
py: Python<'py>,
|
||||
name: &str,
|
||||
doc: Option<&str>,
|
||||
base: Option<&PyType>,
|
||||
base: Option<&Bound<'py, PyType>>,
|
||||
dict: Option<PyObject>,
|
||||
) -> PyResult<Py<PyType>> {
|
||||
let base: *mut ffi::PyObject = match base {
|
||||
|
@ -635,6 +659,18 @@ impl PyErr {
|
|||
unsafe { ffi::PyErr_WriteUnraisable(obj.map_or(std::ptr::null_mut(), Bound::as_ptr)) }
|
||||
}
|
||||
|
||||
/// Deprecated form of [`PyErr::warn_bound`].
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`PyErr::warn` will be replaced by `PyErr::warn_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn warn(py: Python<'_>, category: &PyAny, message: &str, stacklevel: i32) -> PyResult<()> {
|
||||
Self::warn_bound(py, &category.as_borrowed(), message, stacklevel)
|
||||
}
|
||||
|
||||
/// Issues a warning message.
|
||||
///
|
||||
/// May return an `Err(PyErr)` if warnings-as-errors is enabled.
|
||||
|
@ -650,13 +686,18 @@ impl PyErr {
|
|||
/// # use pyo3::prelude::*;
|
||||
/// # fn main() -> PyResult<()> {
|
||||
/// Python::with_gil(|py| {
|
||||
/// let user_warning = py.get_type::<pyo3::exceptions::PyUserWarning>();
|
||||
/// PyErr::warn(py, user_warning, "I am warning you", 0)?;
|
||||
/// let user_warning = py.get_type::<pyo3::exceptions::PyUserWarning>().as_borrowed();
|
||||
/// PyErr::warn_bound(py, &user_warning, "I am warning you", 0)?;
|
||||
/// Ok(())
|
||||
/// })
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn warn(py: Python<'_>, category: &PyAny, message: &str, stacklevel: i32) -> PyResult<()> {
|
||||
pub fn warn_bound<'py>(
|
||||
py: Python<'py>,
|
||||
category: &Bound<'py, PyAny>,
|
||||
message: &str,
|
||||
stacklevel: i32,
|
||||
) -> PyResult<()> {
|
||||
let message = CString::new(message)?;
|
||||
error_on_minusone(py, unsafe {
|
||||
ffi::PyErr_WarnEx(
|
||||
|
@ -667,14 +708,14 @@ impl PyErr {
|
|||
})
|
||||
}
|
||||
|
||||
/// Issues a warning message, with more control over the warning attributes.
|
||||
///
|
||||
/// May return a `PyErr` if warnings-as-errors is enabled.
|
||||
///
|
||||
/// Equivalent to `warnings.warn_explicit()` in Python.
|
||||
///
|
||||
/// The `category` should be one of the `Warning` classes available in
|
||||
/// [`pyo3::exceptions`](crate::exceptions), or a subclass.
|
||||
/// Deprecated form of [`PyErr::warn_explicit_bound`].
|
||||
#[cfg_attr(
|
||||
not(feature = "gil-refs"),
|
||||
deprecated(
|
||||
since = "0.21.0",
|
||||
note = "`PyErr::warn_explicit` will be replaced by `PyErr::warn_explicit_bound` in a future PyO3 version"
|
||||
)
|
||||
)]
|
||||
pub fn warn_explicit(
|
||||
py: Python<'_>,
|
||||
category: &PyAny,
|
||||
|
@ -683,6 +724,34 @@ impl PyErr {
|
|||
lineno: i32,
|
||||
module: Option<&str>,
|
||||
registry: Option<&PyAny>,
|
||||
) -> PyResult<()> {
|
||||
Self::warn_explicit_bound(
|
||||
py,
|
||||
&category.as_borrowed(),
|
||||
message,
|
||||
filename,
|
||||
lineno,
|
||||
module,
|
||||
registry.map(PyNativeType::as_borrowed).as_deref(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Issues a warning message, with more control over the warning attributes.
|
||||
///
|
||||
/// May return a `PyErr` if warnings-as-errors is enabled.
|
||||
///
|
||||
/// Equivalent to `warnings.warn_explicit()` in Python.
|
||||
///
|
||||
/// The `category` should be one of the `Warning` classes available in
|
||||
/// [`pyo3::exceptions`](crate::exceptions), or a subclass.
|
||||
pub fn warn_explicit_bound<'py>(
|
||||
py: Python<'py>,
|
||||
category: &Bound<'py, PyAny>,
|
||||
message: &str,
|
||||
filename: &str,
|
||||
lineno: i32,
|
||||
module: Option<&str>,
|
||||
registry: Option<&Bound<'py, PyAny>>,
|
||||
) -> PyResult<()> {
|
||||
let message = CString::new(message)?;
|
||||
let filename = CString::new(filename)?;
|
||||
|
@ -975,7 +1044,7 @@ mod tests {
|
|||
use super::PyErrState;
|
||||
use crate::exceptions::{self, PyTypeError, PyValueError};
|
||||
use crate::types::any::PyAnyMethods;
|
||||
use crate::{PyErr, PyTypeInfo, Python};
|
||||
use crate::{PyErr, PyNativeType, PyTypeInfo, Python};
|
||||
|
||||
#[test]
|
||||
fn no_error() {
|
||||
|
@ -1172,7 +1241,7 @@ mod tests {
|
|||
// GIL locked should prevent effects to be visible to other testing
|
||||
// threads.
|
||||
Python::with_gil(|py| {
|
||||
let cls = py.get_type::<exceptions::PyUserWarning>();
|
||||
let cls = py.get_type::<exceptions::PyUserWarning>().as_borrowed();
|
||||
|
||||
// Reset warning filter to default state
|
||||
let warnings = py.import_bound("warnings").unwrap();
|
||||
|
@ -1181,7 +1250,7 @@ mod tests {
|
|||
// First, test the warning is emitted
|
||||
assert_warnings!(
|
||||
py,
|
||||
{ PyErr::warn(py, cls, "I am warning you", 0).unwrap() },
|
||||
{ PyErr::warn_bound(py, &cls, "I am warning you", 0).unwrap() },
|
||||
[(exceptions::PyUserWarning, "I am warning you")]
|
||||
);
|
||||
|
||||
|
@ -1189,7 +1258,7 @@ mod tests {
|
|||
warnings
|
||||
.call_method1("simplefilter", ("error", cls))
|
||||
.unwrap();
|
||||
PyErr::warn(py, cls, "I am warning you", 0).unwrap_err();
|
||||
PyErr::warn_bound(py, &cls, "I am warning you", 0).unwrap_err();
|
||||
|
||||
// Test with error for an explicit module
|
||||
warnings.call_method0("resetwarnings").unwrap();
|
||||
|
@ -1200,13 +1269,20 @@ mod tests {
|
|||
// This has the wrong module and will not raise, just be emitted
|
||||
assert_warnings!(
|
||||
py,
|
||||
{ PyErr::warn(py, cls, "I am warning you", 0).unwrap() },
|
||||
{ PyErr::warn_bound(py, &cls, "I am warning you", 0).unwrap() },
|
||||
[(exceptions::PyUserWarning, "I am warning you")]
|
||||
);
|
||||
|
||||
let err =
|
||||
PyErr::warn_explicit(py, cls, "I am warning you", "pyo3test.py", 427, None, None)
|
||||
.unwrap_err();
|
||||
let err = PyErr::warn_explicit_bound(
|
||||
py,
|
||||
&cls,
|
||||
"I am warning you",
|
||||
"pyo3test.py",
|
||||
427,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(err
|
||||
.value(py)
|
||||
.getattr("args")
|
||||
|
|
|
@ -240,16 +240,17 @@ macro_rules! create_exception_type_object {
|
|||
impl $name {
|
||||
fn type_object_raw(py: $crate::Python<'_>) -> *mut $crate::ffi::PyTypeObject {
|
||||
use $crate::sync::GILOnceCell;
|
||||
use $crate::PyNativeType;
|
||||
static TYPE_OBJECT: GILOnceCell<$crate::Py<$crate::types::PyType>> =
|
||||
GILOnceCell::new();
|
||||
|
||||
TYPE_OBJECT
|
||||
.get_or_init(py, ||
|
||||
$crate::PyErr::new_type(
|
||||
$crate::PyErr::new_type_bound(
|
||||
py,
|
||||
concat!(stringify!($module), ".", stringify!($name)),
|
||||
$doc,
|
||||
::std::option::Option::Some(py.get_type::<$base>()),
|
||||
::std::option::Option::Some(&py.get_type::<$base>().as_borrowed()),
|
||||
::std::option::Option::None,
|
||||
).expect("Failed to initialize new exception type.")
|
||||
).as_ptr() as *mut $crate::ffi::PyTypeObject
|
||||
|
|
Loading…
Reference in New Issue