]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-131884: Fix incorrect formatting in json.dumps() when using indent and skipkeys...
authorRoei Ben Artzi <155478676+roeibenartzi@users.noreply.github.com>
Tue, 3 Jun 2025 07:40:25 +0000 (10:40 +0300)
committerGitHub <noreply@github.com>
Tue, 3 Jun 2025 07:40:25 +0000 (10:40 +0300)
Lib/json/encoder.py
Lib/test/test_json/test_dump.py
Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst [new file with mode: 0644]
Modules/_json.c

index 016638549aa59b699664af281dcb9a8f6d172c10..bc446e0f377a119f369f694e70e9810a9e3975ca 100644 (file)
@@ -348,7 +348,6 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
             _current_indent_level += 1
             newline_indent = '\n' + _indent * _current_indent_level
             item_separator = _item_separator + newline_indent
-            yield newline_indent
         else:
             newline_indent = None
             item_separator = _item_separator
@@ -381,6 +380,8 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
                                 f'not {key.__class__.__name__}')
             if first:
                 first = False
+                if newline_indent is not None:
+                    yield newline_indent
             else:
                 yield item_separator
             yield _encoder(key)
@@ -413,7 +414,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
             except BaseException as exc:
                 exc.add_note(f'when serializing {type(dct).__name__} item {key!r}')
                 raise
-        if newline_indent is not None:
+        if not first and newline_indent is not None:
             _current_indent_level -= 1
             yield '\n' + _indent * _current_indent_level
         yield '}'
index 13b40020781bae33ea47c8ff5446030e7f348677..39470754003bb6f11b26a6fe5296e761a2648bed 100644 (file)
@@ -22,6 +22,14 @@ class TestDump:
         self.assertIn('valid_key', o)
         self.assertNotIn(b'invalid_key', o)
 
+    def test_dump_skipkeys_indent_empty(self):
+        v = {b'invalid_key': False}
+        self.assertEqual(self.json.dumps(v, skipkeys=True, indent=4), '{}')
+
+    def test_skipkeys_indent(self):
+        v = {b'invalid_key': False, 'valid_key': True}
+        self.assertEqual(self.json.dumps(v, skipkeys=True, indent=4), '{\n    "valid_key": true\n}')
+
     def test_encode_truefalse(self):
         self.assertEqual(self.dumps(
                  {True: False, False: True}, sort_keys=True),
diff --git a/Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst b/Misc/NEWS.d/next/Library/2025-04-07-06-41-54.gh-issue-131884.ym9BJN.rst
new file mode 100644 (file)
index 0000000..d9e2eae
--- /dev/null
@@ -0,0 +1 @@
+Fix formatting issues in :func:`json.dump` when both *indent* and *skipkeys* are used.
index 57678ad595f928571b37ddd804e3547c10f90e1a..6b5f6ea42df4d1c15f90742147d4d5f798b14cc8 100644 (file)
@@ -1603,6 +1603,12 @@ encoder_encode_key_value(PyEncoderObject *s, PyUnicodeWriter *writer, bool *firs
 
     if (*first) {
         *first = false;
+        if (s->indent != Py_None) {
+            if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
+                Py_DECREF(keystr);
+                return -1;
+            }
+        }
     }
     else {
         if (PyUnicodeWriter_WriteStr(writer, item_separator) < 0) {
@@ -1670,11 +1676,8 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
     if (s->indent != Py_None) {
         indent_level++;
         separator = get_item_separator(s, indent_level, indent_cache);
-        if (separator == NULL ||
-            write_newline_indent(writer, indent_level, indent_cache) < 0)
-        {
+        if (separator == NULL)
             goto bail;
-        }
     }
 
     if (s->sort_keys || !PyDict_CheckExact(dct)) {
@@ -1714,7 +1717,7 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer,
             goto bail;
         Py_CLEAR(ident);
     }
-    if (s->indent != Py_None) {
+    if (s->indent != Py_None && !first) {
         indent_level--;
         if (write_newline_indent(writer, indent_level, indent_cache) < 0) {
             goto bail;