Skip to content

Commit ca1bbe3

Browse files
committed
add migration notes for PyO3 0.18
1 parent 72c561c commit ca1bbe3

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

guide/src/migration.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,70 @@
33
This guide can help you upgrade code through breaking changes from one PyO3 version to the next.
44
For a detailed list of all changes, see the [CHANGELOG](changelog.md).
55

6+
## from 0.17.* to 0.18
7+
8+
### Required arguments after `Option<_>` arguments will no longer be automatically inferred
9+
10+
In `#[pyfunction]` and `#[pymethods]`, if a "required" function input such as `i32` came after an `Option<_>` input, then the `Option<_>` would be implicitly treated as required. (All trailing `Option<_>` arguments were treated as optional with a default value of `None`).
11+
12+
Starting with PyO3 0.18, this is deprecated and a future PyO3 version will require a [`#[pyo3(signature = (...))]` option](./function/signature.md) to explicitly declare the programmer's intention.
13+
14+
Before, x in the below example would be required to be passed from Python code:
15+
16+
```rust,compile_fail
17+
# #![allow(dead_code)]
18+
# use pyo3::prelude::*;
19+
20+
#[pyfunction]
21+
fn required_argument_after_option(x: Option<i32>, y: i32) { }
22+
```
23+
24+
After, specify the intended Python signature explicitly:
25+
26+
```rust
27+
# #![allow(dead_code)]
28+
# use pyo3::prelude::*;
29+
30+
// If x really was intended to be required
31+
#[pyfunction(signature = (x, y))]
32+
fn required_argument_after_option_a(x: Option<i32>, y: i32) { }
33+
34+
// If x was intended to be optional, y needs a default too
35+
#[pyfunction(signature = (x=None, y=0))]
36+
fn required_argument_after_option_b(x: Option<i32>, y: i32) { }
37+
```
38+
39+
### `__text_signature__` is now automatically generated for `#[pyfunction]` and `#[pymethods]`
40+
41+
The [`#[pyo3(text_signature = "...")]` option](./function/signature.md#making-the-function-signature-available-to-python) was previously the only supported way to set the `__text_signature__` attribute on generated Python functions.
42+
43+
PyO3 is now able to automatically populate `__text_signature__` for all functions automatically based on their Rust signature (or the [new `#[pyo3(signature = (...))]` option](./function/signature.md)). These automatically-generated `__text_signature__` values will currently only render `...` for all default values. Many `#[pyo3(text_signature = "...")]` options can be removed from functions when updating to PyO3 0.18, however in cases with default values a manual implementation may still be preferred for now.
44+
45+
As examples:
46+
47+
```rust
48+
# use pyo3::prelude::*;
49+
50+
// The `text_signature` option here is no longer necessary, as PyO3 will automatically
51+
// generate exactly the same value.
52+
#[pyfunction(text_signature = "(a, b, c)")]
53+
fn simple_function(a: i32, b: i32, c: i32) {}
54+
55+
// The `text_signature` still provides value here as of PyO3 0.18, because the automatically
56+
// generated signature would be "(a, b=..., c=...)".
57+
#[pyfunction(signature = (a, b = 1, c = 2), text_signature = "(a, b=1, c=2)")]
58+
fn function_with_defaults(a: i32, b: i32, c: i32) {}
59+
60+
# fn main() {
61+
# Python::with_gil(|py| {
62+
# let simple = wrap_pyfunction!(simple_function, py).unwrap();
63+
# assert_eq!(simple.getattr("__text_signature__").unwrap().to_string(), "(a, b, c)");
64+
# let defaulted = wrap_pyfunction!(function_with_defaults, py).unwrap();
65+
# assert_eq!(defaulted.getattr("__text_signature__").unwrap().to_string(), "(a, b=1, c=2)");
66+
# })
67+
# }
68+
```
69+
670
## from 0.16.* to 0.17
771

872
### Type checks have been changed for `PyMapping` and `PySequence` types

0 commit comments

Comments
 (0)