Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PyErr: Send + Sync #1067

Merged
merged 1 commit into from Aug 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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)
Expand Down
30 changes: 23 additions & 7 deletions src/err.rs
Expand Up @@ -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))
}
Expand Down Expand Up @@ -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:
Expand All @@ -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() };
Expand All @@ -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(),
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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>();
}
}
6 changes: 4 additions & 2 deletions src/exceptions.rs
Expand Up @@ -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()
}
}
Expand Down