Skip to content

Commit 140db44

Browse files
author
Andrew J Westlake
committed
Added the migration guide to the README
1 parent c79cbc3 commit 140db44

File tree

1 file changed

+98
-3
lines changed

1 file changed

+98
-3
lines changed

README.md

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717

1818
> PyO3 Asyncio is a _brand new_ part of the broader PyO3 ecosystem. Feel free to open any issues for feature requests or bugfixes for this crate.
1919
20-
## Known Problems
21-
22-
This library can give spurious failures during finalization prior to PyO3 release `v0.13.2`. Make sure your PyO3 dependency is up-to-date!
20+
__If you're a new-comer, the best way to get started is to read through the primer below! For `v0.13` users I highly recommend reading through the [migration section](#migrating-from-013-to-014) to get a general idea of what's changed in `v0.14`.__
2321

2422
## PyO3 Asyncio Primer
2523

@@ -833,6 +831,103 @@ async fn main() -> pyo3::PyResult<()> {
833831
}
834832
```
835833

834+
## Migrating from 0.13 to 0.14
835+
836+
So what's changed from `v0.13` to `v0.14`?
837+
838+
Well, a lot actually. There were some pretty major flaws in the initialization behaviour of `v0.13`. While it would have been nicer to address these issues without changing the public API, I decided it'd be better to break some of the old API rather than completely change the underlying behaviour of the existing functions. I realize this is going to be a bit of a headache, so hopefully this section will help you through it.
839+
840+
To make things a bit easier, I decided to keep most of the old API alongside the new one (with some deprecation warnings to encourage users to move away from it). It should be possible to use the `v0.13` API alongside the newer `v0.14` API, which should allow you to upgrade your application piecemeal rather than all at once.
841+
842+
__Before you get started, I personally recommend taking a look at [Event Loop References and Thread-awareness](#event-loop-references-and-thread-awareness) in order to get a better grasp on the motivation behind these changes and the nuance involved in using the new conversions.__
843+
844+
### 0.14 Highlights
845+
- Tokio initialization is now lazy.
846+
- No configuration necessary if you're using the multithreaded scheduler
847+
- Calls to `pyo3_asyncio::tokio::init_multithread` or `pyo3_asyncio::tokio::init_multithread_once` can just be removed.
848+
- Calls to `pyo3_asyncio::tokio::init_current_thread` or `pyo3_asyncio::tokio::init_current_thread_once` require some special attention.
849+
- Custom runtime configuration is done by passing a `tokio::runtime::Builder` into `pyo3_asyncio::tokio::init` instead of a `tokio::runtime::Runtime`
850+
- A new, more correct set of functions has been added to replace the `v0.13` conversions.
851+
- `pyo3_asyncio::into_future_with_loop`
852+
- `pyo3_asyncio::<runtime>::future_into_py_with_loop`
853+
- `pyo3_asyncio::<runtime>::local_future_into_py_with_loop`
854+
- `pyo3_asyncio::<runtime>::into_future`
855+
- `pyo3_asyncio::<runtime>::future_into_py`
856+
- `pyo3_asyncio::<runtime>::local_future_into_py`
857+
- `pyo3_asyncio::<runtime>::get_current_loop`
858+
- The `ThreadPoolExecutor` is no longer configured automatically at the start.
859+
- Fortunately, this doesn't seem to have much effect on `v0.13` code, it just means that it's now possible to configure the executor manually as you see fit.
860+
861+
### Upgrading Your Code to 0.14
862+
863+
1. Fix PyO3 0.14 initialization.
864+
- PyO3 0.14 feature gated its automatic initialization behaviour behind "auto-initialize". You can either enable the "auto-initialize" behaviour in your project or add a call to `pyo3::prepare_freethreaded_python()` to the start of your program.
865+
- If you're using the `#[pyo3_asyncio::<runtime>::main]` proc macro attributes, then you can skip this step. `#[pyo3_asyncio::<runtime>::main]` will call `pyo3::prepare_freethreaded_python()` at the start regardless of your project's "auto-initialize" feature.
866+
2. Fix the tokio initialization.
867+
- Calls to `pyo3_asyncio::tokio::init_multithread` or `pyo3_asyncio::tokio::init_multithread_once` can just be removed.
868+
- If you're using the current thread scheduler, you'll need to manually spawn the thread that it runs on during initialization:
869+
```rust no_run
870+
let mut builder = tokio::runtime::Builder::new_current_thread();
871+
builder.enable_all();
872+
873+
pyo3_asyncio::tokio::init(builder);
874+
std::thread::spawn(move || {
875+
pyo3_asyncio::tokio::get_runtime().block_on(
876+
futures::future::pending::<()>()
877+
);
878+
});
879+
```
880+
- Custom `tokio::runtime::Builder` configs can be passed into `pyo3_asyncio::tokio::init`. The `tokio::runtime::Runtime` will be lazily instantiated on the first call to `pyo3_asyncio::tokio::get_runtime()`
881+
3. If you're using `pyo3_asyncio::run_forever` in your application, you should switch to a more manual approach.
882+
> `run_forever` is not the recommended way of running an event loop in Python, so it might be a good idea to move away from it. This function would have needed to change for `0.14`, but since it's considered an edge case, it was decided that users could just manually call it if they need to.
883+
```rust
884+
use pyo3::prelude::*;
885+
886+
fn main() -> PyResult<()> {
887+
pyo3::prepare_freethreaded_python();
888+
889+
Python::with_gil(|py| {
890+
let asyncio = py.import("asyncio")?;
891+
892+
let event_loop = asyncio.call_method0("new_event_loop")?;
893+
asyncio.call_method1("set_event_loop", (event_loop,))?;
894+
895+
let event_loop_hdl = PyObject::from(event_loop);
896+
897+
pyo3_asyncio::tokio::get_runtime().spawn(async move {
898+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
899+
900+
// Stop the event loop manually
901+
Python::with_gil(|py| {
902+
event_loop_hdl
903+
.as_ref(py)
904+
.call_method1(
905+
"call_soon_threadsafe",
906+
(event_loop_hdl
907+
.as_ref(py)
908+
.getattr("stop")
909+
.unwrap(),),
910+
)
911+
.unwrap();
912+
})
913+
});
914+
915+
event_loop.call_method0("run_forever")?;
916+
Ok(())
917+
})
918+
}
919+
```
920+
4. Replace conversions with their newer counterparts.
921+
> You may encounter some issues regarding the usage of `get_running_loop` vs `get_event_loop`. For more details on these newer conversions and how they should be used see [Event Loop References and Thread-awareness](#event-loop-references-and-thread-awareness).
922+
- Replace `pyo3_asyncio::into_future` with `pyo3_asyncio::<runtime>::into_future`
923+
- Replace `pyo3_asyncio::<runtime>::into_coroutine` with `pyo3_asyncio::<runtime>::future_into_py`
924+
- Replace `pyo3_asyncio::get_event_loop` with `pyo3_asyncio::<runtime>::get_current_loop`
925+
5. After all conversions have been replaced with their `v0.14` counterparts, `pyo3_asyncio::try_init` can safely be removed.
926+
927+
## Known Problems
928+
929+
This library can give spurious failures during finalization prior to PyO3 release `v0.13.2`. Make sure your PyO3 dependency is up-to-date!
930+
836931
## MSRV
837932
Currently the MSRV for this library is 1.46.0, _but_ if you don't need to use the `async-std-runtime`
838933
feature, you can use rust 1.45.0.

0 commit comments

Comments
 (0)