Make `PyErr: Send + Sync`

This commit is contained in:
David Hewitt 2020-07-24 09:05:16 +01:00
parent b05eb4814b
commit 09aef5d299
3 changed files with 28 additions and 9 deletions

View File

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Correct FFI definition `_PyLong_AsByteArray` `*mut c_uchar` argument instead of `*const c_uchar`. [#1029](https://github.com/PyO3/pyo3/pull/1029)
- `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047)
- Change `PyIterator::from_object` to return `PyResult<PyIterator>` instead of `Result<PyIterator, PyDowncastError>`. [#1051](https://github.com/PyO3/pyo3/pull/1051)
- Implement `Send + Sync` for `PyErr`. `PyErr::new`, `PyErr::from_type`, `PyException::py_err` and `PyException::into` have had these bounds added to their arguments. [#1067](https://github.com/PyO3/pyo3/pull/1067)
### Removed
- Remove `PyString::as_bytes`. [#1023](https://github.com/PyO3/pyo3/pull/1023)

View File

@ -26,12 +26,15 @@ use std::ptr::NonNull;
pub enum PyErrValue {
None,
Value(PyObject),
ToArgs(Box<dyn PyErrArguments>),
ToObject(Box<dyn ToPyObject>),
ToArgs(Box<dyn PyErrArguments + Send + Sync>),
ToObject(Box<dyn ToPyObject + Send + Sync>),
}
impl PyErrValue {
pub fn from_err_args<T: 'static + PyErrArguments>(value: T) -> Self {
pub fn from_err_args<T>(value: T) -> Self
where
T: PyErrArguments + Send + Sync + 'static,
{
let _ = Python::acquire_gil();
PyErrValue::ToArgs(Box::new(value))
}
@ -85,6 +88,8 @@ impl PyErr {
/// * a tuple: the exception instance will be created using Python `T(*tuple)`
/// * any other value: the exception instance will be created using Python `T(value)`
///
/// Note: if `value` is not `Send` or `Sync`, consider using `PyErr::from_value` instead.
///
/// Panics if `T` is not a Python class derived from `BaseException`.
///
/// Example:
@ -101,7 +106,7 @@ impl PyErr {
pub fn new<T, V>(value: V) -> PyErr
where
T: PyTypeObject,
V: ToPyObject + 'static,
V: ToPyObject + Send + Sync + 'static,
{
let gil = ensure_gil();
let py = unsafe { gil.python() };
@ -123,7 +128,7 @@ impl PyErr {
/// `args` is the a tuple of arguments to pass to the exception constructor.
pub fn from_type<A>(exc: &PyType, args: A) -> PyErr
where
A: ToPyObject + 'static,
A: ToPyObject + Send + Sync + 'static,
{
PyErr {
ptype: exc.into(),
@ -559,13 +564,15 @@ impl PyErrArguments for io::Error {
}
}
impl<W: 'static + Send + std::fmt::Debug> std::convert::From<std::io::IntoInnerError<W>> for PyErr {
impl<W: 'static + Send + Sync + std::fmt::Debug> std::convert::From<std::io::IntoInnerError<W>>
for PyErr
{
fn from(err: std::io::IntoInnerError<W>) -> PyErr {
PyErr::from_value::<exceptions::PyOSError>(PyErrValue::from_err_args(err))
}
}
impl<W: Send + std::fmt::Debug> PyErrArguments for std::io::IntoInnerError<W> {
impl<W: Send + Sync + std::fmt::Debug> PyErrArguments for std::io::IntoInnerError<W> {
fn arguments(&self, py: Python) -> PyObject {
self.to_string().to_object(py)
}
@ -654,4 +661,13 @@ mod tests {
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| PyErr::fetch(py))).is_err();
assert!(started_unwind);
}
#[test]
fn test_pyerr_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<PyErr>();
is_sync::<PyErr>();
}
}

View File

@ -26,10 +26,12 @@ macro_rules! impl_exception_boilerplate {
}
impl $name {
pub fn py_err<V: $crate::ToPyObject + 'static>(args: V) -> $crate::PyErr {
pub fn py_err<V: $crate::ToPyObject + Send + Sync + 'static>(args: V) -> $crate::PyErr {
$crate::PyErr::new::<$name, V>(args)
}
pub fn into<R, V: $crate::ToPyObject + 'static>(args: V) -> $crate::PyResult<R> {
pub fn into<R, V: $crate::ToPyObject + Send + Sync + 'static>(
args: V,
) -> $crate::PyResult<R> {
$crate::PyErr::new::<$name, V>(args).into()
}
}