Skip to content

Commit f5df133

Browse files
committed
Override JSONEncoder.iterencode
We do this to handle NaN, Inf, and -Inf
1 parent ce0adcc commit f5df133

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

plotly/utils.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,72 @@ class PlotlyJSONEncoder(json.JSONEncoder):
119119
120120
See PlotlyJSONEncoder.default for more implementation information.
121121
122+
Additionally, this encoder overrides nan functionality so that 'Inf',
123+
'NaN' and '-Inf' encode to 'null'. Which is stricter JSON than the Python
124+
version.
125+
122126
"""
123127

128+
# we want stricter JSON, so convert NaN, Inf, -Inf --> 'null'
129+
nan_str = inf_str = neg_inf_str = 'null'
130+
131+
# uses code from official python json.encoder module. Same licence applies.
132+
def iterencode(self, o, _one_shot=False):
133+
"""
134+
Encode the given object and yield each string
135+
representation as available.
136+
137+
For example::
138+
139+
for chunk in JSONEncoder().iterencode(bigobject):
140+
mysocket.write(chunk)
141+
142+
"""
143+
if self.check_circular:
144+
markers = {}
145+
else:
146+
markers = None
147+
if self.ensure_ascii:
148+
_encoder = json.encoder.encode_basestring_ascii
149+
else:
150+
_encoder = json.encoder.encode_basestring
151+
if self.encoding != 'utf-8':
152+
def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
153+
if isinstance(o, str):
154+
o = o.decode(_encoding)
155+
return _orig_encoder(o)
156+
157+
def floatstr(o, allow_nan=self.allow_nan,
158+
_repr=json.encoder.FLOAT_REPR, _inf=json.encoder.INFINITY,
159+
_neginf=-json.encoder.INFINITY):
160+
# Check for specials. Note that this type of test is processor
161+
# and/or platform-specific, so do tests which don't depend on the
162+
# internals.
163+
164+
# *any* two NaNs are not equivalent (even to itself) try:
165+
# float('NaN') == float('NaN')
166+
if o != o:
167+
text = self.nan_str
168+
elif o == _inf:
169+
text = self.inf_str
170+
elif o == _neginf:
171+
text = self.neg_inf_str
172+
else:
173+
return _repr(o)
174+
175+
if not allow_nan:
176+
raise ValueError(
177+
"Out of range float values are not JSON compliant: " +
178+
repr(o))
179+
180+
return text
181+
182+
_iterencode = json.encoder._make_iterencode(
183+
markers, self.default, _encoder, self.indent, floatstr,
184+
self.key_separator, self.item_separator, self.sort_keys,
185+
self.skipkeys, _one_shot)
186+
return _iterencode(o, 0)
187+
124188
def default(self, obj):
125189
"""
126190
Accept an object (of unknown type) and try to encode with priority:

0 commit comments

Comments
 (0)