From c359f5ca1d1cf1207cf65a63983d0feb5f78401a Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Mon, 12 Feb 2024 00:55:56 +0100 Subject: [PATCH] deprecate `PyDict::new` constructor (#3823) * deprecate `PyDict::new` * update benchmarks * convert `test_frompyobject` --- guide/src/conversions/traits.md | 2 +- pyo3-benches/benches/bench_any.rs | 12 +-- pyo3-benches/benches/bench_bigint.rs | 27 ++--- pyo3-benches/benches/bench_decimal.rs | 8 +- pyo3-benches/benches/bench_dict.rs | 26 ++--- pyo3-benches/benches/bench_extract.rs | 25 +++-- src/conversions/num_bigint.rs | 8 +- src/conversions/smallvec.rs | 2 +- src/conversions/std/time.rs | 6 +- src/impl_/extract_argument.rs | 2 +- src/instance.rs | 8 +- src/marshal.rs | 14 +-- src/sync.rs | 14 +-- src/types/any.rs | 24 ++--- src/types/dict.rs | 7 ++ src/types/ellipsis.rs | 2 +- src/types/none.rs | 2 +- src/types/notimplemented.rs | 4 +- tests/test_frompyobject.rs | 129 ++++++++++++++---------- tests/test_proto_methods.rs | 2 +- tests/ui/wrong_aspyref_lifetimes.rs | 6 +- tests/ui/wrong_aspyref_lifetimes.stderr | 12 +-- 22 files changed, 189 insertions(+), 153 deletions(-) diff --git a/guide/src/conversions/traits.md b/guide/src/conversions/traits.md index 71e823f8..b46e5c02 100644 --- a/guide/src/conversions/traits.md +++ b/guide/src/conversions/traits.md @@ -86,7 +86,7 @@ struct RustyStruct { # use pyo3::types::PyDict; # fn main() -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> { -# let dict = PyDict::new(py); +# let dict = PyDict::new_bound(py); # dict.set_item("my_string", "test")?; # # let rustystruct: RustyStruct = dict.extract()?; diff --git a/pyo3-benches/benches/bench_any.rs b/pyo3-benches/benches/bench_any.rs index bfd010ef..b77ab956 100644 --- a/pyo3-benches/benches/bench_any.rs +++ b/pyo3-benches/benches/bench_any.rs @@ -1,11 +1,11 @@ use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criterion}; use pyo3::{ + prelude::*, types::{ PyBool, PyByteArray, PyBytes, PyDict, PyFloat, PyFrozenSet, PyInt, PyList, PyMapping, PySequence, PySet, PyString, PyTuple, }, - PyAny, PyResult, Python, }; #[derive(PartialEq, Eq, Debug)] @@ -27,7 +27,7 @@ enum ObjectType { Unknown, } -fn find_object_type(obj: &PyAny) -> ObjectType { +fn find_object_type(obj: &Bound<'_, PyAny>) -> ObjectType { if obj.is_none() { ObjectType::None } else if obj.is_instance_of::() { @@ -63,17 +63,17 @@ fn find_object_type(obj: &PyAny) -> ObjectType { fn bench_identify_object_type(b: &mut Bencher<'_>) { Python::with_gil(|py| { - let obj = py.eval("object()", None, None).unwrap(); + let obj = py.eval_bound("object()", None, None).unwrap(); - b.iter(|| find_object_type(obj)); + b.iter(|| find_object_type(&obj)); - assert_eq!(find_object_type(obj), ObjectType::Unknown); + assert_eq!(find_object_type(&obj), ObjectType::Unknown); }); } fn bench_collect_generic_iterator(b: &mut Bencher<'_>) { Python::with_gil(|py| { - let collection = py.eval("list(range(1 << 20))", None, None).unwrap(); + let collection = py.eval_bound("list(range(1 << 20))", None, None).unwrap(); b.iter(|| { collection diff --git a/pyo3-benches/benches/bench_bigint.rs b/pyo3-benches/benches/bench_bigint.rs index d3c71629..4a50b437 100644 --- a/pyo3-benches/benches/bench_bigint.rs +++ b/pyo3-benches/benches/bench_bigint.rs @@ -1,14 +1,15 @@ use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Bencher, Criterion}; -use pyo3::{types::PyDict, PyAny, Python}; +use pyo3::prelude::*; +use pyo3::types::PyDict; use num_bigint::BigInt; fn extract_bigint_extract_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).extract::() { + bench.iter(|| match black_box(&d).extract::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -17,10 +18,10 @@ fn extract_bigint_extract_fail(bench: &mut Bencher<'_>) { fn extract_bigint_small(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let int = py.eval("-42", None, None).unwrap(); + let int = py.eval_bound("-42", None, None).unwrap(); bench.iter(|| { - let v = black_box(int).extract::().unwrap(); + let v = black_box(&int).extract::().unwrap(); black_box(v); }); }); @@ -28,10 +29,10 @@ fn extract_bigint_small(bench: &mut Bencher<'_>) { fn extract_bigint_big_negative(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let int = py.eval("-10**300", None, None).unwrap(); + let int = py.eval_bound("-10**300", None, None).unwrap(); bench.iter(|| { - let v = black_box(int).extract::().unwrap(); + let v = black_box(&int).extract::().unwrap(); black_box(v); }); }); @@ -39,10 +40,10 @@ fn extract_bigint_big_negative(bench: &mut Bencher<'_>) { fn extract_bigint_big_positive(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let int = py.eval("10**300", None, None).unwrap(); + let int = py.eval_bound("10**300", None, None).unwrap(); bench.iter(|| { - let v = black_box(int).extract::().unwrap(); + let v = black_box(&int).extract::().unwrap(); black_box(v); }); }); @@ -50,10 +51,10 @@ fn extract_bigint_big_positive(bench: &mut Bencher<'_>) { fn extract_bigint_huge_negative(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let int = py.eval("-10**3000", None, None).unwrap(); + let int = py.eval_bound("-10**3000", None, None).unwrap(); bench.iter(|| { - let v = black_box(int).extract::().unwrap(); + let v = black_box(&int).extract::().unwrap(); black_box(v); }); }); @@ -61,10 +62,10 @@ fn extract_bigint_huge_negative(bench: &mut Bencher<'_>) { fn extract_bigint_huge_positive(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let int = py.eval("10**3000", None, None).unwrap(); + let int = py.eval_bound("10**3000", None, None).unwrap(); bench.iter(|| { - let v = black_box(int).extract::().unwrap(); + let v = black_box(&int).extract::().unwrap(); black_box(v); }); }); diff --git a/pyo3-benches/benches/bench_decimal.rs b/pyo3-benches/benches/bench_decimal.rs index 203756b5..6db6704b 100644 --- a/pyo3-benches/benches/bench_decimal.rs +++ b/pyo3-benches/benches/bench_decimal.rs @@ -6,20 +6,20 @@ use rust_decimal::Decimal; fn decimal_via_extract(b: &mut Bencher<'_>) { Python::with_gil(|py| { - let locals = PyDict::new(py); - py.run( + let locals = PyDict::new_bound(py); + py.run_bound( r#" import decimal py_dec = decimal.Decimal("0.0") "#, None, - Some(locals), + Some(&locals), ) .unwrap(); let py_dec = locals.get_item("py_dec").unwrap().unwrap(); b.iter(|| { - let _: Decimal = black_box(py_dec).extract().unwrap(); + let _: Decimal = black_box(&py_dec).extract().unwrap(); }); }) } diff --git a/pyo3-benches/benches/bench_dict.rs b/pyo3-benches/benches/bench_dict.rs index 06559519..072dd940 100644 --- a/pyo3-benches/benches/bench_dict.rs +++ b/pyo3-benches/benches/bench_dict.rs @@ -8,10 +8,10 @@ use std::hint::black_box; fn iter_dict(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py); + let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); let mut sum = 0; b.iter(|| { - for (k, _v) in dict { + for (k, _v) in dict.iter() { let i: u64 = k.extract().unwrap(); sum += i; } @@ -22,14 +22,14 @@ fn iter_dict(b: &mut Bencher<'_>) { fn dict_new(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 50_000; - b.iter(|| (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py)); + b.iter_with_large_drop(|| (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py)); }); } fn dict_get_item(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 50_000; - let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py); + let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); let mut sum = 0; b.iter(|| { for i in 0..LEN { @@ -47,16 +47,16 @@ fn dict_get_item(b: &mut Bencher<'_>) { fn extract_hashmap(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py); - b.iter(|| HashMap::::extract(dict)); + let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); + b.iter(|| HashMap::::extract_bound(&dict)); }); } fn extract_btreemap(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py); - b.iter(|| BTreeMap::::extract(dict)); + let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); + b.iter(|| BTreeMap::::extract_bound(&dict)); }); } @@ -64,19 +64,15 @@ fn extract_btreemap(b: &mut Bencher<'_>) { fn extract_hashbrown_map(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py); - b.iter(|| hashbrown::HashMap::::extract(dict)); + let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); + b.iter(|| hashbrown::HashMap::::extract_bound(&dict)); }); } fn mapping_from_dict(b: &mut Bencher<'_>) { Python::with_gil(|py| { const LEN: usize = 100_000; - let dict = &(0..LEN as u64) - .map(|i| (i, i * 2)) - .into_py_dict(py) - .to_object(py) - .into_bound(py); + let dict = &(0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py); b.iter(|| black_box(dict).downcast::().unwrap()); }); } diff --git a/pyo3-benches/benches/bench_extract.rs b/pyo3-benches/benches/bench_extract.rs index 479bd0fd..1c783c3b 100644 --- a/pyo3-benches/benches/bench_extract.rs +++ b/pyo3-benches/benches/bench_extract.rs @@ -3,7 +3,6 @@ use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Benc use pyo3::{ prelude::*, types::{PyDict, PyFloat, PyInt, PyString}, - IntoPy, PyAny, PyObject, Python, }; fn extract_str_extract_success(bench: &mut Bencher<'_>) { @@ -16,9 +15,9 @@ fn extract_str_extract_success(bench: &mut Bencher<'_>) { fn extract_str_extract_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).extract::<&str>() { + bench.iter(|| match black_box(&d).extract::<&str>() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -39,9 +38,9 @@ fn extract_str_downcast_success(bench: &mut Bencher<'_>) { fn extract_str_downcast_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).downcast::() { + bench.iter(|| match black_box(&d).downcast::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -62,9 +61,9 @@ fn extract_int_extract_success(bench: &mut Bencher<'_>) { fn extract_int_extract_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).extract::() { + bench.iter(|| match black_box(&d).extract::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -86,9 +85,9 @@ fn extract_int_downcast_success(bench: &mut Bencher<'_>) { fn extract_int_downcast_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).downcast::() { + bench.iter(|| match black_box(&d).downcast::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -109,9 +108,9 @@ fn extract_float_extract_success(bench: &mut Bencher<'_>) { fn extract_float_extract_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).extract::() { + bench.iter(|| match black_box(&d).extract::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); @@ -133,9 +132,9 @@ fn extract_float_downcast_success(bench: &mut Bencher<'_>) { fn extract_float_downcast_fail(bench: &mut Bencher<'_>) { Python::with_gil(|py| { - let d = PyDict::new(py) as &PyAny; + let d = PyDict::new_bound(py).into_any(); - bench.iter(|| match black_box(d).downcast::() { + bench.iter(|| match black_box(&d).downcast::() { Ok(v) => panic!("should err {}", v), Err(e) => black_box(e), }); diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index ebda6c85..ff5bd030 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -85,14 +85,18 @@ macro_rules! bigint_conversion { let bytes = $to_bytes(self); let bytes_obj = PyBytes::new_bound(py, &bytes); let kwargs = if $is_signed > 0 { - let kwargs = PyDict::new(py); + let kwargs = PyDict::new_bound(py); kwargs.set_item(crate::intern!(py, "signed"), true).unwrap(); Some(kwargs) } else { None }; py.get_type::() - .call_method("from_bytes", (bytes_obj, "little"), kwargs) + .call_method( + "from_bytes", + (bytes_obj, "little"), + kwargs.as_ref().map(crate::Bound::as_gil_ref), + ) .expect("int.from_bytes() failed during to_object()") // FIXME: #1813 or similar .into() } diff --git a/src/conversions/smallvec.rs b/src/conversions/smallvec.rs index ade64a51..f51da1de 100644 --- a/src/conversions/smallvec.rs +++ b/src/conversions/smallvec.rs @@ -121,7 +121,7 @@ mod tests { #[test] fn test_smallvec_from_py_object_fails() { Python::with_gil(|py| { - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); let sv: PyResult> = dict.extract(); assert_eq!( sv.unwrap_err().to_string(), diff --git a/src/conversions/std/time.rs b/src/conversions/std/time.rs index bdf938c0..201dd67c 100755 --- a/src/conversions/std/time.rs +++ b/src/conversions/std/time.rs @@ -337,9 +337,11 @@ mod tests { fn max_datetime(py: Python<'_>) -> &PyAny { let naive_max = datetime_class(py).getattr("max").unwrap(); - let kargs = PyDict::new(py); + let kargs = PyDict::new_bound(py); kargs.set_item("tzinfo", tz_utc(py)).unwrap(); - naive_max.call_method("replace", (), Some(kargs)).unwrap() + naive_max + .call_method("replace", (), Some(kargs.as_gil_ref())) + .unwrap() } #[test] diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index b9f3fa27..4df674e7 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -681,7 +681,7 @@ impl<'py> VarkeywordsHandler<'py> for DictVarkeywords { _function_description: &FunctionDescription, ) -> PyResult<()> { varkeywords - .get_or_insert_with(|| PyDict::new(name.py())) + .get_or_insert_with(|| PyDict::new_bound(name.py()).into_gil_ref()) .set_item(name, value) } } diff --git a/src/instance.rs b/src/instance.rs index d99fe6f1..7f92744c 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -634,7 +634,7 @@ impl IntoPy for Borrowed<'_, '_, T> { /// #[new] /// fn __new__() -> Foo { /// Python::with_gil(|py| { -/// let dict: Py = PyDict::new(py).into(); +/// let dict: Py = PyDict::new_bound(py).unbind(); /// Foo { inner: dict } /// }) /// } @@ -706,7 +706,7 @@ impl IntoPy for Borrowed<'_, '_, T> { /// /// # fn main() { /// Python::with_gil(|py| { -/// let first: Py = PyDict::new(py).into(); +/// let first: Py = PyDict::new_bound(py).unbind(); /// /// // All of these are valid syntax /// let second = Py::clone_ref(&first, py); @@ -1130,7 +1130,7 @@ impl Py { /// /// # fn main() { /// Python::with_gil(|py| { - /// let first: Py = PyDict::new(py).into(); + /// let first: Py = PyDict::new_bound(py).unbind(); /// let second = Py::clone_ref(&first, py); /// /// // Both point to the same object @@ -1683,7 +1683,7 @@ impl PyObject { /// use pyo3::types::{PyDict, PyList}; /// /// Python::with_gil(|py| { - /// let any: PyObject = PyDict::new(py).into(); + /// let any: PyObject = PyDict::new_bound(py).into(); /// /// assert!(any.downcast::(py).is_ok()); /// assert!(any.downcast::(py).is_err()); diff --git a/src/marshal.rs b/src/marshal.rs index 5e62e6b6..95268139 100644 --- a/src/marshal.rs +++ b/src/marshal.rs @@ -38,14 +38,14 @@ pub fn dumps<'py>( /// /// # Examples /// ``` -/// # use pyo3::{marshal, types::PyDict}; +/// # use pyo3::{marshal, types::PyDict, prelude::PyDictMethods}; /// # pyo3::Python::with_gil(|py| { -/// let dict = PyDict::new(py); +/// let dict = PyDict::new_bound(py); /// dict.set_item("aap", "noot").unwrap(); /// dict.set_item("mies", "wim").unwrap(); /// dict.set_item("zus", "jet").unwrap(); /// -/// let bytes = marshal::dumps_bound(py, dict, marshal::VERSION); +/// let bytes = marshal::dumps_bound(py, &dict, marshal::VERSION); /// # }); /// ``` pub fn dumps_bound<'py>( @@ -90,20 +90,20 @@ where #[cfg(test)] mod tests { use super::*; - use crate::types::{bytes::PyBytesMethods, PyDict}; + use crate::types::{bytes::PyBytesMethods, dict::PyDictMethods, PyDict}; #[test] fn marshal_roundtrip() { Python::with_gil(|py| { - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); dict.set_item("aap", "noot").unwrap(); dict.set_item("mies", "wim").unwrap(); dict.set_item("zus", "jet").unwrap(); - let pybytes = dumps_bound(py, dict, VERSION).expect("marshalling failed"); + let pybytes = dumps_bound(py, &dict, VERSION).expect("marshalling failed"); let deserialized = loads_bound(py, pybytes.as_bytes()).expect("unmarshalling failed"); - assert!(equal(py, dict, &deserialized)); + assert!(equal(py, &dict, &deserialized)); }); } diff --git a/src/sync.rs b/src/sync.rs index 76c81026..04786c85 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -210,11 +210,11 @@ impl GILOnceCell> { /// /// ``` /// use pyo3::intern; -/// # use pyo3::{pyfunction, types::PyDict, wrap_pyfunction, PyResult, Python}; +/// # use pyo3::{pyfunction, types::PyDict, wrap_pyfunction, PyResult, Python, prelude::PyDictMethods, Bound}; /// /// #[pyfunction] -/// fn create_dict(py: Python<'_>) -> PyResult<&PyDict> { -/// let dict = PyDict::new(py); +/// fn create_dict(py: Python<'_>) -> PyResult> { +/// let dict = PyDict::new_bound(py); /// // 👇 A new `PyString` is created /// // for every call of this function. /// dict.set_item("foo", 42)?; @@ -222,8 +222,8 @@ impl GILOnceCell> { /// } /// /// #[pyfunction] -/// fn create_dict_faster(py: Python<'_>) -> PyResult<&PyDict> { -/// let dict = PyDict::new(py); +/// fn create_dict_faster(py: Python<'_>) -> PyResult> { +/// let dict = PyDict::new_bound(py); /// // 👇 A `PyString` is created once and reused /// // for the lifetime of the program. /// dict.set_item(intern!(py, "foo"), 42)?; @@ -270,7 +270,7 @@ impl Interned { mod tests { use super::*; - use crate::types::PyDict; + use crate::types::{any::PyAnyMethods, dict::PyDictMethods, PyDict}; #[test] fn test_intern() { @@ -279,7 +279,7 @@ mod tests { let foo2 = intern!(py, "foo"); let foo3 = intern!(py, stringify!(foo)); - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); dict.set_item(foo1, 42_usize).unwrap(); assert!(dict.contains(foo2).unwrap()); assert_eq!( diff --git a/src/types/any.rs b/src/types/any.rs index afc9a83d..73582bbc 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -388,9 +388,9 @@ impl PyAny { /// let module = PyModule::from_code(py, CODE, "", "")?; /// let fun = module.getattr("function")?; /// let args = ("hello",); - /// let kwargs = PyDict::new(py); + /// let kwargs = PyDict::new_bound(py); /// kwargs.set_item("cruel", "world")?; - /// let result = fun.call(args, Some(kwargs))?; + /// let result = fun.call(args, Some(kwargs.as_gil_ref()))?; /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// Ok(()) /// }) @@ -488,9 +488,9 @@ impl PyAny { /// let module = PyModule::from_code(py, CODE, "", "")?; /// let instance = module.getattr("a")?; /// let args = ("hello",); - /// let kwargs = PyDict::new(py); + /// let kwargs = PyDict::new_bound(py); /// kwargs.set_item("cruel", "world")?; - /// let result = instance.call_method("method", args, Some(kwargs))?; + /// let result = instance.call_method("method", args, Some(kwargs.as_gil_ref()))?; /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// Ok(()) /// }) @@ -691,9 +691,9 @@ impl PyAny { /// use pyo3::types::{PyDict, PyList}; /// /// Python::with_gil(|py| { - /// let dict = PyDict::new(py); + /// let dict = PyDict::new_bound(py); /// assert!(dict.is_instance_of::()); - /// let any: &PyAny = dict.as_ref(); + /// let any = dict.as_any(); /// /// assert!(any.downcast::().is_ok()); /// assert!(any.downcast::().is_err()); @@ -1268,9 +1268,9 @@ pub trait PyAnyMethods<'py> { /// let module = PyModule::from_code(py, CODE, "", "")?; /// let fun = module.getattr("function")?; /// let args = ("hello",); - /// let kwargs = PyDict::new(py); + /// let kwargs = PyDict::new_bound(py); /// kwargs.set_item("cruel", "world")?; - /// let result = fun.call(args, Some(kwargs))?; + /// let result = fun.call(args, Some(kwargs.as_gil_ref()))?; /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// Ok(()) /// }) @@ -1360,9 +1360,9 @@ pub trait PyAnyMethods<'py> { /// let module = PyModule::from_code(py, CODE, "", "")?; /// let instance = module.getattr("a")?; /// let args = ("hello",); - /// let kwargs = PyDict::new(py); + /// let kwargs = PyDict::new_bound(py); /// kwargs.set_item("cruel", "world")?; - /// let result = instance.call_method("method", args, Some(kwargs))?; + /// let result = instance.call_method("method", args, Some(kwargs.as_gil_ref()))?; /// assert_eq!(result.extract::<&str>()?, "called with args and kwargs"); /// Ok(()) /// }) @@ -1519,9 +1519,9 @@ pub trait PyAnyMethods<'py> { /// use pyo3::types::{PyDict, PyList}; /// /// Python::with_gil(|py| { - /// let dict = PyDict::new(py); + /// let dict = PyDict::new_bound(py); /// assert!(dict.is_instance_of::()); - /// let any: &PyAny = dict.as_ref(); + /// let any = dict.as_any(); /// /// assert!(any.downcast::().is_ok()); /// assert!(any.downcast::().is_err()); diff --git a/src/types/dict.rs b/src/types/dict.rs index 34812176..741d974e 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -57,6 +57,13 @@ pyobject_native_type_core!( impl PyDict { /// Deprecated form of [`new_bound`][PyDict::new_bound]. + #[cfg_attr( + not(feature = "gil-refs"), + deprecated( + since = "0.21.0", + note = "`PyDict::new` will be replaced by `PyDict::new_bound` in a future PyO3 version" + ) + )] #[inline] pub fn new(py: Python<'_>) -> &PyDict { Self::new_bound(py).into_gil_ref() diff --git a/src/types/ellipsis.rs b/src/types/ellipsis.rs index b39b74b3..4d091c6f 100644 --- a/src/types/ellipsis.rs +++ b/src/types/ellipsis.rs @@ -78,7 +78,7 @@ mod tests { #[test] fn test_dict_is_not_ellipsis() { Python::with_gil(|py| { - assert!(PyDict::new(py).downcast::().is_err()); + assert!(PyDict::new_bound(py).downcast::().is_err()); }) } } diff --git a/src/types/none.rs b/src/types/none.rs index ee650f12..6460482e 100644 --- a/src/types/none.rs +++ b/src/types/none.rs @@ -118,7 +118,7 @@ mod tests { #[test] fn test_dict_is_not_none() { Python::with_gil(|py| { - assert!(PyDict::new(py).downcast::().is_err()); + assert!(PyDict::new_bound(py).downcast::().is_err()); }) } } diff --git a/src/types/notimplemented.rs b/src/types/notimplemented.rs index 5832c6a9..9d31e670 100644 --- a/src/types/notimplemented.rs +++ b/src/types/notimplemented.rs @@ -81,7 +81,9 @@ mod tests { #[test] fn test_dict_is_not_notimplemented() { Python::with_gil(|py| { - assert!(PyDict::new(py).downcast::().is_err()); + assert!(PyDict::new_bound(py) + .downcast::() + .is_err()); }) } } diff --git a/tests/test_frompyobject.rs b/tests/test_frompyobject.rs index 82e91b84..c475d8ea 100644 --- a/tests/test_frompyobject.rs +++ b/tests/test_frompyobject.rs @@ -22,13 +22,13 @@ fn extract_traceback(py: Python<'_>, mut error: PyErr) -> String { } #[derive(Debug, FromPyObject)] -pub struct A<'a> { +pub struct A<'py> { #[pyo3(attribute)] s: String, #[pyo3(item)] - t: &'a PyString, + t: Bound<'py, PyString>, #[pyo3(attribute("foo"))] - p: &'a PyAny, + p: Bound<'py, PyAny>, } #[pyclass] @@ -58,8 +58,9 @@ fn test_named_fields_struct() { foo: None, }; let py_c = Py::new(py, pya).unwrap(); - let a: A<'_> = - FromPyObject::extract(py_c.as_ref(py)).expect("Failed to extract A from PyA"); + let a = py_c + .extract::>(py) + .expect("Failed to extract A from PyA"); assert_eq!(a.s, "foo"); assert_eq!(a.t.to_string_lossy(), "bar"); assert!(a.p.is_none()); @@ -76,10 +77,12 @@ pub struct B { fn test_transparent_named_field_struct() { Python::with_gil(|py| { let test: PyObject = "test".into_py(py); - let b: B = FromPyObject::extract(test.as_ref(py)).expect("Failed to extract B from String"); + let b = test + .extract::(py) + .expect("Failed to extract B from String"); assert_eq!(b.test, "test"); let test: PyObject = 1.into_py(py); - let b = B::extract(test.as_ref(py)); + let b = test.extract::(py); assert!(b.is_err()); }); } @@ -94,12 +97,14 @@ pub struct D { fn test_generic_transparent_named_field_struct() { Python::with_gil(|py| { let test: PyObject = "test".into_py(py); - let d: D = - D::extract(test.as_ref(py)).expect("Failed to extract D from String"); + let d = test + .extract::>(py) + .expect("Failed to extract D from String"); assert_eq!(d.test, "test"); let test = 1usize.into_py(py); - let d: D = - D::extract(test.as_ref(py)).expect("Failed to extract D from String"); + let d = test + .extract::>(py) + .expect("Failed to extract D from String"); assert_eq!(d.test, 1); }); } @@ -128,11 +133,12 @@ fn test_generic_named_fields_struct() { } .into_py(py); - let e: E = - E::extract(pye.as_ref(py)).expect("Failed to extract E from PyE"); + let e = pye + .extract::>(py) + .expect("Failed to extract E from PyE"); assert_eq!(e.test, "test"); assert_eq!(e.test2, 2); - let e = E::::extract(pye.as_ref(py)); + let e = pye.extract::>(py); assert!(e.is_err()); }); } @@ -151,7 +157,7 @@ fn test_named_field_with_ext_fn() { test2: 0, } .into_py(py); - let c = C::extract(pyc.as_ref(py)).expect("Failed to extract C from PyE"); + let c = pyc.extract::(py).expect("Failed to extract C from PyE"); assert_eq!(c.test, "foo"); }); } @@ -163,10 +169,12 @@ pub struct Tuple(String, usize); fn test_tuple_struct() { Python::with_gil(|py| { let tup = PyTuple::new_bound(py, &[1.into_py(py), "test".into_py(py)]); - let tup = Tuple::extract(tup.as_gil_ref()); + let tup = tup.extract::(); assert!(tup.is_err()); let tup = PyTuple::new_bound(py, &["test".into_py(py), 1.into_py(py)]); - let tup = Tuple::extract(tup.as_gil_ref()).expect("Failed to extract Tuple from PyTuple"); + let tup = tup + .extract::() + .expect("Failed to extract Tuple from PyTuple"); assert_eq!(tup.0, "test"); assert_eq!(tup.1, 1); }); @@ -179,10 +187,11 @@ pub struct TransparentTuple(String); fn test_transparent_tuple_struct() { Python::with_gil(|py| { let tup: PyObject = 1.into_py(py); - let tup = TransparentTuple::extract(tup.as_ref(py)); + let tup = tup.extract::(py); assert!(tup.is_err()); let test: PyObject = "test".into_py(py); - let tup = TransparentTuple::extract(test.as_ref(py)) + let tup = test + .extract::(py) .expect("Failed to extract TransparentTuple from PyTuple"); assert_eq!(tup.0, "test"); }); @@ -215,7 +224,7 @@ fn test_struct_nested_type_errors() { } .into_py(py); - let test: PyResult> = FromPyObject::extract(pybaz.as_ref(py)); + let test = pybaz.extract::>(py); assert!(test.is_err()); assert_eq!( extract_traceback(py,test.unwrap_err()), @@ -237,7 +246,7 @@ fn test_struct_nested_type_errors_with_generics() { } .into_py(py); - let test: PyResult> = FromPyObject::extract(pybaz.as_ref(py)); + let test = pybaz.extract::>(py); assert!(test.is_err()); assert_eq!( extract_traceback(py, test.unwrap_err()), @@ -251,7 +260,7 @@ fn test_struct_nested_type_errors_with_generics() { fn test_transparent_struct_error_message() { Python::with_gil(|py| { let tup: PyObject = 1.into_py(py); - let tup = B::extract(tup.as_ref(py)); + let tup = tup.extract::(py); assert!(tup.is_err()); assert_eq!( extract_traceback(py,tup.unwrap_err()), @@ -265,7 +274,7 @@ fn test_transparent_struct_error_message() { fn test_tuple_struct_error_message() { Python::with_gil(|py| { let tup: PyObject = (1, "test").into_py(py); - let tup = Tuple::extract(tup.as_ref(py)); + let tup = tup.extract::(py); assert!(tup.is_err()); assert_eq!( extract_traceback(py, tup.unwrap_err()), @@ -279,7 +288,7 @@ fn test_tuple_struct_error_message() { fn test_transparent_tuple_error_message() { Python::with_gil(|py| { let tup: PyObject = 1.into_py(py); - let tup = TransparentTuple::extract(tup.as_ref(py)); + let tup = tup.extract::(py); assert!(tup.is_err()); assert_eq!( extract_traceback(py, tup.unwrap_err()), @@ -290,10 +299,10 @@ fn test_transparent_tuple_error_message() { } #[derive(Debug, FromPyObject)] -pub enum Foo<'a> { +pub enum Foo<'py> { TupleVar(usize, String), StructVar { - test: &'a PyString, + test: Bound<'py, PyString>, }, #[pyo3(transparent)] TransparentTuple(usize), @@ -325,7 +334,9 @@ pub struct PyBool { fn test_enum() { Python::with_gil(|py| { let tup = PyTuple::new_bound(py, &[1.into_py(py), "test".into_py(py)]); - let f = Foo::extract(tup.as_gil_ref()).expect("Failed to extract Foo from tuple"); + let f = tup + .extract::>() + .expect("Failed to extract Foo from tuple"); match f { Foo::TupleVar(test, test2) => { assert_eq!(test, 1); @@ -339,43 +350,55 @@ fn test_enum() { test2: 0, } .into_py(py); - let f = Foo::extract(pye.as_ref(py)).expect("Failed to extract Foo from PyE"); + let f = pye + .extract::>(py) + .expect("Failed to extract Foo from PyE"); match f { Foo::StructVar { test } => assert_eq!(test.to_string_lossy(), "foo"), _ => panic!("Expected extracting Foo::StructVar, got {:?}", f), } let int: PyObject = 1.into_py(py); - let f = Foo::extract(int.as_ref(py)).expect("Failed to extract Foo from int"); + let f = int + .extract::>(py) + .expect("Failed to extract Foo from int"); match f { Foo::TransparentTuple(test) => assert_eq!(test, 1), _ => panic!("Expected extracting Foo::TransparentTuple, got {:?}", f), } let none = py.None(); - let f = Foo::extract(none.as_ref(py)).expect("Failed to extract Foo from int"); + let f = none + .extract::>(py) + .expect("Failed to extract Foo from int"); match f { Foo::TransparentStructVar { a } => assert!(a.is_none()), _ => panic!("Expected extracting Foo::TransparentStructVar, got {:?}", f), } let pybool = PyBool { bla: true }.into_py(py); - let f = Foo::extract(pybool.as_ref(py)).expect("Failed to extract Foo from PyBool"); + let f = pybool + .extract::>(py) + .expect("Failed to extract Foo from PyBool"); match f { Foo::StructVarGetAttrArg { a } => assert!(a), _ => panic!("Expected extracting Foo::StructVarGetAttrArg, got {:?}", f), } - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); dict.set_item("a", "test").expect("Failed to set item"); - let f = Foo::extract(dict.as_ref()).expect("Failed to extract Foo from dict"); + let f = dict + .extract::>() + .expect("Failed to extract Foo from dict"); match f { Foo::StructWithGetItem { a } => assert_eq!(a, "test"), _ => panic!("Expected extracting Foo::StructWithGetItem, got {:?}", f), } - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); dict.set_item("foo", "test").expect("Failed to set item"); - let f = Foo::extract(dict.as_ref()).expect("Failed to extract Foo from dict"); + let f = dict + .extract::>() + .expect("Failed to extract Foo from dict"); match f { Foo::StructWithGetItemArg { a } => assert_eq!(a, "test"), _ => panic!("Expected extracting Foo::StructWithGetItemArg, got {:?}", f), @@ -386,8 +409,8 @@ fn test_enum() { #[test] fn test_enum_error() { Python::with_gil(|py| { - let dict = PyDict::new(py); - let err = Foo::extract(dict.as_ref()).unwrap_err(); + let dict = PyDict::new_bound(py); + let err = dict.extract::>().unwrap_err(); assert_eq!( err.to_string(), "\ @@ -402,7 +425,7 @@ TypeError: failed to extract enum Foo ('TupleVar | StructVar | TransparentTuple ); let tup = PyTuple::empty_bound(py); - let err = Foo::extract(tup.as_gil_ref()).unwrap_err(); + let err = tup.extract::>().unwrap_err(); assert_eq!( err.to_string(), "\ @@ -419,23 +442,24 @@ TypeError: failed to extract enum Foo ('TupleVar | StructVar | TransparentTuple } #[derive(Debug, FromPyObject)] -enum EnumWithCatchAll<'a> { +enum EnumWithCatchAll<'py> { #[allow(dead_code)] #[pyo3(transparent)] - Foo(Foo<'a>), + Foo(Foo<'py>), #[pyo3(transparent)] - CatchAll(&'a PyAny), + CatchAll(Bound<'py, PyAny>), } #[test] fn test_enum_catch_all() { Python::with_gil(|py| { - let dict = PyDict::new(py); - let f = EnumWithCatchAll::extract(dict.as_ref()) + let dict = PyDict::new_bound(py); + let f = dict + .extract::>() .expect("Failed to extract EnumWithCatchAll from dict"); match f { EnumWithCatchAll::CatchAll(any) => { - let d = <&PyDict>::extract(any).expect("Expected pydict"); + let d = any.extract::>().expect("Expected pydict"); assert!(d.is_empty()); } _ => panic!( @@ -459,8 +483,8 @@ pub enum Bar { #[test] fn test_err_rename() { Python::with_gil(|py| { - let dict = PyDict::new(py); - let f = Bar::extract(dict.as_ref()); + let dict = PyDict::new_bound(py); + let f = dict.extract::(); assert!(f.is_err()); assert_eq!( f.unwrap_err().to_string(), @@ -493,7 +517,7 @@ fn test_from_py_with() { ) .expect("failed to create dict"); - let zap = Zap::extract_bound(&py_zap).unwrap(); + let zap = py_zap.extract::().unwrap(); assert_eq!(zap.name, "whatever"); assert_eq!(zap.some_object_length, 3usize); @@ -510,7 +534,7 @@ fn test_from_py_with_tuple_struct() { .eval_bound(r#"("whatever", [1, 2, 3])"#, None, None) .expect("failed to create tuple"); - let zap = ZapTuple::extract_bound(&py_zap).unwrap(); + let zap = py_zap.extract::().unwrap(); assert_eq!(zap.0, "whatever"); assert_eq!(zap.1, 3usize); @@ -524,7 +548,7 @@ fn test_from_py_with_tuple_struct_error() { .eval_bound(r#"("whatever", [1, 2, 3], "third")"#, None, None) .expect("failed to create tuple"); - let f = ZapTuple::extract_bound(&py_zap); + let f = py_zap.extract::(); assert!(f.is_err()); assert_eq!( @@ -547,7 +571,7 @@ fn test_from_py_with_enum() { .eval_bound(r#"("whatever", [1, 2, 3])"#, None, None) .expect("failed to create tuple"); - let zap = ZapEnum::extract_bound(&py_zap).unwrap(); + let zap = py_zap.extract::().unwrap(); let expected_zap = ZapEnum::Zip(2); assert_eq!(zap, expected_zap); @@ -564,8 +588,9 @@ pub struct TransparentFromPyWith { #[test] fn test_transparent_from_py_with() { Python::with_gil(|py| { - let result = - TransparentFromPyWith::extract(PyList::new_bound(py, [1, 2, 3]).as_gil_ref()).unwrap(); + let result = PyList::new_bound(py, [1, 2, 3]) + .extract::() + .unwrap(); let expected = TransparentFromPyWith { len: 3 }; assert_eq!(result, expected); diff --git a/tests/test_proto_methods.rs b/tests/test_proto_methods.rs index b1fe7548..872777bf 100644 --- a/tests/test_proto_methods.rs +++ b/tests/test_proto_methods.rs @@ -216,7 +216,7 @@ fn mapping() { let inst = Py::new( py, Mapping { - values: PyDict::new(py).into(), + values: PyDict::new_bound(py).into(), }, ) .unwrap(); diff --git a/tests/ui/wrong_aspyref_lifetimes.rs b/tests/ui/wrong_aspyref_lifetimes.rs index 5cd8a2d3..755b0cf2 100644 --- a/tests/ui/wrong_aspyref_lifetimes.rs +++ b/tests/ui/wrong_aspyref_lifetimes.rs @@ -1,10 +1,10 @@ -use pyo3::{types::PyDict, Py, Python}; +use pyo3::{types::PyDict, Bound, Py, Python}; fn main() { - let dict: Py = Python::with_gil(|py| PyDict::new(py).into()); + let dict: Py = Python::with_gil(|py| PyDict::new_bound(py).unbind()); // Should not be able to get access to Py contents outside of with_gil. - let dict: &PyDict = Python::with_gil(|py| dict.as_ref(py)); + let dict: &Bound<'_, PyDict> = Python::with_gil(|py| dict.bind(py)); let _py: Python = dict.py(); // Obtain a Python<'p> without GIL. } diff --git a/tests/ui/wrong_aspyref_lifetimes.stderr b/tests/ui/wrong_aspyref_lifetimes.stderr index def6f94c..30e63bb8 100644 --- a/tests/ui/wrong_aspyref_lifetimes.stderr +++ b/tests/ui/wrong_aspyref_lifetimes.stderr @@ -1,8 +1,8 @@ error: lifetime may not live long enough - --> tests/ui/wrong_aspyref_lifetimes.rs:7:47 + --> tests/ui/wrong_aspyref_lifetimes.rs:7:58 | -7 | let dict: &PyDict = Python::with_gil(|py| dict.as_ref(py)); - | --- ^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` - | | | - | | return type of closure is &'2 PyDict - | has type `pyo3::Python<'1>` +7 | let dict: &Bound<'_, PyDict> = Python::with_gil(|py| dict.bind(py)); + | --- ^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is &'2 pyo3::Bound<'_, PyDict> + | has type `pyo3::Python<'1>`