You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* docs: use one sentence per line in guide
* formatting corrections
* disable MD013 for paragraphs, tables, headings, and code blocks
* remove unneeded comment
---------
Co-authored-by: Icxolu <10486322+Icxolu@users.noreply.github.com>
Copy file name to clipboardExpand all lines: guide/src/advanced.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,4 +4,5 @@
4
4
5
5
PyO3 exposes much of Python's C API through the `ffi` module.
6
6
7
-
The C API is naturally unsafe and requires you to manage reference counts, errors and specific invariants yourself. Please refer to the [C API Reference Manual](https://docs.python.org/3/c-api/) and [The Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/ffi.html) before using any function from that API.
7
+
The C API is naturally unsafe and requires you to manage reference counts, errors and specific invariants yourself.
8
+
Please refer to the [C API Reference Manual](https://docs.python.org/3/c-api/) and [The Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/ffi.html) before using any function from that API.
*Python awaitables instantiated with this method can only be awaited in *asyncio* context. Other Python async runtime may be supported in the future.*
28
+
*Python awaitables instantiated with this method can only be awaited in `asyncio` context. Other Python async runtime may be supported in the future.*
29
29
30
30
## `Send + 'static` constraint
31
31
32
32
Resulting future of an `async fn` decorated by `#[pyfunction]` must be `Send + 'static` to be embedded in a Python object.
33
33
34
34
As a consequence, `async fn` parameters and return types must also be `Send + 'static`, so it is not possible to have a signature like `async fn does_not_compile<'py>(arg: Bound<'py, PyAny>) -> Bound<'py, PyAny>`.
35
35
36
-
However, there is an exception for method receivers, so async methods can accept `&self`/`&mut self`. Note that this means that the class instance is borrowed for as long as the returned future is not completed, even across yield points and while waiting for I/O operations to complete. Hence, other methods cannot obtain exclusive borrows while the future is still being polled. This is the same as how async methods in Rust generally work but it is more problematic for Rust code interfacing with Python code due to pervasive shared mutability. This strongly suggests to prefer shared borrows `&self` over exclusive ones `&mut self` to avoid racy borrow check failures at runtime.
36
+
However, there is an exception for method receivers, so async methods can accept `&self`/ `&mut self`.
37
+
Note that this means that the class instance is borrowed for as long as the returned future is not completed, even across yield points and while waiting for I/O operations to complete.
38
+
Hence, other methods cannot obtain exclusive borrows while the future is still being polled.
39
+
This is the same as how async methods in Rust generally work but it is more problematic for Rust code interfacing with Python code due to pervasive shared mutability.
40
+
This strongly suggests to prefer shared borrows `&self` over exclusive ones `&mut self` to avoid racy borrow check failures at runtime.
To make a Rust future awaitable in Python, PyO3 defines a [`Coroutine`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.Coroutine.html) type, which implements the Python [coroutine protocol](https://docs.python.org/3/library/collections.abc.html#collections.abc.Coroutine).
100
104
101
-
Each `coroutine.send` call is translated to a `Future::poll` call. If a [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) parameter is declared, the exception passed to `coroutine.throw` call is stored in it and can be retrieved with [`CancelHandle::cancelled`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html#method.cancelled); otherwise, it cancels the Rust future, and the exception is reraised;
105
+
Each `coroutine.send` call is translated to a `Future::poll` call.
106
+
If a [`CancelHandle`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html) parameter is declared, the exception passed to `coroutine.throw` call is stored in it and can be retrieved with [`CancelHandle::cancelled`]({{#PYO3_DOCS_URL}}/pyo3/coroutine/struct.CancelHandle.html#method.cancelled); otherwise, it cancels the Rust future, and the exception is reraised;
102
107
103
108
*The type does not yet have a public constructor until the design is finalized.*
Copy file name to clipboardExpand all lines: guide/src/building-and-distribution/multiple-python-versions.md
+21-9Lines changed: 21 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,14 +1,19 @@
1
1
# Supporting multiple Python versions
2
2
3
-
PyO3 supports all actively-supported Python 3 and PyPy versions. As much as possible, this is done internally to PyO3 so that your crate's code does not need to adapt to the differences between each version. However, as Python features grow and change between versions, PyO3 cannot offer a completely identical API for every Python version. This may require you to add conditional compilation to your crate or runtime checks for the Python version.
3
+
PyO3 supports all actively-supported Python 3 and PyPy versions.
4
+
As much as possible, this is done internally to PyO3 so that your crate's code does not need to adapt to the differences between each version.
5
+
However, as Python features grow and change between versions, PyO3 cannot offer a completely identical API for every Python version.
6
+
This may require you to add conditional compilation to your crate or runtime checks for the Python version.
4
7
5
8
This section of the guide first introduces the `pyo3-build-config` crate, which you can use as a `build-dependency` to add additional `#[cfg]` flags which allow you to support multiple Python versions at compile-time.
6
9
7
-
Second, we'll show how to check the Python version at runtime. This can be useful when building for multiple versions with the `abi3` feature, where the Python API compiled against is not always the same as the one in use.
10
+
Second, we'll show how to check the Python version at runtime.
11
+
This can be useful when building for multiple versions with the `abi3` feature, where the Python API compiled against is not always the same as the one in use.
8
12
9
13
## Conditional compilation for different Python versions
10
14
11
-
The `pyo3-build-config` exposes multiple [`#[cfg]` flags](https://doc.rust-lang.org/rust-by-example/attribute/cfg.html) which can be used to conditionally compile code for a given Python version. PyO3 itself depends on this crate, so by using it you can be sure that you are configured correctly for the Python version PyO3 is building against.
15
+
The `pyo3-build-config` exposes multiple [`#[cfg]` flags](https://doc.rust-lang.org/rust-by-example/attribute/cfg.html) which can be used to conditionally compile code for a given Python version.
16
+
PyO3 itself depends on this crate, so by using it you can be sure that you are configured correctly for the Python version PyO3 is building against.
12
17
13
18
This allows us to write code like the following
14
19
@@ -51,13 +56,15 @@ After these steps you are ready to annotate your code!
51
56
52
57
### Common usages of `pyo3-build-cfg` flags
53
58
54
-
The `#[cfg]` flags added by `pyo3-build-cfg` can be combined with all of Rust's logic in the `#[cfg]` attribute to create very precise conditional code generation. The following are some common patterns implemented using these flags:
59
+
The `#[cfg]` flags added by `pyo3-build-cfg` can be combined with all of Rust's logic in the `#[cfg]` attribute to create very precise conditional code generation.
60
+
The following are some common patterns implemented using these flags:
55
61
56
62
```text
57
63
#[cfg(Py_3_7)]
58
64
```
59
65
60
-
This `#[cfg]` marks code that will only be present on Python 3.7 and upwards. There are similar options `Py_3_8`, `Py_3_9`, `Py_3_10` and so on for each minor version.
66
+
This `#[cfg]` marks code that will only be present on Python 3.7 and upwards.
67
+
There are similar options `Py_3_8`, `Py_3_9`, `Py_3_10` and so on for each minor version.
61
68
62
69
```text
63
70
#[cfg(not(Py_3_7))]
@@ -69,13 +76,15 @@ This `#[cfg]` marks code that will only be present on Python versions before (bu
69
76
#[cfg(not(Py_LIMITED_API))]
70
77
```
71
78
72
-
This `#[cfg]` marks code that is only available when building for the unlimited Python API (i.e. PyO3's `abi3` feature is not enabled). This might be useful if you want to ship your extension module as an `abi3` wheel and also allow users to compile it from source to make use of optimizations only possible with the unlimited API.
79
+
This `#[cfg]` marks code that is only available when building for the unlimited Python API (i.e. PyO3's `abi3` feature is not enabled).
80
+
This might be useful if you want to ship your extension module as an `abi3` wheel and also allow users to compile it from source to make use of optimizations only possible with the unlimited API.
73
81
74
82
```text
75
83
#[cfg(any(Py_3_9, not(Py_LIMITED_API)))]
76
84
```
77
85
78
-
This `#[cfg]` marks code which is available when running Python 3.9 or newer, or when using the unlimited API with an older Python version. Patterns like this are commonly seen on Python APIs which were added to the limited Python API in a specific minor version.
86
+
This `#[cfg]` marks code which is available when running Python 3.9 or newer, or when using the unlimited API with an older Python version.
87
+
Patterns like this are commonly seen on Python APIs which were added to the limited Python API in a specific minor version.
79
88
80
89
```text
81
90
#[cfg(PyPy)]
@@ -87,11 +96,14 @@ This `#[cfg]` marks code which is running on PyPy.
87
96
88
97
When building with PyO3's `abi3` feature, your extension module will be compiled against a specific [minimum version](../building-and-distribution.md#minimum-python-version-for-abi3) of Python, but may be running on newer Python versions.
89
98
90
-
For example with PyO3's `abi3-py38` feature, your extension will be compiled as if it were for Python 3.8. If you were using `pyo3-build-config`, `#[cfg(Py_3_8)]` would be present. Your user could freely install and run your abi3 extension on Python 3.9.
99
+
For example with PyO3's `abi3-py38` feature, your extension will be compiled as if it were for Python 3.8.
100
+
If you were using `pyo3-build-config`, `#[cfg(Py_3_8)]` would be present.
101
+
Your user could freely install and run your abi3 extension on Python 3.9.
91
102
92
103
There's no way to detect your user doing that at compile time, so instead you need to fall back to runtime checks.
93
104
94
-
PyO3 provides the APIs [`Python::version()`] and [`Python::version_info()`] to query the running Python version. This allows you to do the following, for example:
105
+
PyO3 provides the APIs [`Python::version()`] and [`Python::version_info()`] to query the running Python version.
0 commit comments