Skip to content

Commit 4a4655a

Browse files
author
Andrew J Westlake
committed
Wrapping up PR, ran into some env problems on Windows, switching to Ubuntu to continue
1 parent d1aa7ca commit 4a4655a

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

src/async_std.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ where
278278
/// Unlike [`future_into_py_with_loop`], this function will stop the Rust future from running when
279279
/// the `asyncio.Future` is cancelled from Python.
280280
///
281+
/// __This function will be deprecated in favor of [`future_into_py_with_loop`] in `v0.15` because
282+
/// it will become the default behaviour. In `v0.15`, any calls to this function can be seamlessly
283+
/// replaced with [`future_into_py_with_loop`].__
284+
///
281285
/// # Arguments
282286
/// * `event_loop` - The Python event loop that the awaitable should be attached to
283287
/// * `fut` - The Rust future to be converted
@@ -344,6 +348,10 @@ where
344348
/// Unlike [`future_into_py`], this function will stop the Rust future from running when
345349
/// the `asyncio.Future` is cancelled from Python.
346350
///
351+
/// __This function will be deprecated in favor of [`future_into_py`] in `v0.15` because
352+
/// it will become the default behaviour. In `v0.15`, any calls to this function can be seamlessly
353+
/// replaced with [`future_into_py`].__
354+
///
347355
/// # Arguments
348356
/// * `py` - The current PyO3 GIL guard
349357
/// * `fut` - The Rust future to be converted

src/generic.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,111 @@ where
10951095
Ok(future_rx)
10961096
}
10971097

1098+
/// Convert a `!Send` Rust Future into a Python awaitable with a generic runtime
1099+
///
1100+
/// Unlike [`local_future_into_py_with_loop`], this function will stop the Rust future from running
1101+
/// when the `asyncio.Future` is cancelled from Python.
1102+
///
1103+
/// # Arguments
1104+
/// * `event_loop` - The Python event loop that the awaitable should be attached to
1105+
/// * `fut` - The Rust future to be converted
1106+
///
1107+
/// # Examples
1108+
///
1109+
/// ```no_run
1110+
/// # use std::{task::{Context, Poll}, pin::Pin, future::Future};
1111+
/// #
1112+
/// # use pyo3_asyncio::generic::{JoinError, Runtime};
1113+
/// #
1114+
/// # struct MyCustomJoinError;
1115+
/// #
1116+
/// # impl JoinError for MyCustomJoinError {
1117+
/// # fn is_panic(&self) -> bool {
1118+
/// # unreachable!()
1119+
/// # }
1120+
/// # }
1121+
/// #
1122+
/// # struct MyCustomJoinHandle;
1123+
/// #
1124+
/// # impl Future for MyCustomJoinHandle {
1125+
/// # type Output = Result<(), MyCustomJoinError>;
1126+
/// #
1127+
/// # fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
1128+
/// # unreachable!()
1129+
/// # }
1130+
/// # }
1131+
/// #
1132+
/// # struct MyCustomRuntime;
1133+
/// #
1134+
/// # impl MyCustomRuntime {
1135+
/// # async fn sleep(_: Duration) {
1136+
/// # unreachable!()
1137+
/// # }
1138+
/// # }
1139+
/// #
1140+
/// # impl Runtime for MyCustomRuntime {
1141+
/// # type JoinError = MyCustomJoinError;
1142+
/// # type JoinHandle = MyCustomJoinHandle;
1143+
/// #
1144+
/// # fn scope<F, R>(_event_loop: PyObject, fut: F) -> Pin<Box<dyn Future<Output = R> + Send>>
1145+
/// # where
1146+
/// # F: Future<Output = R> + Send + 'static
1147+
/// # {
1148+
/// # unreachable!()
1149+
/// # }
1150+
/// # fn get_task_event_loop(py: Python) -> Option<&PyAny> {
1151+
/// # unreachable!()
1152+
/// # }
1153+
/// #
1154+
/// # fn spawn<F>(fut: F) -> Self::JoinHandle
1155+
/// # where
1156+
/// # F: Future<Output = ()> + Send + 'static
1157+
/// # {
1158+
/// # unreachable!()
1159+
/// # }
1160+
/// # }
1161+
/// #
1162+
/// use std::time::Duration;
1163+
///
1164+
/// use pyo3::prelude::*;
1165+
///
1166+
/// /// Awaitable sleep function
1167+
/// #[pyfunction]
1168+
/// fn sleep_for<'p>(py: Python<'p>, secs: &'p PyAny) -> PyResult<&'p PyAny> {
1169+
/// // Rc is !Send so it cannot be passed into pyo3_asyncio::generic::future_into_py
1170+
/// let secs = Rc::new(secs);
1171+
///
1172+
/// pyo3_asyncio::generic::local_cancellable_future_into_py_with_loop::<MyCustomRuntime, _>(
1173+
/// pyo3_asyncio::get_running_loop(py)?,
1174+
/// async move {
1175+
/// MyCustomRuntime::sleep(Duration::from_secs(*secs)).await;
1176+
/// Python::with_gil(|py| Ok(py.None()))
1177+
/// }
1178+
/// )
1179+
/// }
1180+
/// ```
1181+
pub fn local_cancellable_future_into_py_with_loop<R, F>(event_loop: &PyAny, fut: F) -> PyResult<&PyAny>
1182+
where
1183+
R: Runtime + SpawnLocalExt,
1184+
F: Future<Output = PyResult<PyObject>> + 'static,
1185+
{
1186+
let (cancel_tx, cancel_rx) = oneshot::channel();
1187+
1188+
let py_fut = local_future_into_py_with_loop::<R, _>(
1189+
event_loop,
1190+
Cancellable::new_with_cancel_rx(fut, cancel_rx),
1191+
)?;
1192+
1193+
py_fut.call_method1(
1194+
"add_done_callback",
1195+
(PyDoneCallback {
1196+
cancel_tx: Some(cancel_tx),
1197+
},),
1198+
)?;
1199+
1200+
Ok(py_fut)
1201+
}
1202+
10981203
/// Convert a `!Send` Rust Future into a Python awaitable with a generic runtime
10991204
///
11001205
/// # Arguments

0 commit comments

Comments
 (0)