FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-139772: Add PyDict_FromItems() function by vstinner · Pull Request #139963 · python/cpython · GitHub

Repository navigation

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (2) .h  (1) .py  (1) .rst  (3) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
16 changes: 16 additions & 0 deletions Doc/c-api/dict.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ Dictionary Objects
Return a new empty dictionary, or ``NULL`` on failure.


.. c:function:: PyObject* PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset, PyObject *const *values, Py_ssize_t values_offset, Py_ssize_t length)

Create a dictionary from *keys* and *values* of *length* items.

*keys_offset* is the offset to access the *keys* array and
*values_offset* is the offset to access the *values* array.
*keys_offset* and *values_offset* must be greater than ``0``.

If *length* is ``0``, *keys*, *keys_offset*, *values* and *values_offset*
arguments are ignored, and an empty dictionary is created.

Return a new dictionary, or ``NULL`` on failure.

.. versionadded:: next


.. c:function:: PyObject* PyDictProxy_New(PyObject *mapping)

Return a :class:`types.MappingProxyType` object for a mapping which
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.15.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,10 @@ New features

(Contributed by Victor Stinner in :gh:`129813`.)

* Add :c:func:`PyDict_FromItems` to create a dictionary from an array of keys
and an array of values.
(Contributed by Victor Stinner in :gh:`139772`.)

* Add :c:func:`PyTuple_FromArray` to create a :class:`tuple` from an array.
(Contributed by Victor Stinner in :gh:`111489`.)

Expand Down
7 changes: 7 additions & 0 deletions Include/cpython/dictobject.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,10 @@ PyAPI_FUNC(int) PyDict_ClearWatcher(int watcher_id);
// Mark given dictionary as "watched" (callback will be called if it is modified)
PyAPI_FUNC(int) PyDict_Watch(int watcher_id, PyObject* dict);
PyAPI_FUNC(int) PyDict_Unwatch(int watcher_id, PyObject* dict);

PyAPI_FUNC(PyObject*) PyDict_FromItems(
PyObject *const *keys,
Py_ssize_t keys_offset,
PyObject *const *values,
Py_ssize_t values_offset,
Py_ssize_t length);
45 changes: 45 additions & 0 deletions Lib/test/test_capi/test_dict.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,51 @@ def test_dict_popstring(self):
# CRASHES dict_popstring({}, NULL)
# CRASHES dict_popstring({"a": 1}, NULL)

def test_dict_fromitems(self):
# Test PyDict_FromItems()
dict_fromitems = _testcapi.dict_fromitems

d = dict_fromitems((), 1, (), 1)
self.assertEqual(d, {})

d = dict_fromitems(tuple(range(1, 4)), 1, tuple('abc'), 1)
self.assertEqual(d, {1: 'a', 2: 'b', 3: 'c'})

# test unicode keys
d = dict_fromitems(tuple('abc'), 1, tuple(range(1, 4)), 1)
self.assertEqual(d, {'a': 1, 'b': 2, 'c': 3})

# test "large" dict (1024 items)
d = dict_fromitems(tuple(range(1024)), 1,
tuple(map(str, range(1024))), 1)
self.assertEqual(d, {i: str(i) for i in range(1024)})

# same array for keys and values with keys_offset=values_offset=2
array = ('a', 1, 'b', 2, 'c', 3)
d = dict_fromitems(array, 2)
self.assertEqual(d, {'a': 1, 'b': 2, 'c': 3})

array = ('a', 1, None, 'b', 2, None, 'c', 3, None)
d = dict_fromitems(array, 3)
self.assertEqual(d, {'a': 1, 'b': 2, 'c': 3})

# Test PyDict_FromItems(NULL, 0, NULL, 0, 0)
d = dict_fromitems()
self.assertEqual(d, {})

# test invalid arguments
errmsg = "keys_offset must be greater than 0"
with self.assertRaisesRegex(ValueError, errmsg):
dict_fromitems(tuple('abc'), 0, tuple(range(1, 4)), 1)

errmsg = "values_offset must be greater than 0"
with self.assertRaisesRegex(ValueError, errmsg):
dict_fromitems(tuple('abc'), 1, tuple(range(1, 4)), 0)

