Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions ipykernel/comm/comm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import traitlets.config
from traitlets import Bool, Bytes, Instance, Unicode, default

from ipykernel.jsonutil import json_clean
from ipykernel.kernelbase import Kernel


Expand All @@ -28,7 +27,7 @@ def publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):

data = {} if data is None else data
metadata = {} if metadata is None else metadata
content = json_clean(dict(data=data, comm_id=self.comm_id, **keys))
content = dict(data=data, comm_id=self.comm_id, **keys)

if self.kernel is None:
self.kernel = Kernel.instance()
Expand All @@ -38,7 +37,7 @@ def publish_msg(self, msg_type, data=None, metadata=None, buffers=None, **keys):
self.kernel.iopub_socket,
msg_type,
content,
metadata=json_clean(metadata),
metadata=metadata,
parent=self.kernel.get_parent(),
ident=self.topic,
buffers=buffers,
Expand Down
4 changes: 2 additions & 2 deletions ipykernel/displayhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from jupyter_client.session import Session, extract_header
from traitlets import Any, Instance

from ipykernel.jsonutil import encode_images, json_clean
from ipykernel.jsonutil import encode_images


class ZMQDisplayHook:
Expand Down Expand Up @@ -120,7 +120,7 @@ def write_output_prompt(self):
def write_format_data(self, format_dict, md_dict=None):
"""Write format data to the message."""
if self.msg:
self.msg["content"]["data"] = json_clean(encode_images(format_dict))
self.msg["content"]["data"] = encode_images(format_dict)
self.msg["content"]["metadata"] = md_dict

def finish_displayhook(self):
Expand Down
3 changes: 1 addition & 2 deletions ipykernel/inprocess/ipkernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from traitlets import Any, Enum, Instance, List, Type, default

from ipykernel.ipkernel import IPythonKernel
from ipykernel.jsonutil import json_clean
from ipykernel.zmqshell import ZMQInteractiveShell

from ..iostream import BackgroundSocket, IOPubThread, OutStream
Expand Down Expand Up @@ -98,7 +97,7 @@ def _input_request(self, prompt, ident, parent, password=False):
sys.stderr.flush()

# Send the input request.
content = json_clean(dict(prompt=prompt, password=password))
content = dict(prompt=prompt, password=password)
assert self.session is not None
msg = self.session.msg("input_request", content, parent)
for frontend in self.frontends:
Expand Down
97 changes: 1 addition & 96 deletions ipykernel/jsonutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.

import math
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused imports

import numbers
import re
import types
from binascii import b2a_base64
from datetime import date, datetime
from datetime import datetime

from jupyter_client._version import version_info as jupyter_client_version

Expand Down Expand Up @@ -52,8 +48,6 @@
def encode_images(format_dict):
"""b64-encodes images in a displaypub format dict

Perhaps this should be handled in json_clean itself?

Parameters
----------
format_dict : dict
Expand All @@ -72,92 +66,3 @@ def encode_images(format_dict):
# where bytes objects always represent binary data and thus
# base64-encoded.
return format_dict


def json_clean(obj): # pragma: no cover
"""Deprecated, this is a no-op for jupyter-client>=7.

Clean an object to ensure it's safe to encode in JSON.

Atomic, immutable objects are returned unmodified. Sets and tuples are
converted to lists, lists are copied and dicts are also copied.

Note: dicts whose keys could cause collisions upon encoding (such as a dict
with both the number 1 and the string '1' as keys) will cause a ValueError
to be raised.

Parameters
----------
obj : any python object

Returns
-------
out : object
A version of the input which will not cause an encoding error when
encoded as JSON. Note that this function does not *encode* its inputs,
it simply sanitizes it so that there will be no encoding errors later.

