Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/nbclient/jsonutil.py: 38%
50 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
1"""Utilities to manipulate JSON objects."""
3# NOTE: this is a copy of ipykernel/jsonutils.py (+blackified)
5# Copyright (c) IPython Development Team.
6# Distributed under the terms of the Modified BSD License.
8import math
9import numbers
10import re
11import types
12from binascii import b2a_base64
13from datetime import datetime
14from typing import Dict
16# -----------------------------------------------------------------------------
17# Globals and constants
18# -----------------------------------------------------------------------------
20# timestamp formats
21ISO8601 = "%Y-%m-%dT%H:%M:%S.%f"
22ISO8601_PAT = re.compile(
23 r"^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(\.\d{1,6})?Z?([\+\-]\d{2}:?\d{2})?$"
24)
26# holy crap, strptime is not threadsafe.
27# Calling it once at import seems to help.
28datetime.strptime("1", "%d")
30# -----------------------------------------------------------------------------
31# Classes and functions
32# -----------------------------------------------------------------------------
35# constants for identifying png/jpeg data
36PNG = b'\x89PNG\r\n\x1a\n'
37# front of PNG base64-encoded
38PNG64 = b'iVBORw0KG'
39JPEG = b'\xff\xd8'
40# front of JPEG base64-encoded
41JPEG64 = b'/9'
42# constants for identifying gif data
43GIF_64 = b'R0lGODdh'
44GIF89_64 = b'R0lGODlh'
45# front of PDF base64-encoded
46PDF64 = b'JVBER'
49def encode_images(format_dict: Dict) -> Dict[str, str]:
50 """b64-encodes images in a displaypub format dict
52 Perhaps this should be handled in json_clean itself?
54 Parameters
55 ----------
57 format_dict : dict
58 A dictionary of display data keyed by mime-type
60 Returns
61 -------
63 format_dict : dict
64 A copy of the same dictionary,
65 but binary image data ('image/png', 'image/jpeg' or 'application/pdf')
66 is base64-encoded.
68 """
69 return format_dict
72def json_clean(obj):
73 """Clean an object to ensure it's safe to encode in JSON.
75 Atomic, immutable objects are returned unmodified. Sets and tuples are
76 converted to lists, lists are copied and dicts are also copied.
78 Note: dicts whose keys could cause collisions upon encoding (such as a dict
79 with both the number 1 and the string '1' as keys) will cause a ValueError
80 to be raised.
82 Parameters
83 ----------
84 obj : any python object
86 Returns
87 -------
88 out : object
90 A version of the input which will not cause an encoding error when
91 encoded as JSON. Note that this function does not *encode* its inputs,
92 it simply sanitizes it so that there will be no encoding errors later.
94 """
95 # types that are 'atomic' and ok in json as-is.
96 atomic_ok = (str, type(None))
98 # containers that we need to convert into lists
99 container_to_list = (tuple, set, types.GeneratorType)
101 # Since bools are a subtype of Integrals, which are a subtype of Reals,
102 # we have to check them in that order.
104 if isinstance(obj, bool):
105 return obj
107 if isinstance(obj, numbers.Integral):
108 # cast int to int, in case subclasses override __str__ (e.g. boost enum, #4598)
109 return int(obj)
111 if isinstance(obj, numbers.Real):
112 # cast out-of-range floats to their reprs
113 if math.isnan(obj) or math.isinf(obj):
114 return repr(obj)
115 return float(obj)
117 if isinstance(obj, atomic_ok):
118 return obj
120 if isinstance(obj, bytes):
121 return b2a_base64(obj).decode('ascii')
123 if isinstance(obj, container_to_list) or (
124 hasattr(obj, '__iter__') and hasattr(obj, '__next__')
125 ):
126 obj = list(obj)
128 if isinstance(obj, list):
129 return [json_clean(x) for x in obj]
131 if isinstance(obj, dict):
132 # First, validate that the dict won't lose data in conversion due to
133 # key collisions after stringification. This can happen with keys like
134 # True and 'true' or 1 and '1', which collide in JSON.
135 nkeys = len(obj)
136 nkeys_collapsed = len(set(map(str, obj)))
137 if nkeys != nkeys_collapsed:
138 raise ValueError(
139 'dict cannot be safely converted to JSON: '
140 'key collision would lead to dropped values'
141 )
142 # If all OK, proceed by making the new dict that will be json-safe
143 out = {}
144 for k, v in iter(obj.items()):
145 out[str(k)] = json_clean(v)
146 return out
147 if isinstance(obj, datetime):
148 return obj.strftime(ISO8601)
150 # we don't understand it, it's probably an unserializable object
151 raise ValueError("Can't clean for JSON: %r" % obj)