Skip to content

Commit 1544c73

Browse files
authored
Update pyo3 to 0.26.0 for freethreading improvements (#18)
1 parent dcc9c60 commit 1544c73

File tree

11 files changed

+47
-48
lines changed

11 files changed

+47
-48
lines changed

Cargo.lock

Lines changed: 12 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ http-rewriter = { git = "ssh://git@github.com/platformatic/http-rewriter" }
3131
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
3232
napi = { version = "3", default-features = false, features = ["napi4", "tokio_rt", "async"], optional = true }
3333
napi-derive = { version = "3", optional = true }
34-
pyo3 = { version = "0.25.1", features = ["experimental-async"] }
35-
pyo3-async-runtimes = { version = "0.25.0", features = ["tokio-runtime"] }
34+
pyo3 = { version = "0.26.0", features = ["experimental-async"] }
35+
pyo3-async-runtimes = { version = "0.26.0", features = ["tokio-runtime"] }
3636
thiserror = "2.0.12"
3737
tokio = { version = "1.45.1", features = ["full"] }
3838
libc = "0.2"

src/asgi/http.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,8 @@ mod tests {
527527

528528
#[test]
529529
fn test_http_connection_scope_into_pyobject() {
530-
pyo3::prepare_freethreaded_python();
531-
Python::with_gil(|py| {
530+
Python::initialize();
531+
Python::attach(|py| {
532532
let scope = HttpConnectionScope {
533533
http_version: HttpVersion::V1_1,
534534
method: HttpMethod::Get,
@@ -577,8 +577,8 @@ mod tests {
577577

578578
#[test]
579579
fn test_http_receive_message_into_pyobject() {
580-
pyo3::prepare_freethreaded_python();
581-
Python::with_gil(|py| {
580+
Python::initialize();
581+
Python::attach(|py| {
582582
let message = HttpReceiveMessage::Request {
583583
body: vec![1, 2, 3],
584584
more_body: true,
@@ -596,8 +596,8 @@ mod tests {
596596

597597
#[test]
598598
fn test_http_send_message_from_pyobject() {
599-
pyo3::prepare_freethreaded_python();
600-
Python::with_gil(|py| {
599+
Python::initialize();
600+
Python::attach(|py| {
601601
let dict = PyDict::new(py);
602602
dict.set_item("type", "http.response.start").unwrap();
603603
dict.set_item("status", 200).unwrap();

src/asgi/http_method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ mod tests {
119119

120120
#[test]
121121
fn test_http_method_pyobject_conversion() {
122-
Python::with_gil(|py| {
122+
Python::attach(|py| {
123123
let tests = vec![
124124
(HttpMethod::Get, "GET"),
125125
(HttpMethod::Post, "POST"),

src/asgi/http_version.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ mod tests {
7171

7272
#[test]
7373
fn test_http_version_pyobject_conversion() {
74-
Python::with_gil(|py| {
74+
Python::attach(|py| {
7575
let tests = vec![
7676
(HttpVersion::V1_0, "1.0"),
7777
(HttpVersion::V1_1, "1.1"),

src/asgi/info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ mod tests {
7373

7474
#[test]
7575
fn test_asgi_info_pyobject_conversion() {
76-
Python::with_gil(|py| {
76+
Python::attach(|py| {
7777
let asgi_info = AsgiInfo::new("3.0", "2.5");
7878

7979
// Convert AsgiInfo to PyObject

src/asgi/lifespan.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ mod tests {
107107

108108
#[test]
109109
fn test_lifespan_scope_into_pyobject() {
110-
Python::with_gil(|py| {
110+
Python::attach(|py| {
111111
let lifespan_scope = LifespanScope { state: None };
112112
let py_obj = lifespan_scope.into_pyobject(py).unwrap();
113113
assert_eq!(
@@ -129,7 +129,7 @@ mod tests {
129129

130130
#[test]
131131
fn test_lifespan_receive_message_into_pyobject() {
132-
Python::with_gil(|py| {
132+
Python::attach(|py| {
133133
let message = LifespanReceiveMessage::LifespanStartup;
134134
let py_obj = message.into_pyobject(py).unwrap();
135135
assert_eq!(
@@ -148,7 +148,7 @@ mod tests {
148148

149149
#[test]
150150
fn test_lifespan_send_message_from_pyobject() {
151-
Python::with_gil(|py| {
151+
Python::attach(|py| {
152152
let dict = PyDict::new(py);
153153
dict.set_item("type", "lifespan.shutdown.complete").unwrap();
154154
let message: LifespanSendMessage = dict.extract().unwrap();
@@ -163,7 +163,7 @@ mod tests {
163163

164164
#[test]
165165
fn test_lifespan_send_message_from_pyobject_error_cases() {
166-
Python::with_gil(|py| {
166+
Python::attach(|py| {
167167
// Test missing 'type' key
168168
let dict = PyDict::new(py);
169169
let result: Result<LifespanSendMessage, _> = dict.extract();
@@ -261,7 +261,7 @@ mod tests {
261261

262262
#[test]
263263
fn test_lifespan_scope_with_populated_state() {
264-
Python::with_gil(|py| {
264+
Python::attach(|py| {
265265
// Create a state dictionary with some data
266266
let state_dict = PyDict::new(py);
267267
state_dict.set_item("initialized", true).unwrap();

src/asgi/mod.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,20 @@ pub use websocket::{
6262

6363
/// Handle to a shared Python event loop
6464
pub struct EventLoopHandle {
65-
event_loop: PyObject,
65+
event_loop: Py<PyAny>,
6666
}
6767

6868
impl EventLoopHandle {
6969
/// Get the Python event loop object
70-
pub fn event_loop(&self) -> &PyObject {
70+
pub fn event_loop(&self) -> &Py<PyAny> {
7171
&self.event_loop
7272
}
7373
}
7474

7575
impl Drop for EventLoopHandle {
7676
fn drop(&mut self) {
7777
// Stop the Python event loop when the last handle is dropped
78-
Python::with_gil(|py| {
78+
Python::attach(|py| {
7979
if let Err(e) = self.event_loop.bind(py).call_method0("stop") {
8080
eprintln!("Failed to stop Python event loop: {e}");
8181
}
@@ -111,10 +111,10 @@ fn create_event_loop_handle() -> Result<EventLoopHandle, HandlerError> {
111111
ensure_python_symbols_global();
112112

113113
// Initialize Python if not already initialized
114-
pyo3::prepare_freethreaded_python();
114+
Python::initialize();
115115

116116
// Create event loop
117-
let event_loop = Python::with_gil(|py| -> Result<PyObject, HandlerError> {
117+
let event_loop = Python::attach(|py| -> Result<Py<PyAny>, HandlerError> {
118118
let asyncio = py.import("asyncio")?;
119119
let event_loop = asyncio.call_method0("new_event_loop")?;
120120
let event_loop_py = event_loop.unbind();
@@ -139,7 +139,7 @@ pub struct Asgi {
139139
// Shared Python event loop handle
140140
event_loop_handle: Arc<EventLoopHandle>,
141141
// ASGI app function
142-
app_function: PyObject,
142+
app_function: Py<PyAny>,
143143
}
144144

145145
unsafe impl Send for Asgi {}
@@ -160,7 +160,7 @@ impl Asgi {
160160
let event_loop_handle = ensure_python_event_loop()?;
161161

162162
// Load Python app
163-
let app_function = Python::with_gil(|py| -> Result<PyObject, HandlerError> {
163+
let app_function = Python::attach(|py| -> Result<Py<PyAny>, HandlerError> {
164164
// Load and compile Python module
165165
let entrypoint = docroot
166166
.join(format!("{}.py", target.file))
@@ -241,7 +241,7 @@ impl Handler for Asgi {
241241
tokio::spawn(collect_response_messages(tx_receiver, response_tx));
242242

243243
// Submit the ASGI app call to Python event loop
244-
Python::with_gil(|py| {
244+
Python::attach(|py| {
245245
let scope_py = scope.into_pyobject(py)?;
246246
let coro = self
247247
.app_function
@@ -361,8 +361,8 @@ fn setup_python_paths(py: Python, docroot: &Path) -> PyResult<()> {
361361
}
362362

363363
/// Start a Python thread that runs the event loop forever
364-
fn start_python_event_loop_thread(event_loop: PyObject) {
365-
Python::with_gil(|py| {
364+
fn start_python_event_loop_thread(event_loop: Py<PyAny>) {
365+
Python::attach(|py| {
366366
// Set the event loop for this thread and run it
367367
let asyncio = py.import("asyncio")?;
368368
asyncio.call_method1("set_event_loop", (event_loop.bind(py),))?;

src/asgi/receiver.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,23 @@ impl Receiver {
5050
ReceiverType::Http(rx) => {
5151
let message = rx.lock().await.recv().await;
5252
if let Some(msg) = message {
53-
Python::with_gil(|py| Ok(msg.into_pyobject(py)?.unbind()))
53+
Python::attach(|py| Ok(msg.into_pyobject(py)?.unbind()))
5454
} else {
5555
Err(PyValueError::new_err("No message received"))
5656
}
5757
}
5858
ReceiverType::WebSocket(rx) => {
5959
let message = rx.lock().await.recv().await;
6060
if let Some(msg) = message {
61-
Python::with_gil(|py| Ok(msg.into_pyobject(py)?.unbind()))
61+
Python::attach(|py| Ok(msg.into_pyobject(py)?.unbind()))
6262
} else {
6363
Err(PyValueError::new_err("No message received"))
6464
}
6565
}
6666
ReceiverType::Lifespan(rx) => {
6767
let message = rx.lock().await.recv().await;
6868
if let Some(msg) = message {
69-
Python::with_gil(|py| Ok(msg.into_pyobject(py)?.unbind()))
69+
Python::attach(|py| Ok(msg.into_pyobject(py)?.unbind()))
7070
} else {
7171
Err(PyValueError::new_err("No message received"))
7272
}

src/asgi/sender.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ impl Sender {
5252

5353
#[pymethods]
5454
impl Sender {
55-
async fn __call__(&mut self, args: Py<PyDict>) -> PyResult<PyObject> {
55+
async fn __call__(&mut self, args: Py<PyDict>) -> PyResult<Py<PyAny>> {
5656
// Create acknowledgment channel
5757
let (ack_tx, ack_rx) = oneshot::channel::<()>();
5858

5959
// Send message with acknowledgment channel
60-
let send_result: PyResult<()> = Python::with_gil(|py| {
60+
let send_result: PyResult<()> = Python::attach(|py| {
6161
let args_dict = args.bind(py);
6262
match &self.0 {
6363
SenderType::Http(tx) => {
@@ -95,7 +95,7 @@ impl Sender {
9595

9696
// Wait for acknowledgment
9797
match ack_rx.await {
98-
Ok(()) => Python::with_gil(|py| Ok(py.None())),
98+
Ok(()) => Python::attach(|py| Ok(py.None())),
9999
Err(_) => Err(PyValueError::new_err("message not acknowledged")),
100100
}
101101
}

0 commit comments

Comments
 (0)