Skip to content

Commit 3cee9ce

Browse files
author
Steven Silvester
authored
Merge pull request #708 from martinRenou/clean_json_clean
Make json_clean a no-op for jupyter-client >= 7
2 parents c810559 + a7aa5a0 commit 3cee9ce

File tree

5 files changed

+45
-13
lines changed

5 files changed

+45
-13
lines changed

ipykernel/datapub.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ def publish_data(data):
6666
DeprecationWarning,
6767
stacklevel=2
6868
)
69-
69+
7070
from ipykernel.zmqshell import ZMQInteractiveShell
7171
ZMQInteractiveShell.instance().data_pub.publish_data(data)

ipykernel/debugger.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@
77
from tornado.queues import Queue
88
from tornado.locks import Event
99

10-
from .compiler import (get_file_name, get_tmp_directory, get_tmp_hash_seed)
11-
1210
from IPython.core.getipython import get_ipython
1311

12+
try:
13+
from jupyter_client.jsonutil import json_default
14+
except ImportError:
15+
from jupyter_client.jsonutil import date_default as json_default
16+
17+
from .compiler import (get_file_name, get_tmp_directory, get_tmp_hash_seed)
18+
1419
# This import is required to have the next ones working...
1520
from debugpy.server import api # noqa
1621
from _pydevd_bundle import pydevd_frame_utils
@@ -170,7 +175,12 @@ def _forward_event(self, msg):
170175
def _send_request(self, msg):
171176
if self.routing_id is None:
172177
self.routing_id = self.debugpy_stream.socket.getsockopt(ROUTING_ID)
173-
content = jsonapi.dumps(msg)
178+
content = jsonapi.dumps(
179+
msg,
180+
default=json_default,
181+
ensure_ascii=False,
182+
allow_nan=False,
183+
)
174184
content_length = str(len(content))
175185
buf = (DebugpyMessageQueue.HEADER + content_length + DebugpyMessageQueue.SEPARATOR).encode('ascii')
176186
buf += content
@@ -240,6 +250,7 @@ async def send_dap_request(self, msg):
240250
self.log.debug(rep)
241251
return rep
242252

253+
243254
class Debugger:
244255

245256
# Requests that requires that the debugger has started

ipykernel/inprocess/ipkernel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ def _default_shell_class(self):
152152

153153
@default('stdout')
154154
def _default_stdout(self):
155-
return OutStream(self.session, self.iopub_thread, 'stdout',
155+
return OutStream(self.session, self.iopub_thread, 'stdout',
156156
watchfd=False)
157157

158158
@default('stderr')
159159
def _default_stderr(self):
160-
return OutStream(self.session, self.iopub_thread, 'stderr',
160+
return OutStream(self.session, self.iopub_thread, 'stderr',
161161
watchfd=False)
162162

163163
#-----------------------------------------------------------------------------

ipykernel/jsonutil.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import types
1010
from datetime import datetime
1111
import numbers
12+
from jupyter_client._version import version_info as jupyter_client_version
1213

1314
next_attr_name = '__next__'
1415

@@ -42,6 +43,9 @@
4243
# front of PDF base64-encoded
4344
PDF64 = b'JVBER'
4445

46+
JUPYTER_CLIENT_MAJOR_VERSION = jupyter_client_version[0]
47+
48+
4549
def encode_images(format_dict):
4650
"""b64-encodes images in a displaypub format dict
4751
@@ -68,7 +72,9 @@ def encode_images(format_dict):
6872

6973

7074
def json_clean(obj):
71-
"""Clean an object to ensure it's safe to encode in JSON.
75+
"""Deprecated, this is a no-op for jupyter-client>=7.
76+
77+
Clean an object to ensure it's safe to encode in JSON.
7278
7379
Atomic, immutable objects are returned unmodified. Sets and tuples are
7480
converted to lists, lists are copied and dicts are also copied.
@@ -89,6 +95,9 @@ def json_clean(obj):
8995
it simply sanitizes it so that there will be no encoding errors later.
9096
9197
"""
98+
if JUPYTER_CLIENT_MAJOR_VERSION >= 7:
99+
return obj
100+
92101
# types that are 'atomic' and ok in json as-is.
93102
atomic_ok = (str, type(None))
94103

@@ -110,10 +119,10 @@ def json_clean(obj):
110119
if math.isnan(obj) or math.isinf(obj):
111120
return repr(obj)
112121
return float(obj)
113-
122+
114123
if isinstance(obj, atomic_ok):
115124
return obj
116-
125+
117126
if isinstance(obj, bytes):
118127
# unanmbiguous binary data is base64-encoded
119128
# (this probably should have happened upstream)
@@ -142,6 +151,6 @@ def json_clean(obj):
142151
return out
143152
if isinstance(obj, datetime):
144153
return obj.strftime(ISO8601)
145-
154+
146155
# we don't understand it, it's probably an unserializable object
147156
raise ValueError("Can't clean for JSON: %r" % obj)

ipykernel/tests/test_jsonutil.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,28 @@
1111

1212
import pytest
1313

14+
from jupyter_client._version import version_info as jupyter_client_version
15+
1416
from .. import jsonutil
1517
from ..jsonutil import json_clean, encode_images
1618

19+
20+
JUPYTER_CLIENT_MAJOR_VERSION = jupyter_client_version[0]
21+
22+
1723
class MyInt(object):
1824
def __int__(self):
1925
return 389
2026
numbers.Integral.register(MyInt)
2127

28+
2229
class MyFloat(object):
2330
def __float__(self):
2431
return 3.14
2532
numbers.Real.register(MyFloat)
2633

2734

35+
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
2836
def test():
2937
# list of input/expected output. Use None for the expected output if it
3038
# can be the same as the input.
@@ -47,7 +55,7 @@ def test():
4755
(MyFloat(), 3.14),
4856
(MyInt(), 389)
4957
]
50-
58+
5159
for val, jval in pairs:
5260
if jval is None:
5361
jval = val
@@ -58,13 +66,14 @@ def test():
5866
json.loads(json.dumps(out))
5967

6068

69+
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
6170
def test_encode_images():
6271
# invalid data, but the header and footer are from real files
6372
pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82'
6473
jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9'
6574
pdfdata = b'%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>'
6675
bindata = b'\xff\xff\xff\xff'
67-
76+
6877
fmt = {
6978
'image/png' : pngdata,
7079
'image/jpeg' : jpegdata,
@@ -78,16 +87,18 @@ def test_encode_images():
7887
assert decoded == value
7988
encoded2 = json_clean(encode_images(encoded))
8089
assert encoded == encoded2
81-
90+
8291
for key, value in fmt.items():
8392
decoded = a2b_base64(encoded[key])
8493
assert decoded == value
8594

95+
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
8696
def test_lambda():
8797
with pytest.raises(ValueError):
8898
json_clean(lambda : 1)
8999

90100

101+
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
91102
def test_exception():
92103
bad_dicts = [{1:'number', '1':'string'},
93104
{True:'bool', 'True':'string'},
@@ -97,6 +108,7 @@ def test_exception():
97108
json_clean(d)
98109

99110

111+
@pytest.mark.skipif(JUPYTER_CLIENT_MAJOR_VERSION >= 7, reason="json_clean is a no-op")
100112
def test_unicode_dict():
101113
data = {'üniço∂e': 'üniço∂e'}
102114
clean = jsonutil.json_clean(data)

0 commit comments

Comments
 (0)