summaryrefslogtreecommitdiffstats
path: root/Lib/json
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-07-23 17:02:54 (GMT)
committerGitHub <noreply@github.com>2024-07-23 17:02:54 (GMT)
commite6b25e9a09dbe09839b36f97b9174a30b1db2dbf (patch)
tree000493ed4293ecce1a6433e8892212fe9809c3d6 /Lib/json
parentc908d1f87d287a4b3ec58c85b692a7eb617fa6ea (diff)
downloadcpython-e6b25e9a09dbe09839b36f97b9174a30b1db2dbf.zip
cpython-e6b25e9a09dbe09839b36f97b9174a30b1db2dbf.tar.gz
cpython-e6b25e9a09dbe09839b36f97b9174a30b1db2dbf.tar.bz2
gh-122163: Add notes for JSON serialization errors (GH-122165)
This allows to identify the source of the error.
Diffstat (limited to 'Lib/json')
-rw-r--r--Lib/json/encoder.py119
1 files changed, 67 insertions, 52 deletions
diff --git a/Lib/json/encoder.py b/Lib/json/encoder.py
index 323332f..b804224 100644
--- a/Lib/json/encoder.py
+++ b/Lib/json/encoder.py
@@ -293,37 +293,40 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
else:
newline_indent = None
separator = _item_separator
- first = True
- for value in lst:
- if first:
- first = False
- else:
+ for i, value in enumerate(lst):
+ if i:
buf = separator
- if isinstance(value, str):
- yield buf + _encoder(value)
- elif value is None:
- yield buf + 'null'
- elif value is True:
- yield buf + 'true'
- elif value is False:
- yield buf + 'false'
- elif isinstance(value, int):
- # Subclasses of int/float may override __repr__, but we still
- # want to encode them as integers/floats in JSON. One example
- # within the standard library is IntEnum.
- yield buf + _intstr(value)
- elif isinstance(value, float):
- # see comment above for int
- yield buf + _floatstr(value)
- else:
- yield buf
- if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
- elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
+ try:
+ if isinstance(value, str):
+ yield buf + _encoder(value)
+ elif value is None:
+ yield buf + 'null'
+ elif value is True:
+ yield buf + 'true'
+ elif value is False:
+ yield buf + 'false'
+ elif isinstance(value, int):
+ # Subclasses of int/float may override __repr__, but we still
+ # want to encode them as integers/floats in JSON. One example
+ # within the standard library is IntEnum.
+ yield buf + _intstr(value)
+ elif isinstance(value, float):
+ # see comment above for int
+ yield buf + _floatstr(value)
else:
- chunks = _iterencode(value, _current_indent_level)
- yield from chunks
+ yield buf
+ if isinstance(value, (list, tuple)):
+ chunks = _iterencode_list(value, _current_indent_level)
+ elif isinstance(value, dict):
+ chunks = _iterencode_dict(value, _current_indent_level)
+ else:
+ chunks = _iterencode(value, _current_indent_level)
+ yield from chunks
+ except GeneratorExit:
+ raise
+ except BaseException as exc:
+ exc.add_note(f'when serializing {type(lst).__name__} item {i}')
+ raise
if newline_indent is not None:
_current_indent_level -= 1
yield '\n' + _indent * _current_indent_level
@@ -382,28 +385,34 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
yield item_separator
yield _encoder(key)
yield _key_separator
- if isinstance(value, str):
- yield _encoder(value)
- elif value is None:
- yield 'null'
- elif value is True:
- yield 'true'
- elif value is False:
- yield 'false'
- elif isinstance(value, int):
- # see comment for int/float in _make_iterencode
- yield _intstr(value)
- elif isinstance(value, float):
- # see comment for int/float in _make_iterencode
- yield _floatstr(value)
- else:
- if isinstance(value, (list, tuple)):
- chunks = _iterencode_list(value, _current_indent_level)
- elif isinstance(value, dict):
- chunks = _iterencode_dict(value, _current_indent_level)
+ try:
+ if isinstance(value, str):
+ yield _encoder(value)
+ elif value is None:
+ yield 'null'
+ elif value is True:
+ yield 'true'
+ elif value is False:
+ yield 'false'
+ elif isinstance(value, int):
+ # see comment for int/float in _make_iterencode
+ yield _intstr(value)
+ elif isinstance(value, float):
+ # see comment for int/float in _make_iterencode
+ yield _floatstr(value)
else:
- chunks = _iterencode(value, _current_indent_level)
- yield from chunks
+ if isinstance(value, (list, tuple)):
+ chunks = _iterencode_list(value, _current_indent_level)
+ elif isinstance(value, dict):
+ chunks = _iterencode_dict(value, _current_indent_level)
+ else:
+ chunks = _iterencode(value, _current_indent_level)
+ yield from chunks
+ except GeneratorExit:
+ raise
+ except BaseException as exc:
+ exc.add_note(f'when serializing {type(dct).__name__} item {key!r}')
+ raise
if newline_indent is not None:
_current_indent_level -= 1
yield '\n' + _indent * _current_indent_level
@@ -436,8 +445,14 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = o
- o = _default(o)
- yield from _iterencode(o, _current_indent_level)
+ newobj = _default(o)
+ try:
+ yield from _iterencode(newobj, _current_indent_level)
+ except GeneratorExit:
+ raise
+ except BaseException as exc:
+ exc.add_note(f'when serializing {type(o).__name__} object')
+ raise
if markers is not None:
del markers[markerid]
return _iterencode