Skip to content
Closed
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
5 changes: 4 additions & 1 deletion Doc/library/json.rst
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ Encoders and Decoders
+========================================+===============+
| dict | object |
+----------------------------------------+---------------+
| list, tuple | array |
| list, tuple, deque | array |
+----------------------------------------+---------------+
| str | string |
+----------------------------------------+---------------+
Expand All @@ -406,6 +406,9 @@ Encoders and Decoders
.. versionchanged:: 3.4
Added support for int- and float-derived Enum classes.

.. versionchanged:: 3.8
Added support for deque.

To extend this to recognize other objects, subclass and implement a
:meth:`default` method with another method that returns a serializable object
for ``o`` if possible, otherwise it should call the superclass implementation
Expand Down
8 changes: 4 additions & 4 deletions Lib/json/encoder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Implementation of JSONEncoder
"""
import re

from collections import deque
try:
from _json import encode_basestring_ascii as c_encode_basestring_ascii
except ImportError:
Expand Down Expand Up @@ -316,7 +316,7 @@ def _iterencode_list(lst, _current_indent_level):
yield buf + _floatstr(value)
else:
yield buf
if isinstance(value, (list, tuple)):
if isinstance(value, (list, tuple, deque)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
Expand Down Expand Up @@ -395,7 +395,7 @@ def _iterencode_dict(dct, _current_indent_level):
# see comment for int/float in _make_iterencode
yield _floatstr(value)
else:
if isinstance(value, (list, tuple)):
if isinstance(value, (list, tuple, deque)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
Expand Down Expand Up @@ -424,7 +424,7 @@ def _iterencode(o, _current_indent_level):
elif isinstance(o, float):
# see comment for int/float in _make_iterencode
yield _floatstr(o)
elif isinstance(o, (list, tuple)):
elif isinstance(o, (list, tuple, deque)):
yield from _iterencode_list(o, _current_indent_level)
elif isinstance(o, dict):
yield from _iterencode_dict(o, _current_indent_level)
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_json/test_deque.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from collections import deque
from test.test_json import PyTest, CTest


class TestDeque:
def test_deque_ints(self):
d = deque(range(0, 10))
self.assertEqual(self.dumps(d), '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]')

def test_deque_strings(self):
d = deque('hello')
self.assertEqual(self.dumps(d), '["h", "e", "l", "l", "o"]')


class TestPyDeque(TestDeque, PyTest): pass
class TestCDeque(TestDeque, CTest): pass
6 changes: 5 additions & 1 deletion Modules/_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,10 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
/* Encode Python object obj to a JSON term */
PyObject *newobj;
int rv;
PyObject *mo = PyImport_ImportModule("collections");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't you need to decrease the reference counter to mo and deque_type after using them?

PyObject *deque_type = PyObject_GetAttrString(mo, "deque");

Py_DECREF(mo);
if (obj == Py_None || obj == Py_True || obj == Py_False) {
PyObject *cstr = _encoded_const(obj);
if (cstr == NULL)
Expand All @@ -1519,7 +1522,8 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
return -1;
return _steal_accumulate(acc, encoded);
}
else if (PyList_Check(obj) || PyTuple_Check(obj)) {
else if (PyList_Check(obj) || PyTuple_Check(obj) || PyObject_IsInstance(obj, deque_type)) {
Py_DECREF(deque_type);
if (Py_EnterRecursiveCall(" while encoding a JSON object"))
return -1;
rv = encoder_listencode_list(s, acc, obj, indent_level);
Expand Down