|
| 1 | +# Appendix B: Migration Guides for major version changes |
| 2 | + |
| 3 | +## from 0.8.* to 0.9 |
| 4 | + |
| 5 | +### `#[new]` interface |
| 6 | +[`PyRawObject`](https://docs.rs/pyo3/0.8.5/pyo3/type_object/struct.PyRawObject.html) |
| 7 | +is now removed and our syntax for constructor changed. |
| 8 | + |
| 9 | +Before: |
| 10 | +```compile_fail |
| 11 | +#[pyclass] |
| 12 | +struct MyClass {} |
| 13 | +
|
| 14 | +#[pymethods] |
| 15 | +impl MyClass { |
| 16 | + #[new] |
| 17 | + fn new(obj: &PyRawObject) { |
| 18 | + obj.init(MyClass { }) |
| 19 | + } |
| 20 | +} |
| 21 | +``` |
| 22 | + |
| 23 | +After: |
| 24 | +``` |
| 25 | +# use pyo3::prelude::*; |
| 26 | +#[pyclass] |
| 27 | +struct MyClass {} |
| 28 | +
|
| 29 | +#[pymethods] |
| 30 | +impl MyClass { |
| 31 | + #[new] |
| 32 | + fn new() -> Self { |
| 33 | + MyClass {} |
| 34 | + } |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +Basically you can return `Self` or `Result<Self>` directly. |
| 39 | +For more, see [the constructor section](https://pyo3.rs/master/class.html#constructor) of this guide. |
| 40 | + |
| 41 | +### PyCell |
| 42 | +PyO3 0.9 introduces [`PyCell`](https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html), which is |
| 43 | +a [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) like object wrapper |
| 44 | +for dynamically ensuring |
| 45 | +[Rust's rule of Reference](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references). |
| 46 | + |
| 47 | +For `#[pymethods]` or `#[pyfunction]`s, `PyCell` works without any change. |
| 48 | +Just throw errors when there happens invalid borrowing. |
| 49 | + |
| 50 | +Here is an example. |
| 51 | +``` |
| 52 | +# use pyo3::prelude::*; |
| 53 | +#[pyclass] |
| 54 | +struct Names { |
| 55 | + names: Vec<String> |
| 56 | +} |
| 57 | +
|
| 58 | +#[pymethods] |
| 59 | +impl Names { |
| 60 | + #[new] |
| 61 | + fn new() -> Self { |
| 62 | + Names { names: vec![] } |
| 63 | + } |
| 64 | + fn merge(&mut self, other: &mut Names) { |
| 65 | + self.names.append(&mut other.names) |
| 66 | + } |
| 67 | +} |
| 68 | +# let gil = Python::acquire_gil(); |
| 69 | +# let py = gil.python(); |
| 70 | +# let names = PyCell::new(py, Names::new()).unwrap(); |
| 71 | +# let borrow_mut_err = py.get_type::<pyo3::pycell::PyBorrowMutError>(); |
| 72 | +# pyo3::py_run!(py, names borrow_mut_err, r" |
| 73 | +# try: |
| 74 | +# names.merge(names) |
| 75 | +# assert False, 'Unreachable' |
| 76 | +# except Exception as e: |
| 77 | +# isinstance(e, borrow_mut_err) |
| 78 | +# "); |
| 79 | +``` |
| 80 | +`Names` has `merge` method, which takes `&mut self` and `&mut Self`. |
| 81 | +Given this `#[pyclass]`, calling `names.merge(names)` in Python raises `PyBorrowMutError` exception, |
| 82 | +since it requires two mutable borrows of `names`, |
| 83 | + |
| 84 | +However, for `#[pyproto]` and some functions, you need to manually fix codes. |
| 85 | + |
| 86 | +#### Object creation |
| 87 | +We could use the older `PyRef` and `PyRefMut` for object creation, but now they are just |
| 88 | +reference wrappers for `PyCell`. |
| 89 | +Use `PyCell::new` instead. |
| 90 | + |
| 91 | +Before: |
| 92 | +```compile_fail |
| 93 | +# use pyo3::prelude::*; |
| 94 | +# #[pyclass] |
| 95 | +# struct MyClass {} |
| 96 | +let gil = Python::acquire_gil(); |
| 97 | +let py = gil.python(); |
| 98 | +let obj_ref = PyRef::new(py, MyClass {}).unwrap(); |
| 99 | +``` |
| 100 | + |
| 101 | +After: |
| 102 | +``` |
| 103 | +# use pyo3::prelude::*; |
| 104 | +# #[pyclass] |
| 105 | +# struct MyClass {} |
| 106 | +let gil = Python::acquire_gil(); |
| 107 | +let py = gil.python(); |
| 108 | +let obj = PyCell::new(py, MyClass {}).unwrap(); |
| 109 | +let obj_ref = obj.borrow(); |
| 110 | +``` |
| 111 | + |
| 112 | +#### Object extraction |
| 113 | +Now for `T: PyClass`, `&T` and `&mut T` don't have `FromPyObject` implementation. |
| 114 | +Instead, you can use `&PyCell`, `PyRef`, and `PyRefMut` for object extraction. |
| 115 | + |
| 116 | +Before: |
| 117 | +```ignore |
| 118 | +let obj: &PyAny = create_obj(); |
| 119 | +let obj_ref: &MyClass = obj.extract().unwrap(); |
| 120 | +let obj_ref_mut: &mut MyClass = obj.extract().unwrap(); |
| 121 | +``` |
| 122 | + |
| 123 | +After: |
| 124 | +``` |
| 125 | +# use pyo3::prelude::*; |
| 126 | +# use pyo3::types::{PyAny, IntoPyDict}; |
| 127 | +# #[pyclass] struct MyClass {} |
| 128 | +# #[pymethods] impl MyClass { #[new]fn new() -> Self { MyClass {} }} |
| 129 | +# let gil = Python::acquire_gil(); |
| 130 | +# let py = gil.python(); |
| 131 | +# let typeobj = py.get_type::<MyClass>(); |
| 132 | +# let d = [("c", typeobj)].into_py_dict(py); |
| 133 | +# let create_obj = || py.eval("c()", None, Some(d)).unwrap(); |
| 134 | +let obj: &PyAny = create_obj(); |
| 135 | +let obj_cell: &PyCell<MyClass> = obj.extract().unwrap(); |
| 136 | +{ |
| 137 | + let obj_ref: PyRef<MyClass> = obj.extract().unwrap(); |
| 138 | + // we need to drop obj_ref before taking RefMut |
| 139 | +} |
| 140 | +let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap(); |
| 141 | +``` |
| 142 | + |
| 143 | + |
| 144 | +#### `#[pyproto]` |
| 145 | +Most of `#[pyproto]` arguments requires [`FromPyObject`] implementation. |
| 146 | +So if your protocol methods take `&T` or `&mut T`(where `T: PyClass`), |
| 147 | +please use `PyRef` or `PyRefMut` instead. |
| 148 | + |
| 149 | +Before: |
| 150 | +```compile_fail |
| 151 | +# use pyo3::prelude::*; |
| 152 | +# use pyo3::class::PySequenceProtocol; |
| 153 | +#[pyclass] |
| 154 | +struct ByteSequence { |
| 155 | + elements: Vec<u8>, |
| 156 | +} |
| 157 | +#[pyproto] |
| 158 | +impl PySequenceProtocol for ByteSequence { |
| 159 | + fn __concat__(&self, other: &Self) -> PyResult<Self> { |
| 160 | + let mut elements = self.elements.clone(); |
| 161 | + elements.extend_from_slice(&other.elements); |
| 162 | + Ok(Self { elements }) |
| 163 | + } |
| 164 | +} |
| 165 | +``` |
| 166 | + |
| 167 | +After: |
| 168 | +``` |
| 169 | +# use pyo3::prelude::*; |
| 170 | +# use pyo3::class::PySequenceProtocol; |
| 171 | +#[pyclass] |
| 172 | +struct ByteSequence { |
| 173 | + elements: Vec<u8>, |
| 174 | +} |
| 175 | +#[pyproto] |
| 176 | +impl PySequenceProtocol for ByteSequence { |
| 177 | + fn __concat__(&self, other: PyRef<'p, Self>) -> PyResult<Self> { |
| 178 | + let mut elements = self.elements.clone(); |
| 179 | + elements.extend_from_slice(&other.elements); |
| 180 | + Ok(Self { elements }) |
| 181 | + } |
| 182 | +} |
| 183 | +``` |
0 commit comments