add PyDict keys,values,items methods

This commit is contained in:
Nikolay Kim 2017-07-20 08:23:43 -07:00
parent 97c6b7591a
commit a00ae1757c
3 changed files with 111 additions and 55 deletions

View File

@ -5,7 +5,6 @@
//! Python argument parsing
use ffi;
use instance::AsPyRef;
use python::{Python, PyDowncastFrom};
use objects::{PyObjectRef, PyTuple, PyDict, PyString, exc};
use err::{self, PyResult};
@ -88,13 +87,13 @@ pub fn parse_args<'p>(py: Python<'p>,
}
if !accept_kwargs && used_keywords != nkeywords {
// check for extraneous keyword arguments
for (key, _value) in kwargs.unwrap().items() {
let key = PyString::downcast_from(key.as_ref(py))?.to_string()?;
for item in kwargs.unwrap().items().iter() {
let item = PyTuple::downcast_from(item)?;
let key = PyString::downcast_from(item.get_item(0))?.to_string()?;
if !params.iter().any(|p| p.name == key) {
return Err(err::PyErr::new::<exc::TypeError, _>(
py,
format!("'{}' is an invalid keyword argument for this function",
key)));
format!("'{}' is an invalid keyword argument for this function", key)));
}
}
}

View File

@ -44,36 +44,24 @@ pub unsafe fn PyDictViewSet_Check(op : *mut PyObject) -> c_int {
#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
pub fn PyDict_New() -> *mut PyObject;
pub fn PyDict_GetItem(mp: *mut PyObject, key: *mut PyObject)
-> *mut PyObject;
pub fn PyDict_GetItemWithError(mp: *mut PyObject, key: *mut PyObject)
-> *mut PyObject;
pub fn PyDict_SetItem(mp: *mut PyObject, key: *mut PyObject,
item: *mut PyObject) -> c_int;
pub fn PyDict_DelItem(mp: *mut PyObject, key: *mut PyObject)
-> c_int;
pub fn PyDict_GetItem(mp: *mut PyObject, key: *mut PyObject) -> *mut PyObject;
pub fn PyDict_GetItemWithError(mp: *mut PyObject, key: *mut PyObject) -> *mut PyObject;
pub fn PyDict_SetItem(mp: *mut PyObject, key: *mut PyObject, item: *mut PyObject) -> c_int;
pub fn PyDict_DelItem(mp: *mut PyObject, key: *mut PyObject) -> c_int;
pub fn PyDict_Clear(mp: *mut PyObject) -> ();
pub fn PyDict_Next(mp: *mut PyObject, pos: *mut Py_ssize_t,
key: *mut *mut PyObject, value: *mut *mut PyObject)
-> c_int;
key: *mut *mut PyObject, value: *mut *mut PyObject) -> c_int;
pub fn PyDict_Keys(mp: *mut PyObject) -> *mut PyObject;
pub fn PyDict_Values(mp: *mut PyObject) -> *mut PyObject;
pub fn PyDict_Items(mp: *mut PyObject) -> *mut PyObject;
pub fn PyDict_Size(mp: *mut PyObject) -> Py_ssize_t;
pub fn PyDict_Copy(mp: *mut PyObject) -> *mut PyObject;
pub fn PyDict_Contains(mp: *mut PyObject, key: *mut PyObject)
-> c_int;
pub fn PyDict_Update(mp: *mut PyObject, other: *mut PyObject)
-> c_int;
pub fn PyDict_Merge(mp: *mut PyObject, other: *mut PyObject,
_override: c_int) -> c_int;
pub fn PyDict_MergeFromSeq2(d: *mut PyObject, seq2: *mut PyObject,
_override: c_int) -> c_int;
pub fn PyDict_GetItemString(dp: *mut PyObject, key: *const c_char)
-> *mut PyObject;
pub fn PyDict_Contains(mp: *mut PyObject, key: *mut PyObject) -> c_int;
pub fn PyDict_Update(mp: *mut PyObject, other: *mut PyObject) -> c_int;
pub fn PyDict_Merge(mp: *mut PyObject, other: *mut PyObject, _override: c_int) -> c_int;
pub fn PyDict_MergeFromSeq2(d: *mut PyObject, seq2: *mut PyObject, _override: c_int) -> c_int;
pub fn PyDict_GetItemString(dp: *mut PyObject, key: *const c_char) -> *mut PyObject;
pub fn PyDict_SetItemString(dp: *mut PyObject, key: *const c_char,
item: *mut PyObject) -> c_int;
pub fn PyDict_DelItemString(dp: *mut PyObject, key: *const c_char)
-> c_int;
pub fn PyDict_DelItemString(dp: *mut PyObject, key: *const c_char) -> c_int;
}

