sapling/eden/scm/edenscm/mercurial/json.py
Durham Goode f918387338 py3: fix graphql producing unicode blobs in python 2
Summary:
As part of the py3 migration we've started enforcing that encodeutf8 is
only called on bytes. graphql is returning unicode, so we need to change it to
return bytes on python 2.

Reviewed By: xavierd

Differential Revision: D19819701

fbshipit-source-id: 433ced2da87d522e4234ff453d11cacfaeebdd8d
2020-02-11 09:38:55 -08:00

92 lines
2.7 KiB
Python

# Portions Copyright (c) Facebook, Inc. and its affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
# json.py - json encoding
#
# Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import json as _sysjson
import sys
from edenscm.mercurial import encoding, error, pycompat, util
try:
# pyre-fixme[18]: Global name `long` is undefined.
long
except NameError:
long = int
def dumps(obj, paranoid=True):
if obj is None:
return "null"
elif obj is False:
return "false"
elif obj is True:
return "true"
elif isinstance(obj, (int, long, float)):
return pycompat.bytestr(obj)
elif isinstance(obj, bytes):
return '"%s"' % encoding.jsonescape(obj, paranoid=paranoid)
elif isinstance(obj, str):
return _sysjson.dumps(obj)
elif util.safehasattr(obj, "keys"):
out = []
for k, v in sorted(pycompat.iteritems(obj)):
if isinstance(k, bytes):
key = '"%s"' % encoding.jsonescape(k, paranoid=paranoid)
else:
key = _sysjson.dumps(k)
out.append(key + ": %s" % dumps(v, paranoid))
return "{" + ", ".join(out) + "}"
elif util.safehasattr(obj, "__iter__"):
out = [dumps(i, paranoid) for i in obj]
return "[" + ", ".join(out) + "]"
else:
raise TypeError("cannot encode type %s" % obj.__class__.__name__)
def _rapply(f, xs):
if xs is None:
# assume None means non-value of optional data
return xs
if isinstance(xs, (list, set, tuple)):
return type(xs)(_rapply(f, x) for x in xs)
if isinstance(xs, dict):
return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
return f(xs)
def load(fp):
if sys.version_info[0] < 3:
return loads(fp.read())
else:
return _sysjson.load(fp)
def loads(string):
"""Like stdlib json.loads, but results are bytes instead of unicode
Warning: this does not round-trip with "dumps". "dumps" supports non-utf8
binary content that is unsupported by this function.
"""
if sys.version_info[0] < 3:
# XXX: This should round-trip with "dumps". But it might be non-trivial to
# do so.
def encode(s):
if isinstance(s, type(u"")):
return pycompat.decodeutf8(s.encode("utf-8"))
else:
return s
return _rapply(encode, _sysjson.loads(string))
else:
return _sysjson.loads(string)