Skip to content

Commit

Permalink
Merge pull request #966 from davidhewitt/pyclass-send
Browse files Browse the repository at this point in the history
Require Send for #[pyclass] (no compilefail test)
  • Loading branch information
kngwyu authored Jun 9, 2020
2 parents 4317f16 + 33617bf commit 7a72713
Show file tree
Hide file tree
Showing 6 changed files with 17 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Simplify internals of `#[pyo3(get)]` attribute. (Remove the hidden API `GetPropertyValue`.) [#934](https://github.com/PyO3/pyo3/pull/934)
- Call `Py_Finalize` at exit to flush buffers, etc. [#943](https://github.com/PyO3/pyo3/pull/943)
- Add type parameter to PyBuffer. #[951](https://github.com/PyO3/pyo3/pull/951)
- Require `Send` bound for `#[pyclass]`. [#966](https://github.com/PyO3/pyo3/pull/966)

### Removed
- Remove `ManagedPyRef` (unused, and needs specialization) [#930](https://github.com/PyO3/pyo3/pull/930)
Expand Down
5 changes: 2 additions & 3 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ struct MyClass {
}
```

The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`],
and [`PyClass`] for `MyClass`.
Because Python objects are freely shared between threads by the Python interpreter, all structs annotated with `#[pyclass]` must implement `Send`.

If you curious what `#[pyclass]` generates, see [How methods are implemented](#how-methods-are-implemented) section.
The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`], and [`PyClass`] for `MyClass`. To see these generated implementations, refer to the section [How methods are implemented](#how-methods-are-implemented) at the end of this chapter.

## Adding the class to a module

Expand Down
4 changes: 3 additions & 1 deletion src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ pub unsafe fn tp_free_fallback(obj: *mut ffi::PyObject) {
///
/// The `#[pyclass]` attribute automatically implements this trait for your Rust struct,
/// so you don't have to use this trait directly.
pub trait PyClass: PyTypeInfo<Layout = PyCell<Self>> + Sized + PyClassAlloc + PyMethods {
pub trait PyClass:
PyTypeInfo<Layout = PyCell<Self>> + Sized + PyClassAlloc + PyMethods + Send
{
/// Specify this class has `#[pyclass(dict)]` or not.
type Dict: PyClassDict;
/// Specify this class has `#[pyclass(weakref)]` or not.
Expand Down
11 changes: 5 additions & 6 deletions tests/test_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use pyo3::class::PyVisit;
use pyo3::prelude::*;
use pyo3::type_object::PyTypeObject;
use pyo3::{py_run, AsPyPointer, PyCell, PyTryInto};
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

Expand Down Expand Up @@ -84,19 +83,19 @@ fn data_is_dropped() {
#[allow(dead_code)]
#[pyclass]
struct GCIntegration {
self_ref: RefCell<PyObject>,
self_ref: PyObject,
dropped: TestDropCall,
}

#[pyproto]
impl PyGCProtocol for GCIntegration {
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
visit.call(&*self.self_ref.borrow())
visit.call(&self.self_ref)
}

fn __clear__(&mut self) {
let gil = GILGuard::acquire();
*self.self_ref.borrow_mut() = gil.python().None();
self.self_ref = gil.python().None();
}
}

Expand All @@ -110,7 +109,7 @@ fn gc_integration() {
let inst = PyCell::new(
py,
GCIntegration {
self_ref: RefCell::new(py.None()),
self_ref: py.None(),
dropped: TestDropCall {
drop_called: Arc::clone(&drop_called),
},
Expand All @@ -119,7 +118,7 @@ fn gc_integration() {
.unwrap();

let mut borrow = inst.borrow_mut();
*borrow.self_ref.borrow_mut() = inst.to_object(py);
borrow.self_ref = inst.to_object(py);
}

let gil = Python::acquire_gil();
Expand Down
14 changes: 3 additions & 11 deletions tests/ui/static_ref.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
use pyo3::prelude::*;
use pyo3::types::PyList;

#[pyclass]
struct MyClass {
list: &'static PyList,
}

#[pymethods]
impl MyClass {
#[new]
fn new(list: &'static PyList) -> Self {
Self { list }
}
#[pyfunction]
fn static_ref(list: &'static PyList) -> usize {
list.len()
}

fn main() {}
6 changes: 3 additions & 3 deletions tests/ui/static_ref.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0597]: `pool` does not live long enough
--> $DIR/static_ref.rs:9:1
--> $DIR/static_ref.rs:4:1
|
9 | #[pymethods]
| ^^^^^^^^^^^^
4 | #[pyfunction]
| ^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| `pool` dropped here while still borrowed
Expand Down

0 comments on commit 7a72713

Please sign in to comment.