]> granicus.if.org Git - python/commitdiff
bpo-24641: Improved error message for JSON unserializible keys. (#4364)
authorSerhiy Storchaka <storchaka@gmail.com>
Sat, 25 Nov 2017 15:38:20 +0000 (17:38 +0200)
committerGitHub <noreply@github.com>
Sat, 25 Nov 2017 15:38:20 +0000 (17:38 +0200)
Also updated an example for default() in the module docstring.
Removed quotes around type name in other error messages.

Lib/json/__init__.py
Lib/json/encoder.py
Lib/test/test_json/test_fail.py
Modules/_json.c

index 6d0511ebfe90cf9451e464f714d318f989159f2a..a5660099af7514534983f915c33c1edececa2a85 100644 (file)
@@ -76,7 +76,8 @@ Specializing JSON object encoding::
     >>> def encode_complex(obj):
     ...     if isinstance(obj, complex):
     ...         return [obj.real, obj.imag]
-    ...     raise TypeError(repr(obj) + " is not JSON serializable")
+    ...     raise TypeError(f'Object of type {obj.__class__.__name__} '
+    ...                     f'is not JSON serializable')
     ...
     >>> json.dumps(2 + 1j, default=encode_complex)
     '[2.0, 1.0]'
@@ -344,8 +345,8 @@ def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None,
                                   s, 0)
     else:
         if not isinstance(s, (bytes, bytearray)):
-            raise TypeError('the JSON object must be str, bytes or bytearray, '
-                            'not {!r}'.format(s.__class__.__name__))
+            raise TypeError(f'the JSON object must be str, bytes or bytearray, '
+                            f'not {s.__class__.__name__}')
         s = s.decode(detect_encoding(s), 'surrogatepass')
 
     if (cls is None and object_hook is None and
index 41a497c5da016031f055059366c31b53dacbcf47..fb083ed61bb1f8b83b26aa69bd89411dddf4e75a 100644 (file)
@@ -176,8 +176,8 @@ class JSONEncoder(object):
                 return JSONEncoder.default(self, o)
 
         """
-        raise TypeError("Object of type '%s' is not JSON serializable" %
-                        o.__class__.__name__)
+        raise TypeError(f'Object of type {o.__class__.__name__} '
+                        f'is not JSON serializable')
 
     def encode(self, o):
         """Return a JSON string representation of a Python data structure.
@@ -373,7 +373,8 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
             elif _skipkeys:
                 continue
             else:
-                raise TypeError("key " + repr(key) + " is not a string")
+                raise TypeError(f'keys must be str, int, float, bool or None, '
+                                f'not {key.__class__.__name__}')
             if first:
                 first = False
             else:
index 791052102140b764c7cc5a78faa1e068894e07fd..eb9064edea9115d86292a455e420fee968b04a82 100644 (file)
@@ -93,12 +93,15 @@ class TestFail:
 
     def test_non_string_keys_dict(self):
         data = {'a' : 1, (1, 2) : 2}
+        with self.assertRaisesRegex(TypeError,
+                'keys must be str, int, float, bool or None, not tuple'):
+            self.dumps(data)
 
-        #This is for c encoder
-        self.assertRaises(TypeError, self.dumps, data)
-
-        #This is for python encoder
-        self.assertRaises(TypeError, self.dumps, data, indent=True)
+    def test_not_serializable(self):
+        import sys
+        with self.assertRaisesRegex(TypeError,
+                'Object of type module is not JSON serializable'):
+            self.dumps(sys)
 
     def test_truncated_input(self):
         test_cases = [
index 13218a6ecce587bc5de63911b2ba973aeb8c99c4..5a9464e34fb7f339d5f494cce00f8bf07a65c6b1 100644 (file)
@@ -1650,8 +1650,9 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
             continue;
         }
         else {
-            /* TODO: include repr of key */
-            PyErr_SetString(PyExc_TypeError, "keys must be a string");
+            PyErr_Format(PyExc_TypeError,
+                         "keys must be str, int, float, bool or None, "
+                         "not %.100s", key->ob_type->tp_name);
             goto bail;
         }