diff --git a/Cargo.toml b/Cargo.toml index b5a6d9c..393cfc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ anyhow = "1.0.82" chrono = "0.4.38" indexmap = "2.2.6" nom = "7.1.3" -pyo3 = { version = "=0.22.6", features = ["chrono"] } +pyo3 = { version = "=0.23.1", features = ["chrono"] } rayon = "1.10.0" regex = "1.10.4" serde = { version = "1.0.200", features = ["derive"] } diff --git a/src/inventory.rs b/src/inventory.rs index a5d9f68..ebb9a24 100644 --- a/src/inventory.rs +++ b/src/inventory.rs @@ -76,17 +76,17 @@ impl Inventory { /// /// The structure of the returned dict should match Python reclass the structure of the dict /// returned by Python reclass's `inventory()` method. - fn as_dict(&self, py: Python<'_>) -> PyResult> { - let dict = PyDict::new_bound(py); - dict.set_item("applications", self.applications.clone().into_py(py))?; - dict.set_item("classes", self.classes.clone().into_py(py))?; - let nodes_dict = PyDict::new_bound(py); + fn as_dict<'py>(&self, py: Python<'py>) -> PyResult> { + let dict = PyDict::new(py); + dict.set_item("applications", self.applications.clone().into_pyobject(py)?)?; + dict.set_item("classes", self.classes.clone().into_pyobject(py)?)?; + let nodes_dict = PyDict::new(py); for (name, info) in &self.nodes { nodes_dict.set_item(name, info.as_dict(py)?)?; } dict.set_item("nodes", nodes_dict)?; - let reclass_dict = PyDict::new_bound(py); + let reclass_dict = PyDict::new(py); let ts = Local::now(); reclass_dict.set_item("timestamp", ts.format("%c").to_string())?; dict.set_item("__reclass__", reclass_dict)?; diff --git a/src/node/nodeinfo.rs b/src/node/nodeinfo.rs index 4712428..41f98fe 100644 --- a/src/node/nodeinfo.rs +++ b/src/node/nodeinfo.rs @@ -160,13 +160,13 @@ impl NodeInfo { /// Returns the NodeInfo `parameters` field as a PyDict #[getter] - fn parameters(&self, py: Python<'_>) -> PyResult> { + fn parameters<'py>(&self, py: Python<'py>) -> PyResult> { self.parameters.as_py_dict(py) } /// Returns the NodeInfo `exports` field as a PyDict #[getter] - fn exports(&self, py: Python<'_>) -> PyResult> { + fn exports<'py>(&self, py: Python<'py>) -> PyResult> { #[cfg(debug_assertions)] eprintln!("reclass_rs doesn't support exports yet!"); self.exports.as_py_dict(py) @@ -176,24 +176,30 @@ impl NodeInfo { /// /// This method generates a PyDict which should be structured identically to Python Reclass's /// `nodeinfo` return value. - pub(crate) fn as_dict(&self, py: Python<'_>) -> PyResult> { - let dict = PyDict::new_bound(py); + pub(crate) fn as_dict<'py>(&self, py: Python<'py>) -> PyResult> { + let dict = PyDict::new(py); dict.set_item("__reclass__", self.reclass_as_dict(py)?)?; - dict.set_item("applications", self.applications.clone().into_py(py))?; - dict.set_item("classes", self.classes.clone().into_py(py))?; - dict.set_item("environment", self.reclass.environment.clone().into_py(py))?; + dict.set_item("applications", self.applications.clone().into_pyobject(py)?)?; + dict.set_item("applications", self.applications.clone().into_pyobject(py)?)?; + dict.set_item( + "environment", + self.reclass.environment.clone().into_pyobject(py)?, + )?; dict.set_item("exports", self.exports(py)?)?; dict.set_item("parameters", self.parameters(py)?)?; Ok(dict.into()) } /// Returns the NodeInfo `meta` field as a PyDict - fn reclass_as_dict(&self, py: Python<'_>) -> PyResult> { - let dict = PyDict::new_bound(py); - dict.set_item("node", self.reclass.node.clone().into_py(py))?; - dict.set_item("name", self.reclass.name.clone().into_py(py))?; - dict.set_item("uri", self.reclass.uri.clone().into_py(py))?; - dict.set_item("environment", self.reclass.environment.clone().into_py(py))?; + fn reclass_as_dict<'py>(&self, py: Python<'py>) -> PyResult> { + let dict = PyDict::new(py); + dict.set_item("node", self.reclass.node.clone().into_pyobject(py)?)?; + dict.set_item("name", self.reclass.name.clone().into_pyobject(py)?)?; + dict.set_item("uri", self.reclass.uri.clone().into_pyobject(py)?)?; + dict.set_item( + "environment", + self.reclass.environment.clone().into_pyobject(py)?, + )?; // Format time as strftime %c for Python compatibility dict.set_item( "timestamp", diff --git a/src/types/from.rs b/src/types/from.rs index a3f0323..bbd96ed 100644 --- a/src/types/from.rs +++ b/src/types/from.rs @@ -132,7 +132,7 @@ impl TryFrom> for Value { "list" => { let v = value.downcast::()?; let mut items: Vec = vec![]; - for it in v.iter()? { + for it in v.try_iter()? { items.push(TryInto::try_into(it?)?); } Ok(Self::Sequence(items)) diff --git a/src/types/mapping.rs b/src/types/mapping.rs index 5719b0e..361c9b9 100644 --- a/src/types/mapping.rs +++ b/src/types/mapping.rs @@ -355,8 +355,8 @@ impl Mapping { } /// Converts the `Mapping` into a `PyDict`. - pub fn as_py_dict(&self, py: Python<'_>) -> PyResult> { - let dict = PyDict::new_bound(py); + pub fn as_py_dict<'py>(&self, py: Python<'py>) -> PyResult> { + let dict = PyDict::new(py); for (k, v) in self { let pyk = k.as_py_obj(py)?; @@ -364,7 +364,7 @@ impl Mapping { dict.set_item(pyk, pyv)?; } - Ok(dict.into()) + Ok(dict.into_pyobject(py)?) } /// Checks if the provided key is marked as constant. @@ -740,17 +740,12 @@ mod mapping_tests { ); pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let pym = m.as_py_dict(py).unwrap(); - let m = pym.bind(py); + let m = m.as_py_dict(py).unwrap(); assert_eq!(m.len(), 6); assert_eq!(format!("{:?}", m.keys()), "['a', 'b', 'c', 'd', 'e', 'f']"); let a = m.get_item(&"a").unwrap().unwrap(); assert!(a.is_instance_of::()); - assert!(a - .downcast_exact::() - .unwrap() - .eq(1.into_py(py)) - .unwrap()); + assert!(a.downcast_exact::().unwrap().eq(&1)); let f = m.get_item(&"f").unwrap().unwrap(); assert!(f.is_instance_of::()); let f = f.downcast_exact::().unwrap(); diff --git a/src/types/value.rs b/src/types/value.rs index 1c00270..fbd9310 100644 --- a/src/types/value.rs +++ b/src/types/value.rs @@ -426,21 +426,21 @@ impl Value { /// Converts the `Value` into a `PyObject`. #[allow(clippy::missing_panics_doc)] - pub fn as_py_obj(&self, py: Python<'_>) -> PyResult { + pub fn as_py_obj<'py>(&self, py: Python<'py>) -> PyResult> { let obj = match self { - Value::Literal(s) | Value::String(s) => s.into_py(py), - Value::Bool(b) => b.into_py(py), + Value::Literal(s) | Value::String(s) => s.into_pyobject(py)?.into_any(), + Value::Bool(b) => pyo3::types::PyBool::new(py, *b).to_owned().into_any(), Value::Number(n) => { if n.is_i64() { // NOTE(sg): We allow the missing panics doc because we already checked that // `as_i64()` can't panic here. - n.as_i64().unwrap().into_py(py) + n.as_i64().unwrap().into_pyobject(py)?.into_any() } else if n.is_u64() { - n.as_u64().unwrap().into_py(py) + n.as_u64().unwrap().into_pyobject(py)?.into_any() } else if n.is_f64() { - n.as_f64().unwrap().into_py(py) + n.as_f64().unwrap().into_pyobject(py)?.into_any() } else { - Option::<()>::None.into_py(py) + Option::<()>::None.into_pyobject(py)?.into_any() } } Value::Sequence(s) => { @@ -448,10 +448,10 @@ impl Value { for v in s { pyseq.push(v.as_py_obj(py)?); } - pyseq.into_py(py) + pyseq.into_pyobject(py)?.into_any() } - Value::Mapping(m) => m.as_py_dict(py)?.into(), - Value::Null => Option::<()>::None.into_py(py), + Value::Mapping(m) => m.as_py_dict(py)?.into_any(), + Value::Null => Option::<()>::None.into_pyobject(py)?.into_any(), // ValueList should never get emitted to Python Value::ValueList(_) => unreachable!(), }; diff --git a/src/types/value/value_as_py_obj_tests.rs b/src/types/value/value_as_py_obj_tests.rs index e790ce3..0bd888a 100644 --- a/src/types/value/value_as_py_obj_tests.rs +++ b/src/types/value/value_as_py_obj_tests.rs @@ -3,8 +3,7 @@ use super::*; fn test_as_py_obj_null() { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let pyv = Value::Null.as_py_obj(py).unwrap(); - let v = pyv.bind(py); + let v = Value::Null.as_py_obj(py).unwrap(); assert!(v.is_none()); }); } @@ -13,8 +12,7 @@ fn test_as_py_obj_null() { fn test_as_py_obj_bool() { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let pyb = Value::Bool(true).as_py_obj(py).unwrap(); - let b = pyb.bind(py); + let b = Value::Bool(true).as_py_obj(py).unwrap(); assert!(b.is_instance_of::()); assert!(b.downcast_exact::().unwrap().is_true()); }); @@ -27,13 +25,9 @@ fn test_as_py_obj_int() { let nums: Vec = vec![5.into(), (-2i64).into()]; for n in nums { let pyn = n.as_py_obj(py).unwrap(); - let n = pyn.bind(py); - assert!(n.is_instance_of::()); - assert!(n - .downcast_exact::() - .unwrap() - .eq(n.into_py(py)) - .unwrap()); + let n = n.as_i64().unwrap(); + assert!(pyn.is_instance_of::()); + assert!(pyn.downcast_exact::().unwrap().eq(&n)); } }); } @@ -43,14 +37,12 @@ fn test_as_py_obj_float() { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let n: Value = 3.14.into(); - let pyn = n.as_py_obj(py).unwrap(); - let n = pyn.bind(py); + let n = n.as_py_obj(py).unwrap(); assert!(n.is_instance_of::()); assert!(n .downcast_exact::() .unwrap() - .eq(3.14.into_py(py)) - .unwrap()); + .eq(&3.14)); }); } @@ -59,13 +51,12 @@ fn test_as_py_obj_sequence() { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { let s: Value = vec![1, 2, 3].into(); - let pys = s.as_py_obj(py).unwrap(); - let s = pys.bind(py); + let s = s.as_py_obj(py).unwrap(); assert!(s.is_instance_of::()); assert!(s .downcast_exact::() .unwrap() - .eq(pyo3::types::PyList::new_bound(py, vec![1, 2, 3])) + .eq(&vec![1, 2, 3]) .unwrap()); }); } @@ -74,10 +65,9 @@ fn test_as_py_obj_sequence() { fn test_as_py_obj_string() { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let pys = std::convert::Into::::into("hello, world") + let s = std::convert::Into::::into("hello, world") .as_py_obj(py) .unwrap(); - let s = pys.bind(py); assert!(s.is_instance_of::()); assert_eq!( s.downcast_exact::() diff --git a/tests/test_py.rs b/tests/test_py.rs index 7045f25..8946965 100644 --- a/tests/test_py.rs +++ b/tests/test_py.rs @@ -1,3 +1,5 @@ +use std::ffi::CString; + use pyo3::prelude::*; use pyo3::types::PyDict; @@ -9,11 +11,12 @@ fn test_reclass() { Python::with_gil(|py| { let r = Reclass::new("./tests/inventory", "nodes", "classes", false) .unwrap() - .into_py(py); - let locals = PyDict::new_bound(py); + .into_pyobject(py) + .unwrap(); + let locals = PyDict::new(py); locals.set_item("r", r).unwrap(); - py.run_bound( - r#"assert r and "Reclass" in str(type(r))"#, + py.run( + &CString::new(r#"assert r and "Reclass" in str(type(r))"#).unwrap(), None, Some(&locals), )