From b643ef8f8e92728c2a4afaaa860592e384c7178c Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sun, 31 Oct 2010 08:00:16 +0000 Subject: [PATCH] Issue #5729: json.dumps to support using '\t' as an indent string --- Doc/library/json.rst | 10 +++++---- Lib/json/encoder.py | 11 ++++++---- Lib/json/tests/test_indent.py | 40 +++++++++++++++++++---------------- Misc/NEWS | 3 +++ 4 files changed, 38 insertions(+), 26 deletions(-) diff --git a/Doc/library/json.rst b/Doc/library/json.rst index a26001d1cb6..b0703a4aef6 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -135,10 +135,12 @@ Basic Usage ``inf``, ``-inf``) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - 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. ``None`` (the default) selects the most compact - representation. + If *indent* is a non-negative integer or string, then JSON array elements and + object members will be pretty-printed with that indent level. An indent level + of 0 or ``""`` will only insert newlines. ``None`` (the default) selects the + most compact representation. Using an integer indent indents that many spaces + per level. If *indent* is a string (such at '\t'), that string is used to indent + each level. If *separators* is an ``(item_separator, dict_separator)`` tuple, then it will be used instead of the default ``(', ', ': ')`` separators. ``(',', diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py index 13359856d29..7475f5a5443 100644 --- a/Lib/json/encoder.py +++ b/Lib/json/encoder.py @@ -259,6 +259,9 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, tuple=tuple, ): + if _indent is not None and not isinstance(_indent, str): + _indent = ' ' * _indent + def _iterencode_list(lst, _current_indent_level): if not lst: yield '[]' @@ -271,7 +274,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, buf = '[' if _indent is not None: _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) + newline_indent = '\n' + _indent * _current_indent_level separator = _item_separator + newline_indent buf += newline_indent else: @@ -307,7 +310,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, yield chunk if newline_indent is not None: _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) + yield '\n' + _indent * _current_indent_level yield ']' if markers is not None: del markers[markerid] @@ -324,7 +327,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, yield '{' if _indent is not None: _current_indent_level += 1 - newline_indent = '\n' + (' ' * (_indent * _current_indent_level)) + newline_indent = '\n' + _indent * _current_indent_level item_separator = _item_separator + newline_indent yield newline_indent else: @@ -383,7 +386,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, yield chunk if newline_indent is not None: _current_indent_level -= 1 - yield '\n' + (' ' * (_indent * _current_indent_level)) + yield '\n' + _indent * _current_indent_level yield '}' if markers is not None: del markers[markerid] diff --git a/Lib/json/tests/test_indent.py b/Lib/json/tests/test_indent.py index 605516230fb..ddf88cd4afc 100644 --- a/Lib/json/tests/test_indent.py +++ b/Lib/json/tests/test_indent.py @@ -10,32 +10,36 @@ class TestIndent(TestCase): expect = textwrap.dedent("""\ [ - [ - "blorpie" - ], - [ - "whoops" - ], - [], - "d-shtaeou", - "d-nthiouh", - "i-vhbjkhnth", - { - "nifty": 87 - }, - { - "field": "yes", - "morefield": false - } + \t[ + \t\t"blorpie" + \t], + \t[ + \t\t"whoops" + \t], + \t[], + \t"d-shtaeou", + \t"d-nthiouh", + \t"i-vhbjkhnth", + \t{ + \t\t"nifty": 87 + \t}, + \t{ + \t\t"field": "yes", + \t\t"morefield": false + \t} ]""") d1 = json.dumps(h) d2 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + d3 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) h1 = json.loads(d1) h2 = json.loads(d2) + h3 = json.loads(d3) self.assertEquals(h1, h) self.assertEquals(h2, h) - self.assertEquals(d2, expect) + self.assertEquals(h3, h) + self.assertEquals(d2, expect.expandtabs(2)) + self.assertEquals(d3, expect) diff --git a/Misc/NEWS b/Misc/NEWS index 21dcacfdb81..199e4c78fe3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Core and Builtins Library ------- +- Issue #5729: json.dumps() now supports using a string such as '\t' + for pretty-printing multilevel objects. + - Issue #10253: FileIO leaks a file descriptor when trying to open a file for append that isn't seekable. Patch by Brian Brazil.