51 changed files with 7819 additions and 0 deletions
@ -0,0 +1,23 @@
|
||||
#
|
||||
# Project: speedtest-cli
|
||||
# Created by George "walkero" Sokianos
|
||||
# 2022-07-31
|
||||
#
|
||||
|
||||
release: clean |
||||
mkdir -p release/speedtest-cli
|
||||
cp -r release_files/* release/speedtest-cli/
|
||||
cp speedtest.py release/speedtest-cli/speedtest-cli
|
||||
protect release/speedtest-cli/speedtest-cli srwed
|
||||
cp -r simplejson release/speedtest-cli/
|
||||
rm -rf release/speedtest-cli/simplejson/tests
|
||||
cp README-OS4.md release/speedtest-cli/
|
||||
cp README.rst release/speedtest-cli/
|
||||
cp LICENSE release/speedtest-cli/
|
||||
cp release_files/Icons/cha05e90/speedtest-cli.info release/speedtest-cli.info
|
||||
lha -aeqr3 a speedtest-cli.lha release/
|
||||
rm -rf release
|
||||
|
||||
clean: |
||||
rm -f simplejson/#?.pyc
|
||||
|
@ -0,0 +1,24 @@
|
||||
speedtest-cli |
||||
--------------------------------------------------------------------------- |
||||
|
||||
This is a simple terminal script that uses speedtest.net API. This is |
||||
based on Python, so it should work on any operating system supporting |
||||
Python v2.4 and above. This is created by Matt Martz and can be found |
||||
at his GitHub repository at https://github.com/sivel/speedtest-cli |
||||
|
||||
I adapted it to work with AmigaOS 4. To use it just double click its |
||||
icon and a new shell window will open. Automatically a close server |
||||
will be chosen and it will measure the download and upload speed of |
||||
your system. |
||||
|
||||
More parameters are available for the script and you can find them |
||||
in the included document README.rst. |
||||
|
||||
The icons are designed by Frank Ruthe and can be found at |
||||
http://os4depot.net/?function=showfile&file=graphics/icon/cha05e90_icons_2012.lha |
||||
|
||||
Changelog |
||||
-------------------------- |
||||
v2.1.3r1 - 2022-07-31 |
||||
* First release |
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,577 @@
|
||||
r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of |
||||
JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data |
||||
interchange format. |
||||
|
||||
:mod:`simplejson` exposes an API familiar to users of the standard library |
||||
:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained |
||||
version of the :mod:`json` library contained in Python 2.6, but maintains |
||||
compatibility back to Python 2.5 and (currently) has significant performance |
||||
advantages, even without using the optional C extension for speedups. |
||||
|
||||
Encoding basic Python object hierarchies:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) |
||||
'["foo", {"bar": ["baz", null, 1.0, 2]}]' |
||||
>>> print(json.dumps("\"foo\bar")) |
||||
"\"foo\bar" |
||||
>>> print(json.dumps(u'\u1234')) |
||||
"\u1234" |
||||
>>> print(json.dumps('\\')) |
||||
"\\" |
||||
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)) |
||||
{"a": 0, "b": 0, "c": 0} |
||||
>>> from simplejson.compat import StringIO |
||||
>>> io = StringIO() |
||||
>>> json.dump(['streaming API'], io) |
||||
>>> io.getvalue() |
||||
'["streaming API"]' |
||||
|
||||
Compact encoding:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> obj = [1,2,3,{'4': 5, '6': 7}] |
||||
>>> json.dumps(obj, separators=(',',':'), sort_keys=True) |
||||
'[1,2,3,{"4":5,"6":7}]' |
||||
|
||||
Pretty printing:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ')) |
||||
{ |
||||
"4": 5, |
||||
"6": 7 |
||||
} |
||||
|
||||
Decoding JSON:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] |
||||
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj |
||||
True |
||||
>>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' |
||||
True |
||||
>>> from simplejson.compat import StringIO |
||||
>>> io = StringIO('["streaming API"]') |
||||
>>> json.load(io)[0] == 'streaming API' |
||||
True |
||||
|
||||
Specializing JSON object decoding:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> def as_complex(dct): |
||||
... if '__complex__' in dct: |
||||
... return complex(dct['real'], dct['imag']) |
||||
... return dct |
||||
... |
||||
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', |
||||
... object_hook=as_complex) |
||||
(1+2j) |
||||
>>> from decimal import Decimal |
||||
>>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1') |
||||
True |
||||
|
||||
Specializing JSON object encoding:: |
||||
|
||||
>>> import simplejson as json |
||||
>>> def encode_complex(obj): |
||||
... if isinstance(obj, complex): |
||||
... return [obj.real, obj.imag] |
||||
... raise TypeError('Object of type %s is not JSON serializable' % |
||||
... obj.__class__.__name__) |
||||
... |
||||
>>> json.dumps(2 + 1j, default=encode_complex) |
||||
'[2.0, 1.0]' |
||||
>>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) |
||||
'[2.0, 1.0]' |
||||
>>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) |
||||
'[2.0, 1.0]' |
||||
|
||||
|
||||
Using simplejson.tool from the shell to validate and pretty-print:: |
||||
|
||||
$ echo '{"json":"obj"}' | python -m simplejson.tool |
||||
{ |
||||
"json": "obj" |
||||
} |
||||
$ echo '{ 1.2:3.4}' | python -m simplejson.tool |
||||
Expecting property name: line 1 column 3 (char 2) |
||||
""" |
||||
from __future__ import absolute_import |
||||
__version__ = '3.16.0' |
||||
__all__ = [ |
||||
'dump', 'dumps', 'load', 'loads', |
||||
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', |
||||
'OrderedDict', 'simple_first', 'RawJSON' |
||||
] |
||||
|
||||
__author__ = 'Bob Ippolito <bob@redivi.com>' |
||||
|
||||
from decimal import Decimal |
||||
|
||||
from .errors import JSONDecodeError |
||||
from .raw_json import RawJSON |
||||
from .decoder import JSONDecoder |
||||
from .encoder import JSONEncoder, JSONEncoderForHTML |
||||
def _import_OrderedDict(): |
||||
import collections |
||||
try: |
||||
return collections.OrderedDict |
||||
except AttributeError: |
||||
from . import ordered_dict |
||||
return ordered_dict.OrderedDict |
||||
OrderedDict = _import_OrderedDict() |
||||
|
||||
def _import_c_make_encoder(): |
||||
try: |
||||
from ._speedups import make_encoder |
||||
return make_encoder |
||||
except ImportError: |
||||
return None |
||||
|
||||
_default_encoder = JSONEncoder( |
||||
skipkeys=False, |
||||
ensure_ascii=True, |
||||
check_circular=True, |
||||
allow_nan=True, |
||||
indent=None, |
||||
separators=None, |
||||
encoding='utf-8', |
||||
default=None, |
||||
use_decimal=True, |
||||
namedtuple_as_object=True, |
||||
tuple_as_array=True, |
||||
iterable_as_array=False, |
||||
bigint_as_string=False, |
||||
item_sort_key=None, |
||||
for_json=False, |
||||
ignore_nan=False, |
||||
int_as_string_bitcount=None, |
||||
) |
||||
|
||||
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, |
||||
allow_nan=True, cls=None, indent=None, separators=None, |
||||
encoding='utf-8', default=None, use_decimal=True, |
||||
namedtuple_as_object=True, tuple_as_array=True, |
||||
bigint_as_string=False, sort_keys=False, item_sort_key=None, |
||||
for_json=False, ignore_nan=False, int_as_string_bitcount=None, |
||||
iterable_as_array=False, **kw): |
||||
"""Serialize ``obj`` as a JSON formatted stream to ``fp`` (a |
||||
``.write()``-supporting file-like object). |
||||
|
||||
If *skipkeys* is true then ``dict`` keys that are not basic types |
||||
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) |
||||
will be skipped instead of raising a ``TypeError``. |
||||
|
||||
If *ensure_ascii* is false, then the some chunks written to ``fp`` |
||||
may be ``unicode`` instances, subject to normal Python ``str`` to |
||||
``unicode`` coercion rules. Unless ``fp.write()`` explicitly |
||||
understands ``unicode`` (as in ``codecs.getwriter()``) this is likely |
||||
to cause an error. |
||||
|
||||
If *check_circular* is false, then the circular reference check |
||||
for container types will be skipped and a circular reference will |
||||
result in an ``OverflowError`` (or worse). |
||||
|
||||
If *allow_nan* is false, then it will be a ``ValueError`` to |
||||
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) |
||||
in strict compliance of the original JSON specification, instead of using |
||||
the JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). See |
||||
*ignore_nan* for ECMA-262 compliant behavior. |
||||
|
||||
If *indent* is a string, then JSON array elements and object members |
||||
will be pretty-printed with a newline followed by that string repeated |
||||
for each level of nesting. ``None`` (the default) selects the most compact |
||||
representation without any newlines. For backwards compatibility with |
||||
versions of simplejson earlier than 2.1.0, an integer is also accepted |
||||
and is converted to a string with that many spaces. |
||||
|
||||
If specified, *separators* should be an |
||||
``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')`` |
||||
if *indent* is ``None`` and ``(',', ': ')`` otherwise. To get the most |
||||
compact JSON representation, you should specify ``(',', ':')`` to eliminate |
||||
whitespace. |
||||
|
||||
*encoding* is the character encoding for str instances, default is UTF-8. |
||||
|
||||
*default(obj)* is a function that should return a serializable version |
||||
of obj or raise ``TypeError``. The default simply raises ``TypeError``. |
||||
|
||||
If *use_decimal* is true (default: ``True``) then decimal.Decimal |
||||
will be natively serialized to JSON with full precision. |
||||
|
||||
If *namedtuple_as_object* is true (default: ``True``), |
||||
:class:`tuple` subclasses with ``_asdict()`` methods will be encoded |
||||
as JSON objects. |
||||
|
||||
If *tuple_as_array* is true (default: ``True``), |
||||
:class:`tuple` (and subclasses) will be encoded as JSON arrays. |
||||
|
||||
If *iterable_as_array* is true (default: ``False``), |
||||
any object not in the above table that implements ``__iter__()`` |
||||
will be encoded as a JSON array. |
||||
|
||||
If *bigint_as_string* is true (default: ``False``), ints 2**53 and higher |
||||
or lower than -2**53 will be encoded as strings. This is to avoid the |
||||
rounding that happens in Javascript otherwise. Note that this is still a |
||||
lossy operation that will not round-trip correctly and should be used |
||||
sparingly. |
||||
|
||||
If *int_as_string_bitcount* is a positive number (n), then int of size |
||||
greater than or equal to 2**n or lower than or equal to -2**n will be |
||||
encoded as strings. |
||||
|
||||
If specified, *item_sort_key* is a callable used to sort the items in |
||||
each dictionary. This is useful if you want to sort items other than |
||||
in alphabetical order by key. This option takes precedence over |
||||
*sort_keys*. |
||||
|
||||
If *sort_keys* is true (default: ``False``), the output of dictionaries |
||||
will be sorted by item. |
||||
|
||||
If *for_json* is true (default: ``False``), objects with a ``for_json()`` |
||||
method will use the return value of that method for encoding as JSON |
||||
instead of the object. |
||||
|
||||
If *ignore_nan* is true (default: ``False``), then out of range |
||||
:class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized as |
||||
``null`` in compliance with the ECMA-262 specification. If true, this will |
||||
override *allow_nan*. |
||||
|
||||
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the |
||||
``.default()`` method to serialize additional types), specify it with |
||||
the ``cls`` kwarg. NOTE: You should use *default* or *for_json* instead |
||||
of subclassing whenever possible. |
||||
|
||||
""" |
||||
# cached encoder |
||||
if (not skipkeys and ensure_ascii and |
||||
check_circular and allow_nan and |
||||
cls is None and indent is None and separators is None and |
||||
encoding == 'utf-8' and default is None and use_decimal |
||||
and namedtuple_as_object and tuple_as_array and not iterable_as_array |
||||
and not bigint_as_string and not sort_keys |
||||
and not item_sort_key and not for_json |
||||
and not ignore_nan and int_as_string_bitcount is None |
||||
and not kw |
||||
): |
||||
iterable = _default_encoder.iterencode(obj) |
||||
else: |
||||
if cls is None: |
||||
cls = JSONEncoder |
||||
iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, |
||||
check_circular=check_circular, allow_nan=allow_nan, indent=indent, |
||||
separators=separators, encoding=encoding, |
||||
default=default, use_decimal=use_decimal, |
||||
namedtuple_as_object=namedtuple_as_object, |
||||
tuple_as_array=tuple_as_array, |
||||
iterable_as_array=iterable_as_array, |
||||
bigint_as_string=bigint_as_string, |
||||
sort_keys=sort_keys, |
||||
item_sort_key=item_sort_key, |
||||
for_json=for_json, |
||||
ignore_nan=ignore_nan, |
||||
int_as_string_bitcount=int_as_string_bitcount, |
||||
**kw).iterencode(obj) |
||||
# could accelerate with writelines in some versions of Python, at |
||||
# a debuggability cost |
||||
for chunk in iterable: |
||||
fp.write(chunk) |
||||
|
||||
|
||||
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, |
||||
allow_nan=True, cls=None, indent=None, separators=None, |
||||
encoding='utf-8', default=None, use_decimal=True, |
||||
namedtuple_as_object=True, tuple_as_array=True, |
||||
bigint_as_string=False, sort_keys=False, item_sort_key=None, |
||||
for_json=False, ignore_nan=False, int_as_string_bitcount=None, |
||||
iterable_as_array=False, **kw): |
||||
"""Serialize ``obj`` to a JSON formatted ``str``. |
||||
|
||||
If ``skipkeys`` is false then ``dict`` keys that are not basic types |
||||
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) |
||||
will be skipped instead of raising a ``TypeError``. |
||||
|
||||
If ``ensure_ascii`` is false, then the return value will be a |
||||
``unicode`` instance subject to normal Python ``str`` to ``unicode`` |
||||
coercion rules instead of being escaped to an ASCII ``str``. |
||||
|
||||
If ``check_circular`` is false, then the circular reference check |
||||
for container types will be skipped and a circular reference will |
||||
result in an ``OverflowError`` (or worse). |
||||
|
||||
If ``allow_nan`` is false, then it will be a ``ValueError`` to |
||||
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in |
||||
strict compliance of the JSON specification, instead of using the |
||||
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). |
||||
|
||||
If ``indent`` is a string, then JSON array elements and object members |
||||
will be pretty-printed with a newline followed by that string repeated |
||||
for each level of nesting. ``None`` (the default) selects the most compact |
||||
representation without any newlines. For backwards compatibility with |
||||
versions of simplejson earlier than 2.1.0, an integer is also accepted |
||||
and is converted to a string with that many spaces. |
||||
|
||||
If specified, ``separators`` should be an |
||||
``(item_separator, key_separator)`` tuple. The default is ``(', ', ': ')`` |
||||
if *indent* is ``None`` and ``(',', ': ')`` otherwise. To get the most |
||||
compact JSON representation, you should specify ``(',', ':')`` to eliminate |
||||
whitespace. |
||||
|
||||
``encoding`` is the character encoding for str instances, default is UTF-8. |
||||
|
||||
``default(obj)`` is a function that should return a serializable version |
||||
of obj or raise TypeError. The default simply raises TypeError. |
||||
|
||||
If *use_decimal* is true (default: ``True``) then decimal.Decimal |
||||
will be natively serialized to JSON with full precision. |
||||
|
||||
If *namedtuple_as_object* is true (default: ``True``), |
||||
:class:`tuple` subclasses with ``_asdict()`` methods will be encoded |
||||
as JSON objects. |
||||
|
||||
If *tuple_as_array* is true (default: ``True``), |
||||
:class:`tuple` (and subclasses) will be encoded as JSON arrays. |
||||
|
||||
If *iterable_as_array* is true (default: ``False``), |
||||
any object not in the above table that implements ``__iter__()`` |
||||
will be encoded as a JSON array. |
||||
|
||||
If *bigint_as_string* is true (not the default), ints 2**53 and higher |
||||
or lower than -2**53 will be encoded as strings. This is to avoid the |
||||
rounding that happens in Javascript otherwise. |
||||
|
||||
If *int_as_string_bitcount* is a positive number (n), then int of size |
||||
greater than or equal to 2**n or lower than or equal to -2**n will be |
||||
encoded as strings. |
||||
|
||||
If specified, *item_sort_key* is a callable used to sort the items in |
||||
each dictionary. This is useful if you want to sort items other than |
||||
in alphabetical order by key. This option takes precendence over |
||||
*sort_keys*. |
||||
|
||||
If *sort_keys* is true (default: ``False``), the output of dictionaries |
||||
will be sorted by item. |
||||
|
||||
If *for_json* is true (default: ``False``), objects with a ``for_json()`` |
||||
method will use the return value of that method for encoding as JSON |
||||
instead of the object. |
||||
|
||||
If *ignore_nan* is true (default: ``False``), then out of range |
||||
:class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized as |
||||
``null`` in compliance with the ECMA-262 specification. If true, this will |
||||
override *allow_nan*. |
||||
|
||||
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the |
||||
``.default()`` method to serialize additional types), specify it with |
||||
the ``cls`` kwarg. NOTE: You should use *default* instead of subclassing |
||||
whenever possible. |
||||
|
||||
""" |
||||
# cached encoder |
||||
if (not skipkeys and ensure_ascii and |
||||
check_circular and allow_nan and |
||||
cls is None and indent is None and separators is None and |
||||
encoding == 'utf-8' and default is None and use_decimal |
||||
and namedtuple_as_object and tuple_as_array and not iterable_as_array |
||||
and not bigint_as_string and not sort_keys |
||||
and not item_sort_key and not for_json |
||||
and not ignore_nan and int_as_string_bitcount is None |
||||
and not kw |
||||
): |
||||
return _default_encoder.encode(obj) |
||||
if cls is None: |
||||
cls = JSONEncoder |
||||
return cls( |
||||
skipkeys=skipkeys, ensure_ascii=ensure_ascii, |
||||
check_circular=check_circular, allow_nan=allow_nan, indent=indent, |
||||
separators=separators, encoding=encoding, default=default, |
||||
use_decimal=use_decimal, |
||||
namedtuple_as_object=namedtuple_as_object, |
||||
tuple_as_array=tuple_as_array, |
||||
iterable_as_array=iterable_as_array, |
||||
bigint_as_string=bigint_as_string, |
||||
sort_keys=sort_keys, |
||||
item_sort_key=item_sort_key, |
||||
for_json=for_json, |
||||
ignore_nan=ignore_nan, |
||||
int_as_string_bitcount=int_as_string_bitcount, |
||||
**kw).encode(obj) |
||||
|
||||
|
||||
_default_decoder = JSONDecoder(encoding=None, object_hook=None, |
||||
object_pairs_hook=None) |
||||
|
||||
|
||||
def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, |
||||
parse_int=None, parse_constant=None, object_pairs_hook=None, |
||||
use_decimal=False, namedtuple_as_object=True, tuple_as_array=True, |
||||
**kw): |
||||
"""Deserialize ``fp`` (a ``.read()``-supporting file-like object containing |
||||
a JSON document) to a Python object. |
||||
|
||||
*encoding* determines the encoding used to interpret any |
||||
:class:`str` objects decoded by this instance (``'utf-8'`` by |
||||
default). It has no effect when decoding :class:`unicode` objects. |
||||
|
||||
Note that currently only encodings that are a superset of ASCII work, |
||||
strings of other encodings should be passed in as :class:`unicode`. |
||||
|
||||
*object_hook*, if specified, will be called with the result of every |
||||
JSON object decoded and its return value will be used in place of the |
||||
given :class:`dict`. This can be used to provide custom |
||||
deserializations (e.g. to support JSON-RPC class hinting). |
||||
|
||||
*object_pairs_hook* is an optional function that will be called with |
||||
the result of any object literal decode with an ordered list of pairs. |
||||
The return value of *object_pairs_hook* will be used instead of the |
||||
:class:`dict`. This feature can be used to implement custom decoders |
||||
that rely on the order that the key and value pairs are decoded (for |
||||
example, :func:`collections.OrderedDict` will remember the order of |
||||
insertion). If *object_hook* is also defined, the *object_pairs_hook* |
||||
takes priority. |
||||
|
||||
*parse_float*, if specified, will be called with the string of every |
||||
JSON float to be decoded. By default, this is equivalent to |
||||
``float(num_str)``. This can be used to use another datatype or parser |
||||
for JSON floats (e.g. :class:`decimal.Decimal`). |
||||
|
||||
*parse_int*, if specified, will be called with the string of every |
||||
JSON int to be decoded. By default, this is equivalent to |
||||
``int(num_str)``. This can be used to use another datatype or parser |
||||
for JSON integers (e.g. :class:`float`). |
||||
|
||||
*parse_constant*, if specified, will be called with one of the |
||||
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This |
||||
can be used to raise an exception if invalid JSON numbers are |
||||
encountered. |
||||
|
||||
If *use_decimal* is true (default: ``False``) then it implies |
||||
parse_float=decimal.Decimal for parity with ``dump``. |
||||
|
||||
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` |
||||
kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead |
||||
of subclassing whenever possible. |
||||
|
||||
""" |
||||
return loads(fp.read(), |
||||
encoding=encoding, cls=cls, object_hook=object_hook, |
||||
parse_float=parse_float, parse_int=parse_int, |
||||
parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, |
||||
use_decimal=use_decimal, **kw) |
||||
|
||||
|
||||
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, |
||||
parse_int=None, parse_constant=None, object_pairs_hook=None, |
||||
use_decimal=False, **kw): |
||||
"""Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON |
||||
document) to a Python object. |
||||
|
||||
*encoding* determines the encoding used to interpret any |
||||
:class:`str` objects decoded by this instance (``'utf-8'`` by |
||||
default). It has no effect when decoding :class:`unicode` objects. |
||||
|
||||
Note that currently only encodings that are a superset of ASCII work, |
||||
strings of other encodings should be passed in as :class:`unicode`. |
||||
|
||||
*object_hook*, if specified, will be called with the result of every |
||||
JSON object decoded and its return value will be used in place of the |
||||
given :class:`dict`. This can be used to provide custom |
||||
deserializations (e.g. to support JSON-RPC class hinting). |
||||
|
||||
*object_pairs_hook* is an optional function that will be called with |
||||
the result of any object literal decode with an ordered list of pairs. |
||||
The return value of *object_pairs_hook* will be used instead of the |
||||
:class:`dict`. This feature can be used to implement custom decoders |
||||
that rely on the order that the key and value pairs are decoded (for |
||||
example, :func:`collections.OrderedDict` will remember the order of |
||||
insertion). If *object_hook* is also defined, the *object_pairs_hook* |
||||
takes priority. |
||||
|
||||
*parse_float*, if specified, will be called with the string of every |
||||
JSON float to be decoded. By default, this is equivalent to |
||||
``float(num_str)``. This can be used to use another datatype or parser |
||||
for JSON floats (e.g. :class:`decimal.Decimal`). |
||||
|
||||
*parse_int*, if specified, will be called with the string of every |
||||
JSON int to be decoded. By default, this is equivalent to |
||||
``int(num_str)``. This can be used to use another datatype or parser |
||||
for JSON integers (e.g. :class:`float`). |
||||
|
||||
*parse_constant*, if specified, will be called with one of the |
||||
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This |
||||
can be used to raise an exception if invalid JSON numbers are |
||||
encountered. |
||||
|
||||
If *use_decimal* is true (default: ``False``) then it implies |
||||
parse_float=decimal.Decimal for parity with ``dump``. |
||||
|
||||
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` |
||||
kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead |
||||
of subclassing whenever possible. |
||||
|
||||
""" |
||||
if (cls is None and encoding is None and object_hook is None and |
||||
parse_int is None and parse_float is None and |
||||
parse_constant is None and object_pairs_hook is None |
||||
and not use_decimal and not kw): |
||||
return _default_decoder.decode(s) |
||||
if cls is None: |
||||
cls = JSONDecoder |
||||
if object_hook is not None: |
||||
kw['object_hook'] = object_hook |
||||
if object_pairs_hook is not None: |
||||
kw['object_pairs_hook'] = object_pairs_hook |
||||
if parse_float is not None: |
||||
kw['parse_float'] = parse_float |
||||
if parse_int is not None: |
||||
kw['parse_int'] = parse_int |
||||
if parse_constant is not None: |
||||
kw['parse_constant'] = parse_constant |
||||
if use_decimal: |
||||
if parse_float is not None: |
||||
raise TypeError("use_decimal=True implies parse_float=Decimal") |
||||
kw['parse_float'] = Decimal |
||||
return cls(encoding=encoding, **kw).decode(s) |
||||
|
||||
|
||||
def _toggle_speedups(enabled): |
||||
from . import decoder as dec |
||||
from . import encoder as enc |
||||
from . import scanner as scan |
||||
c_make_encoder = _import_c_make_encoder() |
||||
if enabled: |
||||
dec.scanstring = dec.c_scanstring or dec.py_scanstring |
||||
enc.c_make_encoder = c_make_encoder |
||||
enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or |
||||
enc.py_encode_basestring_ascii) |
||||
scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner |
||||
else: |
||||
dec.scanstring = dec.py_scanstring |
||||
enc.c_make_encoder = None |
||||
enc.encode_basestring_ascii = enc.py_encode_basestring_ascii |
||||
scan.make_scanner = scan.py_make_scanner |
||||
dec.make_scanner = scan.make_scanner |
||||
global _default_decoder |
||||
_default_decoder = JSONDecoder( |
||||
encoding=None, |
||||
object_hook=None, |
||||
object_pairs_hook=None, |
||||
) |
||||
global _default_encoder |
||||
_default_encoder = JSONEncoder( |
||||
skipkeys=False, |
||||
ensure_ascii=True, |
||||
check_circular=True, |
||||
allow_nan=True, |
||||
indent=None, |
||||
separators=None, |
||||
encoding='utf-8', |
||||
default=None, |
||||
) |
||||
|
||||
def simple_first(kv): |
||||
"""Helper function to pass to item_sort_key to sort simple |
||||
elements to the top, then container elements. |
||||
""" |
||||
return (isinstance(kv[1], (list, dict, tuple)), kv[0]) |
@ -0,0 +1,34 @@
|
||||
"""Python 3 compatibility shims |
||||
""" |
||||
import sys |
||||
if sys.version_info[0] < 3: |
||||
PY3 = False |
||||
def b(s): |
||||
return s |
||||
try: |
||||
from cStringIO import StringIO |
||||
except ImportError: |
||||
from StringIO import StringIO |
||||
BytesIO = StringIO |
||||
text_type = unicode |
||||
binary_type = str |
||||
string_types = (basestring,) |
||||
integer_types = (int, long) |
||||
unichr = unichr |
||||
reload_module = reload |
||||
else: |
||||
PY3 = True |
||||
if sys.version_info[:2] >= (3, 4): |
||||
from importlib import reload as reload_module |
||||
else: |
||||
from imp import reload as reload_module |
||||
def b(s): |
||||
return bytes(s, 'latin1') |
||||
from io import StringIO, BytesIO |
||||
text_type = str |
||||
binary_type = bytes |
||||
string_types = (str,) |
||||
integer_types = (int,) |
||||
unichr = chr |
||||
|
||||
long_type = integer_types[-1] |
@ -0,0 +1,400 @@
|
||||
"""Implementation of JSONDecoder |
||||
""" |
||||
from __future__ import absolute_import |
||||
import re |
||||
import sys |
||||
import struct |
||||
from .compat import PY3, unichr |
||||
from .scanner import make_scanner, JSONDecodeError |
||||
|
||||
def _import_c_scanstring(): |
||||
try: |
||||
from ._speedups import scanstring |
||||
return scanstring |
||||
except ImportError: |
||||
return None |
||||
c_scanstring = _import_c_scanstring() |
||||
|
||||
# NOTE (3.1.0): JSONDecodeError may still be imported from this module for |
||||
# compatibility, but it was never in the __all__ |
||||
__all__ = ['JSONDecoder'] |
||||
|
||||
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL |
||||
|
||||
def _floatconstants(): |
||||
if sys.version_info < (2, 6): |
||||
_BYTES = '7FF80000000000007FF0000000000000'.decode('hex') |
||||
nan, inf = struct.unpack('>dd', _BYTES) |
||||
else: |
||||
nan = float('nan') |
||||
inf = float('inf') |
||||
return nan, inf, -inf |
||||
|
||||
NaN, PosInf, NegInf = _floatconstants() |
||||
|
||||
_CONSTANTS = { |
||||
'-Infinity': NegInf, |
||||
'Infinity': PosInf, |
||||
'NaN': NaN, |
||||
} |
||||
|
||||
STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) |
||||
BACKSLASH = { |
||||
'"': u'"', '\\': u'\\', '/': u'/', |
||||
'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', |
||||
} |
||||
|
||||
DEFAULT_ENCODING = "utf-8" |
||||
|
||||
def py_scanstring(s, end, encoding=None, strict=True, |
||||
_b=BACKSLASH, _m=STRINGCHUNK.match, _join=u''.join, |
||||
_PY3=PY3, _maxunicode=sys.maxunicode): |
||||
"""Scan the string s for a JSON string. End is the index of the |
||||
character in s after the quote that started the JSON string. |
||||
Unescapes all valid JSON string escape sequences and raises ValueError |
||||
on attempt to decode an invalid string. If strict is False then literal |
||||
control characters are allowed in the string. |
||||
|
||||
Returns a tuple of the decoded string and the index of the character in s |
||||
after the end quote.""" |
||||
if encoding is None: |
||||
encoding = DEFAULT_ENCODING |
||||
chunks = [] |
||||
_append = chunks.append |
||||
begin = end - 1 |
||||
while 1: |
||||
chunk = _m(s, end) |
||||
if chunk is None: |
||||
raise JSONDecodeError( |
||||
"Unterminated string starting at", s, begin) |
||||
end = chunk.end() |
||||
content, terminator = chunk.groups() |
||||
# Content is contains zero or more unescaped string characters |
||||
if content: |
||||
if not _PY3 and not isinstance(content, unicode): |
||||
content = unicode(content, encoding) |
||||
_append(content) |
||||
# Terminator is the end of string, a literal control character, |
||||
# or a backslash denoting that an escape sequence follows |
||||
if terminator == '"': |
||||
break |
||||
elif terminator != '\\': |
||||
if strict: |
||||
msg = "Invalid control character %r at" |
||||
raise JSONDecodeError(msg, s, end) |
||||
else: |
||||
_append(terminator) |
||||
continue |
||||
try: |
||||
esc = s[end] |
||||
except IndexError: |
||||
raise JSONDecodeError( |
||||
"Unterminated string starting at", s, begin) |
||||
# If not a unicode escape sequence, must be in the lookup table |
||||
if esc != 'u': |
||||
try: |
||||
char = _b[esc] |
||||
except KeyError: |
||||
msg = "Invalid \\X escape sequence %r" |
||||
raise JSONDecodeError(msg, s, end) |
||||
end += 1 |
||||
else: |
||||
# Unicode escape sequence |
||||
msg = "Invalid \\uXXXX escape sequence" |
||||
esc = s[end + 1:end + 5] |
||||
escX = esc[1:2] |
||||
if len(esc) != 4 or escX == 'x' or escX == 'X': |
||||
raise JSONDecodeError(msg, s, end - 1) |
||||
try: |
||||
uni = int(esc, 16) |
||||
except ValueError: |
||||
raise JSONDecodeError(msg, s, end - 1) |
||||
end += 5 |
||||
# Check for surrogate pair on UCS-4 systems |
||||
# Note that this will join high/low surrogate pairs |
||||
# but will also pass unpaired surrogates through |
||||
if (_maxunicode > 65535 and |
||||
uni & 0xfc00 == 0xd800 and |
||||
s[end:end + 2] == '\\u'): |
||||
esc2 = s[end + 2:end + 6] |
||||
escX = esc2[1:2] |
||||
if len(esc2) == 4 and not (escX == 'x' or escX == 'X'): |
||||
try: |
||||
uni2 = int(esc2, 16) |
||||
except ValueError: |
||||
raise JSONDecodeError(msg, s, end) |
||||
if uni2 & 0xfc00 == 0xdc00: |
||||
uni = 0x10000 + (((uni - 0xd800) << 10) | |
||||
(uni2 - 0xdc00)) |
||||
end += 6 |
||||
char = unichr(uni) |
||||
# Append the unescaped character |
||||
_append(char) |
||||
return _join(chunks), end |
||||
|
||||
|
||||
# Use speedup if available |
||||
scanstring = c_scanstring or py_scanstring |
||||
|
||||
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) |
||||
WHITESPACE_STR = ' \t\n\r' |
||||
|
||||
def JSONObject(state, encoding, strict, scan_once, object_hook, |
||||
object_pairs_hook, memo=None, |
||||
_w=WHITESPACE.match, _ws=WHITESPACE_STR): |
||||
(s, end) = state |
||||
# Backwards compatibility |
||||
if memo is None: |
||||
memo = {} |
||||
memo_get = memo.setdefault |
||||
pairs = [] |
||||
# Use a slice to prevent IndexError from being raised, the following |
||||
# check will raise a more specific ValueError if the string is empty |
||||
nextchar = s[end:end + 1] |
||||
# Normally we expect nextchar == '"' |
||||
if nextchar != '"': |
||||
if nextchar in _ws: |
||||
end = _w(s, end).end() |
||||
nextchar = s[end:end + 1] |
||||
# Trivial empty object |
||||
if nextchar == '}': |
||||
if object_pairs_hook is not None: |
||||
result = object_pairs_hook(pairs) |
||||
return result, end + 1 |
||||
pairs = {} |
||||
if object_hook is not None: |
||||
pairs = object_hook(pairs) |
||||
return pairs, end + 1 |
||||
elif nextchar != '"': |
||||
raise JSONDecodeError( |
||||
"Expecting property name enclosed in double quotes", |
||||
s, end) |
||||
end += 1 |
||||
while True: |
||||
key, end = scanstring(s, end, encoding, strict) |
||||
key = memo_get(key, key) |
||||
|
||||
# To skip some function call overhead we optimize the fast paths where |
||||
# the JSON key separator is ": " or just ":". |
||||
if s[end:end + 1] != ':': |
||||
end = _w(s, end).end() |
||||
if s[end:end + 1] != ':': |
||||
raise JSONDecodeError("Expecting ':' delimiter", s, end) |
||||
|
||||
end += 1 |
||||
|
||||
try: |
||||
if s[end] in _ws: |
||||
end += 1 |
||||
if s[end] in _ws: |
||||
end = _w(s, end + 1).end() |
||||
except IndexError: |
||||
pass |
||||
|
||||
value, end = scan_once(s, end) |
||||
pairs.append((key, value)) |
||||
|
||||
try: |
||||
nextchar = s[end] |
||||
if nextchar in _ws: |
||||
end = _w(s, end + 1).end() |
||||
nextchar = s[end] |
||||
except IndexError: |
||||
nextchar = '' |
||||
end += 1 |
||||
|
||||
if nextchar == '}': |
||||
break |
||||
elif nextchar != ',': |
||||
raise JSONDecodeError("Expecting ',' delimiter or '}'", s, end - 1) |
||||
|
||||
try: |
||||
nextchar = s[end] |
||||
if nextchar in _ws: |
||||
end += 1 |
||||
nextchar = s[end] |
||||
if nextchar in _ws: |
||||
end = _w(s, end + 1).end() |
||||
nextchar = s[end] |
||||
except IndexError: |
||||
nextchar = '' |
||||
|
||||
end += 1 |
||||
if nextchar != '"': |
||||
raise JSONDecodeError( |
||||
"Expecting property name enclosed in double quotes", |
||||
s, end - 1) |
||||
|
||||
if object_pairs_hook is not None: |
||||
result = object_pairs_hook(pairs) |
||||
return result, end |
||||
pairs = dict(pairs) |
||||
if object_hook is not None: |
||||
pairs = object_hook(pairs) |
||||
return pairs, end |
||||
|
||||
def JSONArray(state, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): |
||||
(s, end) = state |
||||
values = [] |
||||
nextchar = s[end:end + 1] |
||||
if nextchar in _ws: |
||||
end = _w(s, end + 1).end() |
||||
nextchar = s[end:end + 1] |
||||
# Look-ahead for trivial empty array |
||||
if nextchar == ']': |
||||
return values, end + 1 |
||||
elif nextchar == '': |
||||
raise JSONDecodeError("Expecting value or ']'", s, end) |
||||
_append = values.append |
||||
while True: |
||||
value, end = scan_once(s, end) |
||||
_append(value) |
||||
nextchar = s[end:end + 1] |
||||
if nextchar in _ws: |
||||
end = _w(s, end + 1).end() |
||||
nextchar = s[end:end + 1] |
||||
end += 1 |
||||
if nextchar == ']': |
||||
break |
||||
elif nextchar != ',': |
||||
raise JSONDecodeError("Expecting ',' delimiter or ']'", s, end - 1) |
||||
|
||||
try: |
||||
if s[end] in _ws: |
||||
end += 1 |
||||
if s[end] in _ws: |
||||
end = _w(s, end + 1).end() |
||||
except IndexError: |
||||
pass |
||||
|
||||
return values, end |
||||
|
||||
class JSONDecoder(object): |
||||
"""Simple JSON <http://json.org> decoder |
||||
|
||||
Performs the following translations in decoding by default: |
||||
|
||||
+---------------+-------------------+ |
||||
| JSON | Python | |
||||
+===============+===================+ |
||||
| object | dict | |
||||
+---------------+-------------------+ |
||||
| array | list | |
||||
+---------------+-------------------+ |
||||
| string | str, unicode | |
||||
+---------------+-------------------+ |
||||
| number (int) | int, long | |
||||
+---------------+-------------------+ |
||||
| number (real) | float | |
||||
+---------------+-------------------+ |
||||
| true | True | |
||||
+---------------+-------------------+ |
||||
| false | False | |
||||
+---------------+-------------------+ |
||||
| null | None | |
||||
+---------------+-------------------+ |
||||
|
||||
It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as |
||||
their corresponding ``float`` values, which is outside the JSON spec. |
||||
|
||||
""" |
||||
|
||||
def __init__(self, encoding=None, object_hook=None, parse_float=None, |
||||
parse_int=None, parse_constant=None, strict=True, |
||||
object_pairs_hook=None): |
||||
""" |
||||
*encoding* determines the encoding used to interpret any |
||||
:class:`str` objects decoded by this instance (``'utf-8'`` by |
||||
default). It has no effect when decoding :class:`unicode` objects. |
||||
|
||||
Note that currently only encodings that are a superset of ASCII work, |
||||
strings of other encodings should be passed in as :class:`unicode`. |
||||
|
||||
*object_hook*, if specified, will be called with the result of every |
||||
JSON object decoded and its return value will be used in place of the |
||||
given :class:`dict`. This can be used to provide custom |
||||
deserializations (e.g. to support JSON-RPC class hinting). |
||||
|
||||
*object_pairs_hook* is an optional function that will be called with |
||||
the result of any object literal decode with an ordered list of pairs. |
||||
The return value of *object_pairs_hook* will be used instead of the |
||||
:class:`dict`. This feature can be used to implement custom decoders |
||||
that rely on the order that the key and value pairs are decoded (for |
||||
example, :func:`collections.OrderedDict` will remember the order of |
||||
insertion). If *object_hook* is also defined, the *object_pairs_hook* |
||||
takes priority. |
||||
|
||||
*parse_float*, if specified, will be called with the string of every |
||||
JSON float to be decoded. By default, this is equivalent to |
||||
``float(num_str)``. This can be used to use another datatype or parser |
||||
for JSON floats (e.g. :class:`decimal.Decimal`). |
||||
|
||||
*parse_int*, if specified, will be called with the string of every |
||||
JSON int to be decoded. By default, this is equivalent to |
||||
``int(num_str)``. This can be used to use another datatype or parser |
||||
for JSON integers (e.g. :class:`float`). |
||||
|
||||
*parse_constant*, if specified, will be called with one of the |
||||
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This |
||||
can be used to raise an exception if invalid JSON numbers are |
||||
encountered. |
||||
|
||||
*strict* controls the parser's behavior when it encounters an |
||||
invalid control character in a string. The default setting of |
||||
``True`` means that unescaped control characters are parse errors, if |
||||
``False`` then control characters will be allowed in strings. |
||||
|
||||
""" |
||||
if encoding is None: |
||||
encoding = DEFAULT_ENCODING |
||||
self.encoding = encoding |
||||
self.object_hook = object_hook |
||||
self.object_pairs_hook = object_pairs_hook |
||||
self.parse_float = parse_float or float |
||||
self.parse_int = parse_int or int |
||||
self.parse_constant = parse_constant or _CONSTANTS.__getitem__ |
||||
self.strict = strict |
||||
self.parse_object = JSONObject |
||||
self.parse_array = JSONArray |
||||
self.parse_string = scanstring |
||||
self.memo = {} |
||||
self.scan_once = make_scanner(self) |
||||
|
||||
def decode(self, s, _w=WHITESPACE.match, _PY3=PY3): |
||||
"""Return the Python representation of ``s`` (a ``str`` or ``unicode`` |
||||
instance containing a JSON document) |
||||
|
||||
""" |
||||
if _PY3 and isinstance(s, bytes): |
||||
s = str(s, self.encoding) |
||||
obj, end = self.raw_decode(s) |
||||
end = _w(s, end).end() |
||||
if end != len(s): |
||||
raise JSONDecodeError("Extra data", s, end, len(s)) |
||||
return obj |
||||
|
||||
def raw_decode(self, s, idx=0, _w=WHITESPACE.match, _PY3=PY3): |
||||
"""Decode a JSON document from ``s`` (a ``str`` or ``unicode`` |
||||
beginning with a JSON document) and return a 2-tuple of the Python |
||||
representation and the index in ``s`` where the document ended. |
||||
Optionally, ``idx`` can be used to specify an offset in ``s`` where |
||||
the JSON document begins. |
||||
|
||||
This can be used to decode a JSON document from a string that may |
||||
have extraneous data at the end. |
||||
|
||||
""" |
||||
if idx < 0: |
||||
# Ensure that raw_decode bails on negative indexes, the regex |
||||
# would otherwise mask this behavior. #98 |
||||
raise JSONDecodeError('Expecting value', s, idx) |
||||
if _PY3 and not isinstance(s, str): |
||||
raise TypeError("Input string must be text, not bytes") |
||||
# strip UTF-8 bom |
||||
if len(s) > idx: |
||||
ord0 = ord(s[idx]) |
||||
if ord0 == 0xfeff: |
||||
idx += 1 |
||||
elif ord0 == 0xef and s[idx:idx + 3] == '\xef\xbb\xbf': |
||||
idx += 3 |
||||
return self.scan_once(s, idx=_w(s, idx).end()) |
@ -0,0 +1,722 @@
|
||||
"""Implementation of JSONEncoder |
||||
""" |
||||
from __future__ import absolute_import |
||||
import re |
||||
from operator import itemgetter |
||||
# Do not import Decimal directly to avoid reload issues |
||||
import decimal |
||||
from .compat import unichr, binary_type, text_type, string_types, integer_types, PY3 |
||||
def _import_speedups(): |
||||
try: |
||||
from . import _speedups |
||||
return _speedups.encode_basestring_ascii, _speedups.make_encoder |
||||
except ImportError: |
||||
return None, None |
||||
c_encode_basestring_ascii, c_make_encoder = _import_speedups() |
||||
|
||||
from .decoder import PosInf |
||||
from .raw_json import RawJSON |
||||
|
||||
ESCAPE = re.compile(r'[\x00-\x1f\\"]') |
||||
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') |
||||
HAS_UTF8 = re.compile(r'[\x80-\xff]') |
||||
ESCAPE_DCT = { |
||||
'\\': '\\\\', |
||||
'"': '\\"', |
||||
'\b': '\\b', |
||||
'\f': '\\f', |
||||
'\n': '\\n', |
||||
'\r': '\\r', |
||||
'\t': '\\t', |
||||
} |
||||
for i in range(0x20): |
||||
#ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) |
||||
ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) |
||||
|
||||
FLOAT_REPR = repr |
||||
|
||||
def encode_basestring(s, _PY3=PY3, _q=u'"'): |
||||
"""Return a JSON representation of a Python string |
||||
|
||||
""" |
||||
if _PY3: |
||||
if isinstance(s, bytes): |
||||
s = str(s, 'utf-8') |
||||
elif type(s) is not str: |
||||
# convert an str subclass instance to exact str |
||||
# raise a TypeError otherwise |
||||
s = str.__str__(s) |
||||
else: |
||||
if isinstance(s, str) and HAS_UTF8.search(s) is not None: |
||||
s = unicode(s, 'utf-8') |
||||
elif type(s) not in (str, unicode): |
||||
# convert an str subclass instance to exact str |
||||
# convert a unicode subclass instance to exact unicode |
||||
# raise a TypeError otherwise |
||||
if isinstance(s, str): |
||||
s = str.__str__(s) |
||||
else: |
||||
s = unicode.__getnewargs__(s)[0] |
||||
def replace(match): |
||||
return ESCAPE_DCT[match.group(0)] |
||||
return _q + ESCAPE.sub(replace, s) + _q |
||||
|
||||
|
||||
def py_encode_basestring_ascii(s, _PY3=PY3): |
||||
"""Return an ASCII-only JSON representation of a Python string |
||||
|
||||
""" |
||||
if _PY3: |
||||
if isinstance(s, bytes): |
||||
s = str(s, 'utf-8') |
||||
elif type(s) is not str: |
||||
# convert an str subclass instance to exact str |
||||
# raise a TypeError otherwise |
||||
s = str.__str__(s) |
||||
else: |
||||
if isinstance(s, str) and HAS_UTF8.search(s) is not None: |
||||
s = unicode(s, 'utf-8') |
||||
elif type(s) not in (str, unicode): |
||||
# convert an str subclass instance to exact str |
||||
# convert a unicode subclass instance to exact unicode |
||||
# raise a TypeError otherwise |
||||
if isinstance(s, str): |
||||
s = str.__str__(s) |
||||
else: |
||||
s = unicode.__getnewargs__(s)[0] |
||||
def replace(match): |
||||
s = match.group(0) |
||||
try: |
||||
return ESCAPE_DCT[s] |
||||
except KeyError: |
||||
n = ord(s) |
||||
if n < 0x10000: |
||||
#return '\\u{0:04x}'.format(n) |
||||
return '\\u%04x' % (n,) |
||||
else: |
||||
# surrogate pair |
||||
n -= 0x10000 |
||||
s1 = 0xd800 | ((n >> 10) & 0x3ff) |
||||
s2 = 0xdc00 | (n & 0x3ff) |
||||
#return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) |
||||
return '\\u%04x\\u%04x' % (s1, s2) |
||||
return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' |
||||
|
||||
|
||||
encode_basestring_ascii = ( |
||||
c_encode_basestring_ascii or py_encode_basestring_ascii) |
||||
|
||||
class JSONEncoder(object): |
||||
"""Extensible JSON <http://json.org> encoder for Python data structures. |
||||
|
||||
Supports the following objects and types by default: |
||||
|
||||
+-------------------+---------------+ |
||||
| Python | JSON | |
||||
+===================+===============+ |
||||
| dict, namedtuple | object | |
||||
+-------------------+---------------+ |
||||
| list, tuple | array | |
||||
+-------------------+---------------+ |
||||
| str, unicode | string | |
||||
+-------------------+---------------+ |
||||
| int, long, float | number | |
||||
+-------------------+---------------+ |
||||
| True | true | |
||||
+-------------------+---------------+ |
||||
| False | false | |
||||
+-------------------+---------------+ |
||||
| None | null | |
||||
+-------------------+---------------+ |
||||
|
||||
To extend this to recognize other objects, subclass and implement a |
||||
``.default()`` method with another method that returns a serializable |
||||
object for ``o`` if possible, otherwise it should call the superclass |
||||
implementation (to raise ``TypeError``). |
||||
|
||||
""" |
||||
item_separator = ', ' |
||||
key_separator = ': ' |
||||
|
||||
def __init__(self, skipkeys=False, ensure_ascii=True, |
||||
check_circular=True, allow_nan=True, sort_keys=False, |
||||
indent=None, separators=None, encoding='utf-8', default=None, |
||||
use_decimal=True, namedtuple_as_object=True, |
||||
tuple_as_array=True, bigint_as_string=False, |
||||
item_sort_key=None, for_json=False, ignore_nan=False, |
||||
int_as_string_bitcount=None, iterable_as_array=False): |
||||
"""Constructor for JSONEncoder, with sensible defaults. |
||||
|
||||
If skipkeys is false, then it is a TypeError to attempt |
||||
encoding of keys that are not str, int, long, float or None. If |
||||
skipkeys is True, such items are simply skipped. |
||||
|
||||
If ensure_ascii is true, the output is guaranteed to be str |
||||
objects with all incoming unicode characters escaped. If |
||||
ensure_ascii is false, the output will be unicode object. |
||||
|
||||
If check_circular is true, then lists, dicts, and custom encoded |
||||
objects will be checked for circular references during encoding to |
||||
prevent an infinite recursion (which would cause an OverflowError). |
||||
Otherwise, no such check takes place. |
||||
|
||||
If allow_nan is true, then NaN, Infinity, and -Infinity will be |
||||
encoded as such. This behavior is not JSON specification compliant, |
||||
but is consistent with most JavaScript based encoders and decoders. |
||||
Otherwise, it will be a ValueError to encode such floats. |
||||
|
||||
If sort_keys is true, then the output of dictionaries will be |
||||
sorted by key; this is useful for regression tests to ensure |
||||
that JSON serializations can be compared on a day-to-day basis. |
||||
|
||||
If indent is a string, then JSON array elements and object members |
||||
will be pretty-printed with a newline followed by that string repeated |
||||
for each level of nesting. ``None`` (the default) selects the most compact |
||||
representation without any newlines. For backwards compatibility with |
||||
versions of simplejson earlier than 2.1.0, an integer is also accepted |
||||
and is converted to a string with that many spaces. |
||||
|
||||
If specified, separators should be an (item_separator, key_separator) |
||||
tuple. The default is (', ', ': ') if *indent* is ``None`` and |
||||
(',', ': ') otherwise. To get the most compact JSON representation, |
||||
you should specify (' |