deprecate `PyDict::new` constructor (#3823)

* deprecate `PyDict::new`

* update benchmarks

* convert `test_frompyobject`
This commit is contained in:
Icxolu 2024-02-12 00:55:56 +01:00 committed by GitHub
parent c983dc9773
commit c359f5ca1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 189 additions and 153 deletions

View File

@ -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()?;

View File

@ -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::<PyBool>() {
@ -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

View File

@ -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::<BigInt>() {
bench.iter(|| match black_box(&d).extract::<BigInt>() {
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::<BigInt>().unwrap();
let v = black_box(&int).extract::<BigInt>().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::<BigInt>().unwrap();
let v = black_box(&int).extract::<BigInt>().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::<BigInt>().unwrap();
let v = black_box(&int).extract::<BigInt>().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::<BigInt>().unwrap();
let v = black_box(&int).extract::<BigInt>().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::<BigInt>().unwrap();
let v = black_box(&int).extract::<BigInt>().unwrap();
black_box(v);
});
});

View File

@ -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();
});
})
}

View File

@ -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::<u64, u64>::extract(dict));
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py);
b.iter(|| HashMap::<u64, u64>::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::<u64, u64>::extract(dict));
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py);
b.iter(|| BTreeMap::<u64, u64>::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::<u64, u64>::extract(dict));
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py);
b.iter(|| hashbrown::HashMap::<u64, u64>::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::<PyMapping>().unwrap());
});
}

View File

