Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Doc/c-api/dict.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ Dictionary objects
Return a new dictionary that contains the same key-value pairs as *p*.
.. versionchanged:: next
If *p* is a subclass of :class:`frozendict`, the result will be a
:class:`frozendict` instance instead of a :class:`dict` instance.
.. c:function:: int PyDict_SetItem(PyObject *p, PyObject *key, PyObject *val)
Insert *val* into the dictionary *p* with a key of *key*. *key* must be
Expand Down
16 changes: 4 additions & 12 deletions Lib/test/test_capi/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,13 @@ def test_dictproxy_new(self):
def test_dict_copy(self):
# Test PyDict_Copy()
copy = _testlimitedcapi.dict_copy
for dict_type in ANYDICT_TYPES:
for dict_type in DICT_TYPES:
dct = dict_type({1: 2})
dct_copy = copy(dct)
if dict_type == frozendict:
expected_type = frozendict
self.assertIs(dct_copy, dct)
else:
if issubclass(dict_type, frozendict):
expected_type = frozendict
else:
expected_type = dict
self.assertIs(type(dct_copy), expected_type)
self.assertEqual(dct_copy, dct)
self.assertIs(type(dct_copy), dict)
self.assertEqual(dct_copy, dct)

for test_type in NOT_ANYDICT_TYPES + OTHER_TYPES:
for test_type in NOT_DICT_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, copy, test_type())
self.assertRaises(SystemError, copy, NULL)

Expand Down
20 changes: 19 additions & 1 deletion Objects/clinic/dictobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 43 additions & 21 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ static int dict_merge_from_seq2(PyObject *d, PyObject *seq2, int override);

/*[clinic input]
class dict "PyDictObject *" "&PyDict_Type"
class frozendict "PyFrozenDictObject *" "&PyFrozenDict_Type"
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=5dfa93bac68e7c54]*/


/*
Expand Down Expand Up @@ -2406,7 +2407,7 @@ dict_unhashable_type(PyObject *op, PyObject *key)
}

const char *errmsg;
if (PyObject_IsInstance(op, (PyObject*)&PyFrozenDict_Type)) {
if (PyFrozenDict_Check(op)) {
errmsg = "cannot use '%T' as a frozendict key (%S)";
}
else {
Expand Down Expand Up @@ -4384,35 +4385,37 @@ copy_lock_held(PyObject *o, int as_frozendict)
return NULL;
}

// Similar to PyDict_Copy(), but copy also frozendict.
static PyObject *
_PyDict_Copy(PyObject *o)
PyObject *
PyDict_Copy(PyObject *o)
{
assert(PyAnyDict_Check(o));
if (o == NULL || !PyDict_Check(o)) {
PyErr_BadInternalCall();
return NULL;
}

PyObject *res;
Py_BEGIN_CRITICAL_SECTION(o);
res = copy_lock_held(o, PyFrozenDict_Check(o));
res = copy_lock_held(o, 0);
Py_END_CRITICAL_SECTION();
return res;
}

PyObject *
PyDict_Copy(PyObject *o)
// Similar to PyDict_Copy(), but return a frozendict if the argument
// is a frozendict.
static PyObject *
anydict_copy(PyObject *o)
{
if (o == NULL || !PyAnyDict_Check(o)) {
PyErr_BadInternalCall();
return NULL;
}

if (PyFrozenDict_CheckExact(o)) {
return Py_NewRef(o);
}
assert(PyAnyDict_Check(o));

return _PyDict_Copy(o);
PyObject *res;
Py_BEGIN_CRITICAL_SECTION(o);
res = copy_lock_held(o, PyFrozenDict_Check(o));
Py_END_CRITICAL_SECTION();
return res;
}

// Similar to PyDict_Copy(), but return a dict if the argument is a frozendict.
// Similar to PyDict_Copy(), but accept also frozendict:
// convert frozendict to a new dict.
PyObject*
_PyDict_CopyAsDict(PyObject *o)
{
Expand Down Expand Up @@ -4969,7 +4972,7 @@ dict_or(PyObject *self, PyObject *other)
if (!PyAnyDict_Check(self) || !PyAnyDict_Check(other)) {
Py_RETURN_NOTIMPLEMENTED;
}
PyObject *new = _PyDict_Copy(self);
PyObject *new = anydict_copy(self);
if (new == NULL) {
return NULL;
}
Expand Down Expand Up @@ -8057,7 +8060,7 @@ static PyMethodDef frozendict_methods[] = {
DICT_ITEMS_METHODDEF
DICT_VALUES_METHODDEF
DICT_FROMKEYS_METHODDEF
DICT_COPY_METHODDEF
FROZENDICT_COPY_METHODDEF
DICT___REVERSED___METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{"__getnewargs__", frozendict_getnewargs, METH_NOARGS},
Expand Down Expand Up @@ -8182,6 +8185,25 @@ PyFrozenDict_New(PyObject *iterable)
}
}

/*[clinic input]
frozendict.copy
Return a shallow copy of the frozendict.
[clinic start generated code]*/

static PyObject *
frozendict_copy_impl(PyFrozenDictObject *self)
/*[clinic end generated code: output=e580fd91d9fc2cf7 input=35f6abeaa08fd4bc]*/
{
assert(PyFrozenDict_Check(self));

if (PyFrozenDict_CheckExact(self)) {
return Py_NewRef(self);
}

return anydict_copy((PyObject*)self);
}


PyTypeObject PyFrozenDict_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
Expand Down
Loading