"""
if int(JUPYTER_CLIENT_MAJOR_VERSION) >= 7:
return obj

# types that are 'atomic' and ok in json as-is.
atomic_ok = (str, type(None))

# containers that we need to convert into lists
container_to_list = (tuple, set, types.GeneratorType)

# Since bools are a subtype of Integrals, which are a subtype of Reals,
# we have to check them in that order.

if isinstance(obj, bool):
return obj

if isinstance(obj, numbers.Integral):
# cast int to int, in case subclasses override __str__ (e.g. boost enum, #4598)
return int(obj)

if isinstance(obj, numbers.Real):
# cast out-of-range floats to their reprs
if math.isnan(obj) or math.isinf(obj):
return repr(obj)
return float(obj)

if isinstance(obj, atomic_ok):
return obj

if isinstance(obj, bytes):
# unanmbiguous binary data is base64-encoded
# (this probably should have happened upstream)
return b2a_base64(obj).decode("ascii")

if isinstance(obj, container_to_list) or (
hasattr(obj, "__iter__") and hasattr(obj, next_attr_name)
):
obj = list(obj)

if isinstance(obj, list):
return [json_clean(x) for x in obj]

if isinstance(obj, dict):
# First, validate that the dict won't lose data in conversion due to
# key collisions after stringification. This can happen with keys like
# True and 'true' or 1 and '1', which collide in JSON.
nkeys = len(obj)
nkeys_collapsed = len(set(map(str, obj)))
if nkeys != nkeys_collapsed:
msg = (
"dict cannot be safely converted to JSON: "
"key collision would lead to dropped values"
)
raise ValueError(msg)
# If all OK, proceed by making the new dict that will be json-safe
out = {}
for k, v in obj.items():
out[str(k)] = json_clean(v)
return out
if isinstance(obj, datetime | date):
return obj.strftime(ISO8601)

# we don't understand it, it's probably an unserializable object
raise ValueError("Can't clean for JSON: %r" % obj)
10 changes: 1 addition & 9 deletions ipykernel/kernelbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@
)
from zmq.eventloop.zmqstream import ZMQStream

from ipykernel.jsonutil import json_clean

from ._version import kernel_protocol_version
from .iostream import OutStream
from .utils import LazyDict, _async_in_context
Expand Down Expand Up @@ -851,7 +849,6 @@ async def execute_request(self, stream, ident, parent):
time.sleep(self._execute_sleep)

# Send the reply.
reply_content = json_clean(reply_content)
metadata = self.finish_metadata(parent, metadata, reply_content)

reply_msg: dict[str, t.Any] = self.session.send( # type:ignore[assignment]
Expand Down Expand Up @@ -901,7 +898,6 @@ async def complete_request(self, stream, ident, parent):
stacklevel=1,
)

matches = json_clean(matches)
self.session.send(stream, "complete_reply", matches, parent, ident)

async def do_complete(self, code, cursor_pos):
Expand Down Expand Up @@ -936,7 +932,6 @@ async def inspect_request(self, stream, ident, parent):
)

# Before we send this object over, we scrub it for JSON usage
reply_content = json_clean(reply_content)
msg = self.session.send(stream, "inspect_reply", reply_content, parent, ident)
self.log.debug("%s", msg)

Expand All @@ -960,7 +955,6 @@ async def history_request(self, stream, ident, parent):
stacklevel=1,
)

reply_content = json_clean(reply_content)
msg = self.session.send(stream, "history_reply", reply_content, parent, ident)
self.log.debug("%s", msg)

Expand Down Expand Up @@ -1126,7 +1120,6 @@ async def is_complete_request(self, stream, ident, parent):
PendingDeprecationWarning,
stacklevel=1,
)
reply_content = json_clean(reply_content)
reply_msg = self.session.send(stream, "is_complete_reply", reply_content, parent, ident)
self.log.debug("%s", reply_msg)

Expand All @@ -1150,7 +1143,6 @@ async def debug_request(self, stream, ident, parent):
PendingDeprecationWarning,
stacklevel=1,
)
reply_content = json_clean(reply_content)
reply_msg = self.session.send(stream, "debug_reply", reply_content, parent, ident)
self.log.debug("%s", reply_msg)

Expand Down Expand Up @@ -1425,7 +1417,7 @@ def _input_request(self, prompt, ident, parent, password=False):

# Send the input request.
assert self.session is not None
content = json_clean(dict(prompt=prompt, password=password))
content = dict(prompt=prompt, password=password)
self.session.send(self.stdin_socket, "input_request", content, parent, ident=ident)

# Await a response.
Expand Down
8 changes: 4 additions & 4 deletions ipykernel/zmqshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

from ipykernel import connect_qtconsole, get_connection_file, get_connection_info
from ipykernel.displayhook import ZMQShellDisplayHook
from ipykernel.jsonutil import encode_images, json_clean
from ipykernel.jsonutil import encode_images

try:
from IPython.core.history import HistoryOutput
Expand Down Expand Up @@ -164,7 +164,7 @@ def publish( # type:ignore[override]
# in order to put it through the transform
# hooks before potentially sending.
assert self.session is not None
msg = self.session.msg(msg_type, json_clean(content), parent=self.parent_header)
msg = self.session.msg(msg_type, content, parent=self.parent_header)

# Each transform either returns a new
# message or None. If None is returned,
Expand Down Expand Up @@ -194,7 +194,7 @@ def clear_output(self, wait=False):
content = dict(wait=wait)
self._flush_streams()
assert self.session is not None
msg = self.session.msg("clear_output", json_clean(content), parent=self.parent_header)
msg = self.session.msg("clear_output", content, parent=self.parent_header)

# see publish() for details on how this works
for hook in self._hooks:
Expand Down Expand Up @@ -684,7 +684,7 @@ def _showtraceback(self, etype, evalue, stb):
dh.session.send( # type:ignore[attr-defined]
dh.pub_socket, # type:ignore[attr-defined]
"error",
json_clean(exc_content),
exc_content,
dh.parent_header, # type:ignore[attr-defined]
ident=topic,
)
Expand Down
120 changes: 0 additions & 120 deletions tests/test_jsonutil.py

This file was deleted.

Loading