Skip to content

Commit

Permalink
Reintroduce PyDict constructors (#4388)
Browse files Browse the repository at this point in the history
* Add back `PyDict::new`

* Add back `IntoPyDict::into_py_dict`

* Add changelog & migration entry
  • Loading branch information
bschoenmaeckers authored Aug 1, 2024
1 parent 7c1ae15 commit 45ba2fc
Show file tree
Hide file tree
Showing 61 changed files with 246 additions and 174 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ fn main() -> PyResult<()> {
let sys = py.import_bound("sys")?;
let version: String = sys.getattr("version")?.extract()?;

let locals = [("os", py.import_bound("os")?)].into_py_dict_bound(py);
let locals = [("os", py.import_bound("os")?)].into_py_dict(py);
let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
let user: String = py.eval_bound(code, None, Some(&locals))?.extract()?;

Expand Down
2 changes: 1 addition & 1 deletion guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ struct RustyStruct {
# use pyo3::types::PyDict;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| -> PyResult<()> {
# let dict = PyDict::new_bound(py);
# let dict = PyDict::new(py);
# dict.set_item("my_string", "test")?;
#
# let rustystruct: RustyStruct = dict.extract()?;
Expand Down
2 changes: 1 addition & 1 deletion guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use pyo3::exceptions::PyException;
create_exception!(mymodule, CustomError, PyException);

Python::with_gil(|py| {
let ctx = [("CustomError", py.get_type_bound::<CustomError>())].into_py_dict_bound(py);
let ctx = [("CustomError", py.get_type_bound::<CustomError>())].into_py_dict(py);
pyo3::py_run!(
py,
*ctx,
Expand Down
51 changes: 51 additions & 0 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,57 @@ let tup = PyTuple::new(py, [1, 2, 3]);
```
</details>

### Renamed `IntoPyDict::into_py_dict_bound` into `IntoPyDict::into_py_dict`.
<details open>
<summary><small>Click to expand</small></summary>

The `IntoPyDict::into_py_dict_bound` method has been renamed to `IntoPyDict::into_py_dict`. If you implemented `IntoPyDict` for your type, you should implement `into_py_dict` instead of `into_py_dict_bound`. The old name is still available but deprecated.

Before:

```rust,ignore
# use pyo3::prelude::*;
# use pyo3::types::{PyDict, IntoPyDict};
# use pyo3::types::dict::PyDictItem;
impl<T, I> IntoPyDict for I
where
T: PyDictItem,
I: IntoIterator<Item = T>,
{
fn into_py_dict_bound(self, py: Python<'_>) -> Bound<'_, PyDict> {
let dict = PyDict::new(py);
for item in self {
dict.set_item(item.key(), item.value())
.expect("Failed to set_item on dict");
}
dict
}
}
```

After:

```rust,ignore
# use pyo3::prelude::*;
# use pyo3::types::{PyDict, IntoPyDict};
# use pyo3::types::dict::PyDictItem;
impl<T, I> IntoPyDict for I
where
T: PyDictItem,
I: IntoIterator<Item = T>,
{
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict> {
let dict = PyDict::new(py);
for item in self {
dict.set_item(item.key(), item.value())
.expect("Failed to set_item on dict");
}
dict
}
}
```
</details>

## from 0.21.* to 0.22

### Deprecation of `gil-refs` feature continues
Expand Down
2 changes: 1 addition & 1 deletion guide/src/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fn func() -> String {
# use pyo3::wrap_pymodule;
# use pyo3::types::IntoPyDict;
# let parent_module = wrap_pymodule!(parent_module)(py);
# let ctx = [("parent_module", parent_module)].into_py_dict_bound(py);
# let ctx = [("parent_module", parent_module)].into_py_dict(py);
#
# py.run_bound("assert parent_module.child_module.func() == 'func'", None, Some(&ctx)).unwrap();
# })
Expand Down
2 changes: 1 addition & 1 deletion guide/src/python-from-rust/calling-existing-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def leaky_relu(x, slope=0.01):
let relu_result: f64 = activators.getattr("relu")?.call1((-1.0,))?.extract()?;
assert_eq!(relu_result, 0.0);

let kwargs = [("slope", 0.2)].into_py_dict_bound(py);
let kwargs = [("slope", 0.2)].into_py_dict(py);
let lrelu_result: f64 = activators
.getattr("leaky_relu")?
.call((-1.0,), Some(&kwargs))?
Expand Down
6 changes: 3 additions & 3 deletions guide/src/python-from-rust/function-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,17 @@ fn main() -> PyResult<()> {
.into();

// call object with PyDict
let kwargs = [(key1, val1)].into_py_dict_bound(py);
let kwargs = [(key1, val1)].into_py_dict(py);
fun.call_bound(py, (), Some(&kwargs))?;

// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
fun.call_bound(py, (), Some(&kwargs.into_py_dict_bound(py)))?;
fun.call_bound(py, (), Some(&kwargs.into_py_dict(py)))?;

// pass arguments as HashMap
let mut kwargs = HashMap::<&str, i32>::new();
kwargs.insert(key1, 1);
fun.call_bound(py, (), Some(&kwargs.into_py_dict_bound(py)))?;
fun.call_bound(py, (), Some(&kwargs.into_py_dict(py)))?;

Ok(())
})
Expand Down
1 change: 1 addition & 0 deletions newsfragments/4388.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Renamed `IntoPyDict::into_py_dict_bound` into `IntoPyDict::into_py_dict`.
2 changes: 1 addition & 1 deletion pyo3-benches/benches/bench_bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use pyo3::types::PyDict;

fn extract_bigint_extract_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).extract::<BigInt>() {
Ok(v) => panic!("should err {}", v),
Expand Down
2 changes: 1 addition & 1 deletion pyo3-benches/benches/bench_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use pyo3::types::PyDict;

fn decimal_via_extract(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
let locals = PyDict::new_bound(py);
let locals = PyDict::new(py);
py.run_bound(
r#"
import decimal
Expand Down
14 changes: 7 additions & 7 deletions pyo3-benches/benches/bench_dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use pyo3::{prelude::*, types::PyMapping};
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_bound(py);
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py);
let mut sum = 0;
b.iter(|| {
for (k, _v) in &dict {
Expand All @@ -23,14 +23,14 @@ fn iter_dict(b: &mut Bencher<'_>) {
fn dict_new(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
const LEN: usize = 50_000;
b.iter_with_large_drop(|| (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict_bound(py));
b.iter_with_large_drop(|| (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(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_bound(py);
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py);
let mut sum = 0;
b.iter(|| {
for i in 0..LEN {
Expand All @@ -48,15 +48,15 @@ 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_bound(py);
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(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_bound(py);
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py);
b.iter(|| BTreeMap::<u64, u64>::extract_bound(&dict));
});
}
Expand All @@ -65,15 +65,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_bound(py);
let dict = (0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(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_bound(py);
let dict = &(0..LEN as u64).map(|i| (i, i * 2)).into_py_dict(py);
b.iter(|| black_box(dict).downcast::<PyMapping>().unwrap());
});
}
Expand Down
12 changes: 6 additions & 6 deletions pyo3-benches/benches/bench_extract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn extract_str_extract_success(bench: &mut Bencher<'_>) {

fn extract_str_extract_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).extract::<&str>() {
Ok(v) => panic!("should err {}", v),
Expand All @@ -40,7 +40,7 @@ fn extract_str_downcast_success(bench: &mut Bencher<'_>) {

fn extract_str_downcast_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).downcast::<PyString>() {
Ok(v) => panic!("should err {}", v),
Expand All @@ -59,7 +59,7 @@ fn extract_int_extract_success(bench: &mut Bencher<'_>) {

fn extract_int_extract_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).extract::<i64>() {
Ok(v) => panic!("should err {}", v),
Expand All @@ -81,7 +81,7 @@ fn extract_int_downcast_success(bench: &mut Bencher<'_>) {

fn extract_int_downcast_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).downcast::<PyInt>() {
Ok(v) => panic!("should err {}", v),
Expand All @@ -100,7 +100,7 @@ fn extract_float_extract_success(bench: &mut Bencher<'_>) {

fn extract_float_extract_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).extract::<f64>() {
Ok(v) => panic!("should err {}", v),
Expand All @@ -122,7 +122,7 @@ fn extract_float_downcast_success(bench: &mut Bencher<'_>) {

fn extract_float_downcast_fail(bench: &mut Bencher<'_>) {
Python::with_gil(|py| {
let d = PyDict::new_bound(py).into_any();
let d = PyDict::new(py).into_any();

bench.iter(|| match black_box(&d).downcast::<PyFloat>() {
Ok(v) => panic!("should err {}", v),
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/anyhow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ mod test_anyhow {
let pyerr = PyErr::from(err);

Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict_bound(py);
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value_bound(py).to_string(), expected_contents);
})
Expand All @@ -163,7 +163,7 @@ mod test_anyhow {
let pyerr = PyErr::from(err);

Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict_bound(py);
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value_bound(py).to_string(), expected_contents);
})
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ mod tests {
use crate::types::dict::PyDictMethods;

Python::with_gil(|py| {
let locals = crate::types::PyDict::new_bound(py);
let locals = crate::types::PyDict::new(py);
py.run_bound(
"import zoneinfo; zi = zoneinfo.ZoneInfo('Europe/London')",
None,
Expand Down Expand Up @@ -1108,7 +1108,7 @@ mod tests {
fn test_pyo3_offset_fixed_frompyobject_created_in_python(timestamp in 0..(i32::MAX as i64), timedelta in -86399i32..=86399i32) {
Python::with_gil(|py| {

let globals = [("datetime", py.import_bound("datetime").unwrap())].into_py_dict_bound(py);
let globals = [("datetime", py.import_bound("datetime").unwrap())].into_py_dict(py);
let code = format!("datetime.datetime.fromtimestamp({}).replace(tzinfo=datetime.timezone(datetime.timedelta(seconds={})))", timestamp, timedelta);
let t = py.eval_bound(&code, Some(&globals), None).unwrap();

Expand Down
4 changes: 2 additions & 2 deletions src/conversions/eyre.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ mod tests {
let pyerr = PyErr::from(err);

Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict_bound(py);
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value_bound(py).to_string(), expected_contents);
})
Expand All @@ -168,7 +168,7 @@ mod tests {
let pyerr = PyErr::from(err);

Python::with_gil(|py| {
let locals = [("err", pyerr)].into_py_dict_bound(py);
let locals = [("err", pyerr)].into_py_dict(py);
let pyerr = py.run_bound("raise err", None, Some(&locals)).unwrap_err();
assert_eq!(pyerr.value_bound(py).to_string(), expected_contents);
})
Expand Down
6 changes: 3 additions & 3 deletions src/conversions/hashbrown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ where
H: hash::BuildHasher,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict_bound(self, py).into()
IntoPyDict::into_py_dict(self, py).into()
}
}

Expand All @@ -47,7 +47,7 @@ where
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict_bound(iter, py).into()
IntoPyDict::into_py_dict(iter, py).into()
}
}

Expand Down Expand Up @@ -163,7 +163,7 @@ mod tests {
let mut map = hashbrown::HashMap::<i32, i32>::new();
map.insert(1, 1);

let py_map = map.into_py_dict_bound(py);
let py_map = map.into_py_dict(py);

assert_eq!(py_map.len(), 1);
assert_eq!(
Expand Down
8 changes: 4 additions & 4 deletions src/conversions/indexmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ where
H: hash::BuildHasher,
{
fn to_object(&self, py: Python<'_>) -> PyObject {
IntoPyDict::into_py_dict_bound(self, py).into()
IntoPyDict::into_py_dict(self, py).into()
}
}

Expand All @@ -112,7 +112,7 @@ where
let iter = self
.into_iter()
.map(|(k, v)| (k.into_py(py), v.into_py(py)));
IntoPyDict::into_py_dict_bound(iter, py).into()
IntoPyDict::into_py_dict(iter, py).into()
}
}

Expand Down Expand Up @@ -192,7 +192,7 @@ mod test_indexmap {
let mut map = indexmap::IndexMap::<i32, i32>::new();
map.insert(1, 1);

let py_map = map.into_py_dict_bound(py);
let py_map = map.into_py_dict(py);

assert_eq!(py_map.len(), 1);
assert_eq!(
Expand Down Expand Up @@ -221,7 +221,7 @@ mod test_indexmap {
}
}

let py_map = map.clone().into_py_dict_bound(py);
let py_map = map.clone().into_py_dict(py);

let trip_map = py_map.extract::<indexmap::IndexMap<i32, i32>>().unwrap();

Expand Down
Loading

0 comments on commit 45ba2fc

Please sign in to comment.