From 28bc3cf1e69d1134b6d06ad8fa0e024d2a475e63 Mon Sep 17 00:00:00 2001 From: ijl Date: Tue, 25 Sep 2018 14:19:23 +0000 Subject: [PATCH] PyDict::from_sequence() --- CHANGELOG.md | 1 + src/types/dict.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4535b16..4d2756a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * `#[pyclass]` objects can now be returned from rust functions * `PyComplex` by kngwyu in [#226](https://github.com/PyO3/pyo3/pull/226) + * `PyDict::from_sequence()`, equivalent to `dict([(key, val), ...])` ### Removed * Removed most entries from the prelude. The new prelude is small and clear. diff --git a/src/types/dict.rs b/src/types/dict.rs index 8588a00f..76e518d1 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -5,7 +5,7 @@ use err::{self, PyErr, PyResult}; use ffi; use instance::PyObjectWithToken; use object::PyObject; -use python::{Python, ToPyPointer}; +use python::{Python, ToPyPointer, IntoPyPointer}; use std; use std::{cmp, collections, hash, mem}; use types::{PyList, PyObjectRef}; @@ -22,6 +22,24 @@ impl PyDict { unsafe { py.from_owned_ptr::(ffi::PyDict_New()) } } + /// Creates a new dictionary from the sequence given. + /// + /// The sequence must consist of `(PyObject, PyObject)`. This is + /// equivalent to `dict([("a", 1), ("b", 2)])`. + /// + /// Returns an error on invalid input. In the case of key collisions, + /// this keeps the last entry seen. + pub fn from_sequence(py: Python, seq: PyObject) -> PyResult<&PyDict> { + unsafe { + let dict = py.from_owned_ptr::(ffi::PyDict_New()); + match ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1i32) { + 0 => Ok(dict), + -1 => Err(PyErr::fetch(py)), + _ => unreachable!(), + } + } + } + /// Return a new dictionary that contains the same key-value pairs as self. /// Corresponds to `dict(self)` in Python. pub fn copy(&self) -> PyResult<&PyDict> { @@ -259,7 +277,7 @@ mod test { use python::Python; use std::collections::{BTreeMap, HashMap}; use types::dict::IntoPyDict; - use types::{PyDict, PyTuple}; + use types::{PyDict, PyTuple, PyList}; use ObjectProtocol; #[test] @@ -272,6 +290,24 @@ mod test { assert_eq!(None, dict.get_item(8i32)); } + #[test] + fn test_from_sequence() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let items = PyList::new(py, &vec![("a", 1), ("b", 2)]); + let dict = PyDict::from_sequence(py, items.to_object(py)).unwrap(); + assert_eq!(1, dict.get_item("a").unwrap().extract::().unwrap()); + assert_eq!(2, dict.get_item("b").unwrap().extract::().unwrap()); + } + + #[test] + fn test_from_sequence_err() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let items = PyList::new(py, &vec!["a", "b"]); + assert!(PyDict::from_sequence(py, items.to_object(py)).is_err()); + } + #[test] fn test_copy() { let gil = Python::acquire_gil();