From a81ed4a5232619f7b45734fd9da4448721ebc83a Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sat, 15 Mar 2025 08:30:15 +0200 Subject: [PATCH] bindings/python: Update PyO3 dependency to 0.24.0 --- Cargo.lock | 24 ++++----- bindings/python/Cargo.toml | 4 +- bindings/python/src/lib.rs | 105 +++++++++++++------------------------ 3 files changed, 51 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e9165f6b..614094b24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2432,9 +2432,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884" +checksum = "7f1c6c3591120564d64db2261bec5f910ae454f01def849b9c22835a84695e86" dependencies = [ "anyhow", "cfg-if", @@ -2451,9 +2451,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38" +checksum = "e9b6c2b34cf71427ea37c7001aefbaeb85886a074795e35f161f5aecc7620a7a" dependencies = [ "once_cell", "target-lexicon", @@ -2461,9 +2461,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636" +checksum = "5507651906a46432cdda02cd02dd0319f6064f1374c9147c45b978621d2c3a9c" dependencies = [ "libc", "pyo3-build-config", @@ -2471,9 +2471,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453" +checksum = "b0d394b5b4fd8d97d48336bb0dd2aebabad39f1d294edd6bcd2cccf2eefe6f42" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2483,9 +2483,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe" +checksum = "fd72da09cfa943b1080f621f024d2ef7e2773df7badd51aa30a2be1f8caa7c8e" dependencies = [ "heck", "proc-macro2", @@ -3104,9 +3104,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "tempfile" diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml index d93baf1c8..402a3a760 100644 --- a/bindings/python/Cargo.toml +++ b/bindings/python/Cargo.toml @@ -18,9 +18,9 @@ extension-module = ["pyo3/extension-module"] [dependencies] anyhow = "1.0" limbo_core = { path = "../../core", features = ["io_uring"] } -pyo3 = { version = "0.22.4", features = ["anyhow"] } +pyo3 = { version = "0.24.0", features = ["anyhow"] } [build-dependencies] version_check = "0.9.5" # used where logic has to be version/distribution specific, e.g. pypy -pyo3-build-config = { version = "0.22.4" } +pyo3-build-config = { version = "0.24.0" } diff --git a/bindings/python/src/lib.rs b/bindings/python/src/lib.rs index f6c505ba9..6b38f503c 100644 --- a/bindings/python/src/lib.rs +++ b/bindings/python/src/lib.rs @@ -1,8 +1,7 @@ use anyhow::Result; use errors::*; use pyo3::prelude::*; -use pyo3::types::PyList; -use pyo3::types::PyTuple; +use pyo3::types::{PyBytes, PyList, PyTuple}; use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; @@ -28,25 +27,7 @@ struct Description { null_ok: Option, } -impl IntoPy> for Description { - fn into_py(self, py: Python<'_>) -> Py { - PyTuple::new_bound( - py, - vec![ - self.name.into_py(py), - self.type_code.into_py(py), - self.display_size.into_py(py), - self.internal_size.into_py(py), - self.precision.into_py(py), - self.scale.into_py(py), - self.null_ok.into_py(py), - ], - ) - .into() - } -} - -#[pyclass] +#[pyclass(unsendable)] pub struct Cursor { /// This read/write attribute specifies the number of rows to fetch at a time with `.fetchmany()`. /// It defaults to `1`, meaning it fetches a single row at a time. @@ -81,8 +62,12 @@ pub struct Cursor { smt: Option>>, } -// SAFETY: The limbo_core crate guarantees that `Cursor` is thread-safe. -unsafe impl Send for Cursor {} +#[pyclass(unsendable)] +#[derive(Clone)] +pub struct Connection { + conn: Rc, + io: Arc, +} #[allow(unused_variables, clippy::arc_with_non_send_sync)] #[pymethods] @@ -135,7 +120,7 @@ impl Cursor { })? { limbo_core::StepResult::Row => { let row = stmt.row().unwrap(); - let py_row = row_to_py(py, &row); + let py_row = row_to_py(py, &row)?; return Ok(Some(py_row)); } limbo_core::StepResult::IO => { @@ -171,7 +156,7 @@ impl Cursor { })? { limbo_core::StepResult::Row => { let row = stmt.row().unwrap(); - let py_row = row_to_py(py, &row); + let py_row = row_to_py(py, &row)?; results.push(py_row); } limbo_core::StepResult::IO => { @@ -230,16 +215,6 @@ fn stmt_is_ddl(sql: &str) -> bool { sql.starts_with("CREATE") || sql.starts_with("ALTER") || sql.starts_with("DROP") } -#[pyclass] -#[derive(Clone)] -pub struct Connection { - conn: Rc, - io: Arc, -} - -// SAFETY: The limbo_core crate guarantees that `Connection` is thread-safe. -unsafe impl Send for Connection {} - #[pymethods] impl Connection { pub fn cursor(&self) -> Result { @@ -298,21 +273,24 @@ pub fn connect(path: &str) -> Result { } } -fn row_to_py(py: Python, row: &limbo_core::Row) -> PyObject { - let py_values: Vec = row - .get_values() - .iter() - .map(|value| match value { - limbo_core::OwnedValue::Null => py.None(), - limbo_core::OwnedValue::Integer(i) => i.to_object(py), - limbo_core::OwnedValue::Float(f) => f.to_object(py), - limbo_core::OwnedValue::Text(s) => s.as_str().to_object(py), - limbo_core::OwnedValue::Blob(b) => b.to_object(py), +fn row_to_py(py: Python, row: &limbo_core::Row) -> Result { + let mut py_values = Vec::new(); + for value in row.get_values() { + match value { + limbo_core::OwnedValue::Null => py_values.push(py.None()), + limbo_core::OwnedValue::Integer(i) => py_values.push(i.into_pyobject(py)?.into()), + limbo_core::OwnedValue::Float(f) => py_values.push(f.into_pyobject(py)?.into()), + limbo_core::OwnedValue::Text(s) => py_values.push(s.as_str().into_pyobject(py)?.into()), + limbo_core::OwnedValue::Blob(b) => { + py_values.push(PyBytes::new(py, b.as_slice()).into()) + } _ => unreachable!(), - }) - .collect(); - - PyTuple::new_bound(py, &py_values).to_object(py) + } + } + Ok(PyTuple::new(py, &py_values) + .unwrap() + .into_pyobject(py)? + .into()) } #[pymodule] @@ -321,24 +299,15 @@ fn _limbo(m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(connect, m)?)?; - m.add("Warning", m.py().get_type_bound::())?; - m.add("Error", m.py().get_type_bound::())?; - m.add("InterfaceError", m.py().get_type_bound::())?; - m.add("DatabaseError", m.py().get_type_bound::())?; - m.add("DataError", m.py().get_type_bound::())?; - m.add( - "OperationalError", - m.py().get_type_bound::(), - )?; - m.add("IntegrityError", m.py().get_type_bound::())?; - m.add("InternalError", m.py().get_type_bound::())?; - m.add( - "ProgrammingError", - m.py().get_type_bound::(), - )?; - m.add( - "NotSupportedError", - m.py().get_type_bound::(), - )?; + m.add("Warning", m.py().get_type::())?; + m.add("Error", m.py().get_type::())?; + m.add("InterfaceError", m.py().get_type::())?; + m.add("DatabaseError", m.py().get_type::())?; + m.add("DataError", m.py().get_type::())?; + m.add("OperationalError", m.py().get_type::())?; + m.add("IntegrityError", m.py().get_type::())?; + m.add("InternalError", m.py().get_type::())?; + m.add("ProgrammingError", m.py().get_type::())?; + m.add("NotSupportedError", m.py().get_type::())?; Ok(()) }