diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 4e7046d6d8f6ac..315bd793c1bdcb 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -239,6 +239,12 @@ Basic Usage .. versionchanged:: 3.6 All optional parameters are now :ref:`keyword-only `. + :param bool arr_oneline: + **New in this release.** + If ``True``, JSON arrays (Python lists and tuples) will be serialized + on a single line regardless of the specified *indent* level. This allows + for a more compact representation of array data while still pretty-printing + objects. Default is ``False``. .. function:: dumps(obj, *, skipkeys=False, ensure_ascii=True, \ check_circular=True, allow_nan=True, cls=None, \ @@ -450,8 +456,7 @@ Encoders and Decoders This can be used to decode a JSON document from a string that may have extraneous data at the end. - -.. class:: JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None) +.. class:: JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None, arr_oneline=False) Extensible JSON encoder for Python data structures. @@ -518,19 +523,26 @@ Encoders and Decoders .. versionchanged:: 3.2 Allow strings for *indent* in addition to integers. - If specified, *separators* should be an ``(item_separator, key_separator)`` - tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` and - ``(',', ': ')`` otherwise. To get the most compact JSON representation, + If specified, *separators* should be a ``(item_separator, key_separator)`` + tuple. The default is ``(', ', ': ')`` if *indent* is ``None`` + and ``(',', ': ')`` otherwise. To get the most compact JSON representation, you should specify ``(',', ':')`` to eliminate whitespace. .. versionchanged:: 3.4 Use ``(',', ': ')`` as default if *indent* is not ``None``. - + If specified, *default* should be a function that gets called for objects that can't otherwise be serialized. It should return a JSON encodable version of the object or raise a :exc:`TypeError`. If not specified, :exc:`TypeError` is raised. - + + :param bool arr_oneline: + **New in this release.** + When ``True``, JSON arrays (lists and tuples) are rendered on a single line, + even if an *indent* level is specified. This option allows for a more compact + representation of array data while still enabling pretty-printing of objects. + Default is ``False``. + .. versionchanged:: 3.6 All parameters are now :ref:`keyword-only `. @@ -828,4 +840,4 @@ Command-line options `_, JSON permits literal U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR) characters in strings, whereas JavaScript - (as of ECMAScript Edition 5.1) does not. + (as of ECMAScript Edition 5.1) does not. \ No newline at end of file diff --git a/Lib/json/__init__.py b/Lib/json/__init__.py index 1d972d22ded072..0a1fba6bc7352d 100644 --- a/Lib/json/__init__.py +++ b/Lib/json/__init__.py @@ -119,7 +119,7 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, - default=None, sort_keys=False, **kw): + default=None, sort_keys=False, arr_oneline=False, **kw): """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a ``.write()``-supporting file-like object). @@ -155,6 +155,8 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, If *sort_keys* is true (default: ``False``), then the output of dictionaries will be sorted by key. + If *arr_oneline* is true (default: ``False``), then lists/tuples will be + encoded as arrays on a single line. To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the ``.default()`` method to serialize additional types), specify it with @@ -172,8 +174,8 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, cls = JSONEncoder iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, - default=default, sort_keys=sort_keys, **kw).iterencode(obj) + separators=separators, default=default, sort_keys=sort_keys, + arr_oneline=arr_oneline, **kw).iterencode(obj) # could accelerate with writelines in some versions of Python, at # a debuggability cost for chunk in iterable: @@ -182,7 +184,7 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, - default=None, sort_keys=False, **kw): + default=None, sort_keys=False, arr_oneline=False, **kw): """Serialize ``obj`` to a JSON formatted ``str``. If ``skipkeys`` is true then ``dict`` keys that are not basic types @@ -217,6 +219,8 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, If *sort_keys* is true (default: ``False``), then the output of dictionaries will be sorted by key. + If *arr_oneline* is true (default: ``False``), then lists/tuples will be + encoded as arrays on a single line. To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the ``.default()`` method to serialize additional types), specify it with @@ -235,7 +239,7 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, skipkeys=skipkeys, ensure_ascii=ensure_ascii, check_circular=check_circular, allow_nan=allow_nan, indent=indent, separators=separators, default=default, sort_keys=sort_keys, - **kw).encode(obj) + arr_oneline=arr_oneline, **kw).encode(obj) _default_decoder = JSONDecoder(object_hook=None, object_pairs_hook=None) diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py index b804224098e14f..5b22324f4b7e23 100644 --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -104,7 +104,7 @@ class JSONEncoder(object): key_separator = ': ' def __init__(self, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, default=None): + indent=None, separators=None, default=None, arr_oneline=False): """Constructor for JSONEncoder, with sensible defaults. If skipkeys is false, then it is a TypeError to attempt @@ -129,6 +129,10 @@ def __init__(self, *, skipkeys=False, ensure_ascii=True, sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis. + If arr_oneline is true, then lists/tuples will be output as arrays + on a single line. If false, a newline character will be placed after each + array element. + If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. @@ -151,6 +155,7 @@ def __init__(self, *, skipkeys=False, ensure_ascii=True, self.allow_nan = allow_nan self.sort_keys = sort_keys self.indent = indent + self.arr_oneline = arr_oneline if separators is not None: self.item_separator, self.key_separator = separators elif indent is not None: @@ -257,11 +262,12 @@ def floatstr(o, allow_nan=self.allow_nan, _iterencode = _make_iterencode( markers, self.default, _encoder, indent, floatstr, self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot) + self.skipkeys, _one_shot, self.arr_oneline) return _iterencode(o, 0) def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, + arr_oneline, ## HACK: hand-optimized bytecode; turn globals into locals ValueError=ValueError, dict=dict, @@ -287,7 +293,10 @@ def _iterencode_list(lst, _current_indent_level): buf = '[' if _indent is not None: _current_indent_level += 1 - newline_indent = '\n' + _indent * _current_indent_level + if not arr_oneline: + newline_indent = '\n' + _indent * _current_indent_level + else: + newline_indent = '' separator = _item_separator + newline_indent buf += newline_indent else: @@ -329,7 +338,8 @@ def _iterencode_list(lst, _current_indent_level): raise if newline_indent is not None: _current_indent_level -= 1 - yield '\n' + _indent * _current_indent_level + if not arr_oneline: + yield '\n' + _indent * _current_indent_level yield ']' if markers is not None: del markers[markerid] diff --git a/Misc/NEWS.d/next/Library/2022-03-08-11-13-25.bpo-46958.2CkwDp.rst b/Misc/NEWS.d/next/Library/2022-03-08-11-13-25.bpo-46958.2CkwDp.rst new file mode 100644 index 00000000000000..bd6679afee68dc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-03-08-11-13-25.bpo-46958.2CkwDp.rst @@ -0,0 +1,3 @@ +Added optional argument *list_oneline* to :meth:`json.dump` and +:meth:`json.dumps` for printing array output on a single +line. Patch by Daniel Marshall.