Skip to content

Commit

Permalink
bpo-24641: Improved error message for JSON unserializible keys. (pyth…
Browse files Browse the repository at this point in the history
…on#4364)

Also updated an example for default() in the module docstring.
Removed quotes around type name in other error messages.
  • Loading branch information
serhiy-storchaka authored Nov 25, 2017
1 parent 5b48dc6 commit cfa797c
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 13 deletions.
7 changes: 4 additions & 3 deletions Lib/json/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
>>> 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]'
Expand Down Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions Lib/json/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ def default(self, o):
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.
Expand Down Expand Up @@ -373,7 +373,8 @@ def _iterencode_dict(dct, _current_indent_level):
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:
Expand Down
13 changes: 8 additions & 5 deletions Lib/test/test_json/test_fail.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@ def test_failures(self):

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 = [
Expand Down
5 changes: 3 additions & 2 deletions Modules/_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit cfa797c

Please sign in to comment.