@ -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::<PyString>() {
bench.iter(|| match black_box(&d).downcast::<PyString>() {
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::<i64>() {
bench.iter(|| match black_box(&d).extract::<i64>() {
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::<PyInt>() {
bench.iter(|| match black_box(&d).downcast::<PyInt>() {
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::<f64>() {
bench.iter(|| match black_box(&d).extract::<f64>() {
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::<PyFloat>() {
bench.iter(|| match black_box(&d).downcast::<PyFloat>() {
Ok(v) => panic!("should err {}", v),
Err(e) => black_box(e),
});

View File

@ -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::<PyLong>()
.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()
}

View File

@ -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<SmallVec<[u64; 8]>> = dict.extract();
assert_eq!(
sv.unwrap_err().to_string(),

View File

@ -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]

View File

@ -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)
}
}

View File

@ -634,7 +634,7 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
/// #[new]
/// fn __new__() -> Foo {
/// Python::with_gil(|py| {
/// let dict: Py<PyDict> = PyDict::new(py).into();
/// let dict: Py<PyDict> = PyDict::new_bound(py).unbind();
/// Foo { inner: dict }
/// })
/// }
@ -706,7 +706,7 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
///
/// # fn main() {
/// Python::with_gil(|py| {
/// let first: Py<PyDict> = PyDict::new(py).into();
/// let first: Py<PyDict> = PyDict::new_bound(py).unbind();
///
/// // All of these are valid syntax
/// let second = Py::clone_ref(&first, py);
@ -1130,7 +1130,7 @@ impl<T> Py<T> {
///
/// # fn main() {
/// Python::with_gil(|py| {
/// let first: Py<PyDict> = PyDict::new(py).into();
/// let first: Py<PyDict> = 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::<PyDict>(py).is_ok());
/// assert!(any.downcast::<PyList>(py).is_err());

View File

@ -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));
});
}

View File

@ -210,11 +210,11 @@ impl GILOnceCell<Py<PyType>> {
///
/// ```
/// 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<Bound<'_, PyDict>> {
/// 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<Py<PyType>> {
/// }
///
/// #[pyfunction]
/// fn create_dict_faster(py: Python<'_>) -> PyResult<&PyDict> {
/// let dict = PyDict::new(py);
/// fn create_dict_faster(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
/// 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!(

View File

@ -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::<PyAny>());
/// let any: &PyAny = dict.as_ref();
/// let any = dict.as_any();
///
/// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().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::<PyAny>());
/// let any: &PyAny = dict.as_ref();
/// let any = dict.as_any();
///
/// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().is_err());

View File

@ -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()

View File

@ -78,7 +78,7 @@ mod tests {
#[test]
fn test_dict_is_not_ellipsis() {
Python::with_gil(|py| {
assert!(PyDict::new(py).downcast::<PyEllipsis>().is_err());
assert!(PyDict::new_bound(py).downcast::<PyEllipsis>().is_err());
})
}
}

View File

@ -118,7 +118,7 @@ mod tests {
#[test]
fn test_dict_is_not_none() {
Python::with_gil(|py| {
assert!(PyDict::new(py).downcast::<PyNone>().is_err());
assert!(PyDict::new_bound(py).downcast::<PyNone>().is_err());
})
}
}

View File

@ -81,7 +81,9 @@ mod tests {
#[test]
fn test_dict_is_not_notimplemented() {
Python::with_gil(|py| {
assert!(PyDict::new(py).downcast::<PyNotImplemented>().is_err());
assert!(PyDict::new_bound(py)
.downcast::<PyNotImplemented>()
.is_err());
})
}
}

View File

@ -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::<A<'_>>(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::<B>(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::<B>(py);
assert!(b.is_err());
});
}
@ -94,12 +97,14 @@ pub struct D<T> {
fn test_generic_transparent_named_field_struct() {
Python::with_gil(|py| {
let test: PyObject = "test".into_py(py);
let d: D<String> =
D::extract(test.as_ref(py)).expect("Failed to extract D<String> from String");
let d = test
.extract::<D<String>>(py)
.expect("Failed to extract D<String> from String");
assert_eq!(d.test, "test");
let test = 1usize.into_py(py);
let d: D<usize> =
D::extract(test.as_ref(py)).expect("Failed to extract D<usize> from String");
let d = test
.extract::<D<usize>>(py)
.expect("Failed to extract D<usize> from String");
assert_eq!(d.test, 1);
});
}
@ -128,11 +133,12 @@ fn test_generic_named_fields_struct() {
}
.into_py(py);
let e: E<String, usize> =
E::extract(pye.as_ref(py)).expect("Failed to extract E<String, usize> from PyE");
let e = pye
.extract::<E<String, usize>>(py)
.expect("Failed to extract E<String, usize> from PyE");
assert_eq!(e.test, "test");
assert_eq!(e.test2, 2);
let e = E::<usize, usize>::extract(pye.as_ref(py));
let e = pye.extract::<E<usize, usize>>(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::<C>(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::<Tuple>();
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::<Tuple>()
.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::<TransparentTuple>(py);
assert!(tup.is_err());
let test: PyObject = "test".into_py(py);
let tup = TransparentTuple::extract(test.as_ref(py))
let tup = test
.extract::<TransparentTuple>(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<Baz<String, usize>> = FromPyObject::extract(pybaz.as_ref(py));
let test = pybaz.extract::<Baz<String, usize>>(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<Baz<usize, String>> = FromPyObject::extract(pybaz.as_ref(py));
let test = pybaz.extract::<Baz<usize, usize>>(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::<B>(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::<Tuple>(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::<TransparentTuple>(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::<Foo<'_>>()
.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::<Foo<'_>>(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::<Foo<'_>>(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::<Foo<'_>>(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::<Foo<'_>>(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::<Foo<'_>>()
.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::<Foo<'_>>()
.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::<Foo<'_>>().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::<Foo<'_>>().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::<EnumWithCatchAll<'_>>()
.expect("Failed to extract EnumWithCatchAll from dict");
match f {
EnumWithCatchAll::CatchAll(any) => {
let d = <&PyDict>::extract(any).expect("Expected pydict");
let d = any.extract::<Bound<'_, PyDict>>().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::<Bar>();
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::<Zap>().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::<ZapTuple>().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::<ZapTuple>();
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::<ZapEnum>().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::<TransparentFromPyWith>()
.unwrap();
let expected = TransparentFromPyWith { len: 3 };
assert_eq!(result, expected);

View File

@ -216,7 +216,7 @@ fn mapping() {
let inst = Py::new(
py,
Mapping {
values: PyDict::new(py).into(),
values: PyDict::new_bound(py).into(),
},
)
.unwrap();

View File

@ -1,10 +1,10 @@
use pyo3::{types::PyDict, Py, Python};
use pyo3::{types::PyDict, Bound, Py, Python};
fn main() {
let dict: Py<PyDict> = Python::with_gil(|py| PyDict::new(py).into());
let dict: Py<PyDict> = 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.
}

View File

@ -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`
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 PyDict
| | return type of closure is &'2 pyo3::Bound<'_, PyDict>
| has type `pyo3::Python<'1>`