Source code for pykern.pkjson
# -*- coding: utf-8 -*-
"""JSON wrapper
:copyright: Copyright (c) 2017-2023 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
import json
#: how bytes are encoded
ENCODING = "utf-8"
#: MIME type
MIME_TYPE = "application/json"
#: Content-Type MIME header
CONTENT_TYPE = f'{MIME_TYPE}; charset="{ENCODING}"'
_JSON_INT_MAX = 2**53 - 1
_JSON_INT_MIN = -(2**53) + 1
[docs]
class Encoder(json.JSONEncoder):
[docs]
def default(self, obj):
# Return Python object, and JSONEncoder._iterencode will encode
return str(obj)
[docs]
def dump_bytes(obj, **kwargs):
"""Formats as json as bytes for network transfer
Args:
obj (object): any Python object
kwargs (object): other arguments to `dump_pretty`
Returns:
bytes: (unsorted) formatted JSON
"""
return dump_pretty(obj, pretty=False, **kwargs).encode(ENCODING)
[docs]
def dump_pretty(obj, filename=None, pretty=True, **kwargs):
"""Formats as json as string
If an object is not encoded by default, will call str() on the
object.
Args:
obj (object): any Python object
filename (str or py.path): where to write [None]
pretty (bool): pretty print [True]
kwargs (object): other arguments to `json.dumps`
Returns:
str: sorted and formatted JSON
"""
if pretty:
res = (
json.dumps(
obj,
indent=4,
separators=(",", ": "),
sort_keys=True,
cls=Encoder,
**kwargs,
)
+ "\n"
)
else:
res = json.dumps(obj, separators=(",", ":"), cls=Encoder, **kwargs)
if filename:
from pykern import pkio
pkio.write_text(filename, res)
return res
[docs]
def dump_str(obj, **kwargs):
"""Formats as a compact json as string
Args:
obj (object): any Python object
kwargs (object): other arguments to `dump_pretty`
Returns:
str: (unsorted) formatted JSON
"""
return dump_pretty(obj, pretty=False, **kwargs)
[docs]
def load_any(obj, *args, **kwargs):
"""Parse object containing json into dict-like object.
object_pairs_hook modifies the return type.
Args:
obj (object): str or object with "read" or py.path
args (tuple): passed verbatim to json.loads()
kwargs (dict): object_pairs_hook may be overriden
Returns:
object: parsed JSON
"""
from pykern import pkcollections
def _parse_int(value):
if len(value) > 64:
# 64 is pretty arbitrary, but reasonable in Python. Nothing in
# JSON can be this large.
raise ValueError(f"number={value:60s}... unreasonably large")
if len(value) > 17:
return float(value)
res = int(value)
if _JSON_INT_MIN <= res <= _JSON_INT_MAX:
return res
return float(res)
kwargs.setdefault("parse_int", _parse_int)
kwargs.setdefault("object_pairs_hook", pkcollections.object_pairs_hook)
return json.loads(obj.read() if hasattr(obj, "read") else obj, *args, **kwargs)