diff --git a/Cargo.lock b/Cargo.lock index c3f159b57..e02e2837b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3199,9 +3199,9 @@ checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] name = "pyo3" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884" +checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219" dependencies = [ "cfg-if", "indoc", @@ -3217,9 +3217,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38" +checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999" dependencies = [ "once_cell", "target-lexicon", @@ -3227,9 +3227,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636" +checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33" dependencies = [ "libc", "pyo3-build-config", @@ -3237,9 +3237,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453" +checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -3249,9 +3249,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.22.6" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe" +checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a" dependencies = [ "heck", "proc-macro2", @@ -4082,9 +4082,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" diff --git a/Cargo.toml b/Cargo.toml index 6f80f0e74..6f0f59c1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] } axum = "0.7" tower = "0.5" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } -pyo3 = { version = "0.22", features = ["abi3-py310"] } +pyo3 = { version = "0.24", features = ["abi3-py310"] } # Phase D PR-D1: AWS SigV4 signing for native Bedrock InvokeModel route. # `aws-sigv4` provides the canonical-request + signing-key implementation; # `aws-config` resolves credentials from the standard provider chain diff --git a/crates/headroom-py/src/lib.rs b/crates/headroom-py/src/lib.rs index e47c9b649..d753244a8 100644 --- a/crates/headroom-py/src/lib.rs +++ b/crates/headroom-py/src/lib.rs @@ -41,7 +41,7 @@ use headroom_core::transforms::{ SearchCompressorConfig as RustSearchConfig, SearchCompressorStats as RustSearchStats, }; use pyo3::prelude::*; -use pyo3::types::{PyBytes, PyDict, PyString}; +use pyo3::types::{PyBytes, PyDict}; /// Identity stub used by the Python smoke test to verify linkage. #[pyfunction] @@ -75,7 +75,7 @@ fn build_crush_array_dict<'py>( compacted: Option, compaction_kind: Option<&'static str>, ) -> Bound<'py, PyDict> { - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); dict.set_item("items", kept_json).unwrap(); dict.set_item("ccr_hash", ccr_hash).unwrap(); dict.set_item("dropped_summary", dropped_summary).unwrap(); @@ -859,32 +859,31 @@ impl PyDetectionResult { /// the underlying Rust value. #[getter] fn metadata<'py>(&self, py: Python<'py>) -> PyResult> { - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); for (k, v) in &self.inner.metadata { // Convert each JSON value into the closest Python primitive. // Detection metadata is always a flat dict of scalars (ints, // bools, strings) so we don't need to recurse. - let py_value: PyObject = match v { - serde_json::Value::Bool(b) => b.into_py(py), + match v { + serde_json::Value::Bool(b) => dict.set_item(k, b)?, serde_json::Value::Number(n) => { if let Some(i) = n.as_u64() { - i.into_py(py) + dict.set_item(k, i)? } else if let Some(i) = n.as_i64() { - i.into_py(py) + dict.set_item(k, i)? } else if let Some(f) = n.as_f64() { - f.into_py(py) + dict.set_item(k, f)? } else { - py.None() + dict.set_item(k, py.None())? } } - serde_json::Value::String(s) => PyString::new_bound(py, s).into_py(py), - serde_json::Value::Null => py.None(), + serde_json::Value::String(s) => dict.set_item(k, s)?, + serde_json::Value::Null => dict.set_item(k, py.None())?, // Detection never emits arrays / objects in metadata // today; if it ever does, fall through to JSON-string for // visibility rather than silently dropping. - other => PyString::new_bound(py, &other.to_string()).into_py(py), + other => dict.set_item(k, other.to_string())?, }; - dict.set_item(k, py_value)?; } Ok(dict) } @@ -1019,7 +1018,7 @@ fn content_has_error_indicators(text: &str) -> bool { #[pyfunction] fn keyword_registry_snapshot(py: Python<'_>) -> Py { let registry = KeywordRegistry::default_set(); - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); for (key, words) in registry.as_map() { dict.set_item(key, words).unwrap(); } @@ -1130,7 +1129,7 @@ impl PySearchCompressionResult { } #[getter] fn summaries<'py>(&self, py: Python<'py>) -> Bound<'py, PyDict> { - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); for (k, v) in &self.inner.summaries { dict.set_item(k, v).unwrap(); } @@ -1330,7 +1329,7 @@ impl PyLogCompressionResult { } #[getter] fn stats<'py>(&self, py: Python<'py>) -> Bound<'py, PyDict> { - let dict = PyDict::new_bound(py); + let dict = PyDict::new(py); for (k, v) in &self.inner.stats { dict.set_item(k, v).unwrap(); } @@ -1522,7 +1521,7 @@ fn compress_openai_responses_live_zone( .collect(); let reason = rust_summarize_openai_responses_no_change_reason(&manifest).to_string(); ( - PyBytes::new_bound(py, body).unbind(), + PyBytes::new(py, body).unbind(), false, saved, transforms, @@ -1540,7 +1539,7 @@ fn compress_openai_responses_live_zone( .map(String::from) .collect(); ( - PyBytes::new_bound(py, bytes).unbind(), + PyBytes::new(py, bytes).unbind(), true, saved, transforms, @@ -1551,7 +1550,7 @@ fn compress_openai_responses_live_zone( // BodyNotJson / NoMessagesArray are non-fatal: nothing to // compress, fall through to passthrough byte-for-byte. ( - PyBytes::new_bound(py, body).unbind(), + PyBytes::new(py, body).unbind(), false, 0, Vec::new(),