errmsg = "length must be greater than or equal to 0"
with self.assertRaisesRegex(ValueError, errmsg):
dict_fromitems(tuple('abc'), 1, tuple(range(1, 4)), 1, -1)


if __name__ == "__main__":
unittest.main()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :c:func:`PyDict_FromItems` to create a dictionary from an array of keys and
an array of values. Patch by Victor Stinner.
56 changes: 55 additions & 1 deletion Modules/_testcapi/dict.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,59 @@ test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored))
}


static PyObject*
dict_fromitems(PyObject* self, PyObject *args)
{
PyObject *keys_obj = UNINITIALIZED_PTR, *values_obj = UNINITIALIZED_PTR;
Py_ssize_t keys_offset = UNINITIALIZED_SIZE, values_offset = UNINITIALIZED_SIZE;
Py_ssize_t length = UNINITIALIZED_SIZE;
if (!PyArg_ParseTuple(args, "|O!nO!nn",
&PyTuple_Type, &keys_obj, &keys_offset,
&PyTuple_Type, &values_obj, &values_offset,
&length)) {
return NULL;
}

PyObject **keys, **values;
if (keys_obj != UNINITIALIZED_PTR) {
keys = &PyTuple_GET_ITEM(keys_obj, 0);
if (values_obj != UNINITIALIZED_PTR) {
values = &PyTuple_GET_ITEM(values_obj, 0);
}
else {
values = keys + 1;
}
}
else {
keys = NULL;
values = NULL;
}

if (keys_offset == UNINITIALIZED_SIZE) {
keys_offset = 0;
}
if (values_offset == UNINITIALIZED_SIZE) {
values_offset = keys_offset;
}

if (length == UNINITIALIZED_SIZE) {
if (keys_obj != UNINITIALIZED_PTR) {
if (keys_offset >= 1) {
length = PyTuple_GET_SIZE(keys_obj) / keys_offset;
}
else {
length = PyTuple_GET_SIZE(keys_obj);
}
}
else {
length = 0;
}
}

return PyDict_FromItems(keys, keys_offset, values, values_offset, length);
}


static PyMethodDef test_methods[] = {
{"dict_containsstring", dict_containsstring, METH_VARARGS},
{"dict_getitemref", dict_getitemref, METH_VARARGS},
Expand All @@ -268,7 +321,8 @@ static PyMethodDef test_methods[] = {
{"dict_pop_null", dict_pop_null, METH_VARARGS},
{"dict_popstring", dict_popstring, METH_VARARGS},
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
{"test_dict_iteration", test_dict_iteration, METH_NOARGS},
{"dict_fromitems", dict_fromitems, METH_VARARGS},
{NULL},
};

Expand Down
30 changes: 30 additions & 0 deletions Objects/dictobject.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2230,6 +2230,10 @@ _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
PyObject *const *values, Py_ssize_t values_offset,
Py_ssize_t length)
{
assert(keys == NULL || keys_offset >= 1);
assert(values == NULL || values_offset >= 1);
assert(length >= 0);

bool unicode = true;
PyObject *const *ks = keys;

Expand Down Expand Up @@ -2263,6 +2267,32 @@ _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
return dict;
}


PyObject *
PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
PyObject *const *values, Py_ssize_t values_offset,
Py_ssize_t length)
{
if (keys != NULL && keys_offset < 1) {
PyErr_SetString(PyExc_ValueError,
"keys_offset must be greater than 0");
return NULL;
}
if (values != NULL && values_offset < 1) {
PyErr_SetString(PyExc_ValueError,
"values_offset must be greater than 0");
return NULL;
}
if (length < 0) {
PyErr_SetString(PyExc_ValueError,
"length must be greater than or equal to 0");
return NULL;
}

return _PyDict_FromItems(keys, keys_offset, values, values_offset, length);
}


/* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
* that may occur (originally dicts supported only string keys, and exceptions
* weren't possible). So, while the original intent was that a NULL return
Expand Down
Loading

Back | FazBrowse Home | New Git URL