Skip to content

Commit c4d96b9

Browse files
committed
fixes
1 parent c707f53 commit c4d96b9

File tree

8 files changed

+72
-41
lines changed

8 files changed

+72
-41
lines changed

examples/03_streams.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import asyncio
24

35
import rsloop

examples/04_unix_and_accepted_socket.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import asyncio
24
import os
35
import socket

examples/05_pipes_signals_subprocesses.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import asyncio
24
import os
35
import signal

python/rsloop/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,31 @@
2525
"stop_profiler",
2626
)
2727
_T = __typing.TypeVar("_T")
28+
__ORIG_SET_EVENT_LOOP = __asyncio.set_event_loop
29+
30+
31+
def __set_event_loop(loop: Loop | None) -> None:
32+
try:
33+
__ORIG_SET_EVENT_LOOP(loop)
34+
return
35+
except (AssertionError, TypeError):
36+
if loop is None or not isinstance(loop, Loop):
37+
raise
38+
39+
# Python 3.8 rejects non-stdlib loop objects in set_event_loop() with a
40+
# hard isinstance() assertion. Mirror the stdlib policy bookkeeping so
41+
# get_event_loop() still returns the current rsloop instance.
42+
policy = __asyncio.get_event_loop_policy()
43+
local = getattr(policy, "_local", None)
44+
if local is None:
45+
raise
46+
local._set_called = True
47+
local._loop = loop
48+
49+
50+
if __asyncio.set_event_loop is __ORIG_SET_EVENT_LOOP:
51+
__asyncio.set_event_loop = __set_event_loop
52+
__asyncio.events.set_event_loop = __set_event_loop
2853

2954

3055
def new_event_loop() -> Loop:

scripts/build-wheels.sh

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,20 @@ fi
9292
for version in "${PYTHON_VERSIONS[@]}"; do
9393
interpreter="$(uv python find "$version")"
9494
echo "Building release wheel for Python ${version} (${interpreter})"
95-
uv run \
96-
--no-project \
97-
--python "$interpreter" \
98-
--with maturin \
99-
maturin build \
100-
--release \
101-
--interpreter "$interpreter" \
102-
--out "$OUTPUT_DIR" \
103-
"${MATURIN_ARGS[@]}"
95+
maturin_cmd=(
96+
uv run
97+
--no-project
98+
--python "$interpreter"
99+
--with maturin
100+
maturin build
101+
--release
102+
--interpreter "$interpreter"
103+
--out "$OUTPUT_DIR"
104+
)
105+
if ((${#MATURIN_ARGS[@]})); then
106+
maturin_cmd+=("${MATURIN_ARGS[@]}")
107+
fi
108+
"${maturin_cmd[@]}"
104109
done
105110

106111
echo "Wheels written to $OUTPUT_DIR"

src/callbacks.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ pub type CallbackId = u64;
1313

1414
enum CallbackArgs {
1515
None,
16-
One(Py<PyAny>),
1716
Many(Py<PyTuple>),
1817
}
1918

@@ -50,12 +49,6 @@ impl ReadyCallback {
5049
) -> Self {
5150
let args = match args.bind(py).len() {
5251
0 => CallbackArgs::None,
53-
1 => CallbackArgs::One(
54-
args.bind(py)
55-
.get_item(0)
56-
.expect("single callback arg missing")
57-
.unbind(),
58-
),
5952
_ => CallbackArgs::Many(args),
6053
};
6154

@@ -127,23 +120,13 @@ impl ReadyCallback {
127120
)
128121
.map(Bound::unbind)
129122
},
130-
CallbackArgs::One(arg) => unsafe {
131-
Bound::from_owned_ptr_or_err(
132-
py,
133-
ffi::PyObject_CallOneArg(self.callback.as_ptr(), arg.as_ptr()),
134-
)
135-
.map(Bound::unbind)
136-
},
137123
CallbackArgs::Many(args) => self.callback.call1(py, args.clone_ref(py)),
138124
}
139125
}
140126

141127
pub fn clone_args_tuple(&self, py: Python<'_>) -> Py<PyTuple> {
142128
match &self.args {
143129
CallbackArgs::None => PyTuple::empty(py).unbind(),
144-
CallbackArgs::One(arg) => PyTuple::new(py, [arg.clone_ref(py)])
145-
.expect("failed to clone single callback arg")
146-
.unbind(),
147130
CallbackArgs::Many(args) => args.clone_ref(py),
148131
}
149132
}

src/python_api.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use std::sync::OnceLock;
88
use std::time::Duration;
99

1010
use pyo3::exceptions::{PyNotImplementedError, PyRuntimeError, PyTypeError, PyValueError};
11-
use pyo3::ffi;
1211
use pyo3::prelude::*;
1312
use pyo3::types::{PyDict, PyModule, PySlice, PyTuple};
1413
use pyo3_async_runtimes::TaskLocals;
@@ -123,13 +122,7 @@ fn create_asyncio_future_for_loop(py: Python<'_>, loop_obj: &Py<PyAny>) -> PyRes
123122
}
124123

125124
fn create_asyncio_future_for_running_loop(py: Python<'_>) -> PyResult<Py<PyAny>> {
126-
unsafe {
127-
Bound::from_owned_ptr_or_err(
128-
py,
129-
ffi::compat::PyObject_CallNoArgs(asyncio_future_cls(py)?.as_ptr()),
130-
)
131-
.map(Bound::unbind)
132-
}
125+
asyncio_future_cls(py)?.call0(py)
133126
}
134127

135128
fn create_asyncio_task_for_loop(
@@ -151,13 +144,7 @@ fn create_asyncio_task_for_loop(
151144
}
152145

153146
fn create_asyncio_task_for_running_loop(py: Python<'_>, coro: Py<PyAny>) -> PyResult<Py<PyAny>> {
154-
unsafe {
155-
Bound::from_owned_ptr_or_err(
156-
py,
157-
ffi::PyObject_CallOneArg(asyncio_task_cls(py)?.as_ptr(), coro.as_ptr()),
158-
)
159-
.map(Bound::unbind)
160-
}
147+
asyncio_task_cls(py)?.call1(py, (coro,))
161148
}
162149

163150
fn call_protocol_factory(

tests/test_run.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import asyncio
2+
import unittest
3+
4+
import rsloop
5+
6+
7+
class RunTests(unittest.TestCase):
8+
def test_set_event_loop_accepts_rsloop_loop(self) -> None:
9+
loop = rsloop.new_event_loop()
10+
try:
11+
asyncio.set_event_loop(loop)
12+
self.assertIs(asyncio.get_event_loop(), loop)
13+
finally:
14+
asyncio.set_event_loop(None)
15+
loop.close()
16+
17+
def test_run_executes_coroutine(self) -> None:
18+
async def main() -> str:
19+
return "ok"
20+
21+
self.assertEqual(rsloop.run(main()), "ok")
22+
23+
24+
if __name__ == "__main__":
25+
unittest.main()

0 commit comments

Comments
 (0)