View File

@ -94,17 +94,32 @@ impl PyDict {
})
}
/// List of dict keys.
/// This is equivalent to the python expression `list(dict.keys())`.
pub fn keys(&self) -> &PyList {
unsafe {
self.py().cast_from_ptr::<PyList>(ffi::PyDict_Keys(self.as_ptr()))
}
}
/// List of dict values.
/// This is equivalent to the python expression `list(dict.values())`.
pub fn values(&self) -> &PyList {
unsafe {
self.py().cast_from_ptr::<PyList>(ffi::PyDict_Values(self.as_ptr()))
}
}
/// List of dict items.
/// This is equivalent to the python expression `list(dict.items())`.
pub fn items_list(&self) -> &PyList {
pub fn items(&self) -> &PyList {
unsafe {
self.py().cast_from_ptr::<PyList>(
ffi::PyDict_Items(self.as_ptr()))
self.py().cast_from_ptr::<PyList>(ffi::PyDict_Items(self.as_ptr()))
}
}
/// Returns the list of (key, value) pairs in this dictionary.
pub fn items(&self) -> Vec<(PyObject, PyObject)> {
pub fn items_vec(&self) -> Vec<(PyObject, PyObject)> {
// Note that we don't provide an iterator because
// PyDict_Next() is unsafe to use when the dictionary might be changed
// by other python code.
@ -231,6 +246,24 @@ mod test {
assert_eq!(123i32, dict.get_item(8i32).unwrap().extract::<i32>().unwrap());
}
#[test]
fn test_set_item_refcnt() {
let cnt;
{
let gil = Python::acquire_gil();
let py = gil.python();
let dict = PyDict::new(py);
let none = py.None();
cnt = none.get_refcnt();
dict.set_item(10, none).unwrap();
}
{
let gil = Python::acquire_gil();
let py = gil.python();
assert_eq!(cnt, py.None().get_refcnt());
}
}
#[test]
fn test_set_item_does_not_update_original_object() {
let gil = Python::acquire_gil();
@ -270,28 +303,6 @@ mod test {
assert_eq!(32i32, *v.get(&7i32).unwrap()); // not updated!
}
#[test]
fn test_items_list() {
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for el in dict.items_list().iter() {
let tuple = el.cast_as::<PyTuple>().unwrap();
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
value_sum += tuple.get_item(1).extract::<i32>().unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);
}
#[test]
fn test_items() {
let gil = Python::acquire_gil();
@ -305,7 +316,65 @@ mod test {
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for (key, value) in dict.items() {
for el in dict.items().iter() {
let tuple = el.cast_as::<PyTuple>().unwrap();
key_sum += tuple.get_item(0).extract::<i32>().unwrap();
value_sum += tuple.get_item(1).extract::<i32>().unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
assert_eq!(32 + 42 + 123, value_sum);
}
#[test]
fn test_keys() {
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
for el in dict.keys().iter() {
key_sum += el.extract::<i32>().unwrap();
}
assert_eq!(7 + 8 + 9, key_sum);
}
#[test]
fn test_values() {
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut values_sum = 0;
for el in dict.values().iter() {
values_sum += el.extract::<i32>().unwrap();
}
assert_eq!(32 + 42 + 123, values_sum);
}
#[test]
fn test_items_vec() {
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);
v.insert(8, 42);
v.insert(9, 123);
let ob = v.to_object(py);
let dict = PyDict::downcast_from(ob.as_ref(py)).unwrap();
// Can't just compare against a vector of tuples since we don't have a guaranteed ordering.
let mut key_sum = 0;
let mut value_sum = 0;
for (key, value) in dict.items_vec() {
key_sum += key.extract::<i32>(py).unwrap();
value_sum += value.extract::<i32>(py).unwrap();
}