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