Skip to content

Commit

Permalink
Merge pull request #19 from crcastle/master
Browse files Browse the repository at this point in the history
PrettyJson working in both ST2 and ST3
  • Loading branch information
dzhibas committed Mar 29, 2013
2 parents 61c8c64 + 3166953 commit b0fdad2
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 114 deletions.
19 changes: 10 additions & 9 deletions PrettyJson.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import sublime
import sublime_plugin
import json
import sys
import decimal

if sys.version_info > (2, 7, 0):
import json
from collections import OrderedDict
else:
try:
# python 3 / Sublime Text 3
from . import simplejson as json
from .simplejson import OrderedDict
except (ValueError):
# python 2 / Sublime Text 2
import simplejson as json
from simplejson import OrderedDict


s = sublime.load_settings("Pretty JSON.sublime-settings")


Expand All @@ -38,5 +37,7 @@ def run(self, edit):
separators=(',', ': '),
use_decimal=True))

except Exception, e:
sublime.status_message(str(e))
except Exception:
import sys
exc = sys.exc_info()[1]
sublime.status_message(str(exc))
34 changes: 18 additions & 16 deletions simplejson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
>>> 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")
>>> print(json.dumps("\"foo\bar"))
"\"foo\bar"
>>> print json.dumps(u'\u1234')
>>> print(json.dumps(u'\u1234'))
"\u1234"
>>> print json.dumps('\\')
>>> print(json.dumps('\\'))
"\\"
>>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
{"a": 0, "b": 0, "c": 0}
>>> from StringIO import StringIO
>>> from simplejson.compat import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
Expand All @@ -31,14 +31,15 @@
Compact encoding::
>>> import simplejson as json
>>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
>>> 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
>>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ')
>>> print '\n'.join([l.rstrip() for l in s.splitlines()])
>>> print('\n'.join([l.rstrip() for l in s.splitlines()]))
{
"4": 5,
"6": 7
Expand All @@ -52,7 +53,7 @@
True
>>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
True
>>> from StringIO import StringIO
>>> from simplejson.compat import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)[0] == 'streaming API'
True
Expand Down Expand Up @@ -97,7 +98,8 @@
$ echo '{ 1.2:3.4}' | python -m simplejson.tool
Expecting property name: line 1 column 2 (char 2)
"""
__version__ = '2.5.2'
from __future__ import absolute_import
__version__ = '3.0.7'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
Expand All @@ -108,20 +110,20 @@

from decimal import Decimal

from decoder import JSONDecoder, JSONDecodeError
from encoder import JSONEncoder
from .decoder import JSONDecoder, JSONDecodeError
from .encoder import JSONEncoder, JSONEncoderForHTML
def _import_OrderedDict():
import collections
try:
return collections.OrderedDict
except AttributeError:
import ordered_dict
from . import ordered_dict
return ordered_dict.OrderedDict
OrderedDict = _import_OrderedDict()

def _import_c_make_encoder():
try:
from simplejson._speedups import make_encoder
from ._speedups import make_encoder
return make_encoder
except ImportError:
return None
Expand Down Expand Up @@ -469,9 +471,9 @@ def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,


def _toggle_speedups(enabled):
import simplejson.decoder as dec
import simplejson.encoder as enc
import simplejson.scanner as scan
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
Expand Down
43 changes: 43 additions & 0 deletions simplejson/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Python 3 compatibility shims
"""
import sys
if sys.version_info[0] < 3:
PY3 = False
def b(s):
return s
def u(s):
return unicode(s, 'unicode_escape')
import cStringIO as StringIO
StringIO = BytesIO = StringIO.StringIO
text_type = unicode
binary_type = str
string_types = (basestring,)
integer_types = (int, long)
unichr = unichr
reload_module = reload
def fromhex(s):
return s.decode('hex')

else:
PY3 = True
from imp import reload as reload_module
import codecs
def b(s):
return codecs.latin_1_encode(s)[0]
def u(s):
return s
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
text_type = str
binary_type = bytes
string_types = (str,)
integer_types = (int,)

def unichr(s):
return u(chr(s))

def fromhex(s):
return bytes.fromhex(s)

long_type = integer_types[-1]
93 changes: 62 additions & 31 deletions simplejson/decoder.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""Implementation of JSONDecoder
"""
from __future__ import absolute_import
import re
import sys
import struct

from simplejson.scanner import make_scanner
from .compat import fromhex, b, u, text_type, binary_type, PY3, unichr
from .scanner import make_scanner
def _import_c_scanstring():
try:
from simplejson._speedups import scanstring
from ._speedups import scanstring
return scanstring
except ImportError:
return None
Expand All @@ -18,7 +19,7 @@ def _import_c_scanstring():
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL

def _floatconstants():
_BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
_BYTES = fromhex('7FF80000000000007FF0000000000000')
# The struct module in Python 2.4 would get frexp() out of range here
# when an endian is specified in the format string. Fixed in Python 2.5+
if sys.byteorder != 'big':
Expand Down Expand Up @@ -87,14 +88,15 @@ def errmsg(msg, doc, pos, end=None):

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',
'"': u('"'), '\\': u('\u005c'), '/': 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):
_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
Expand All @@ -117,8 +119,8 @@ def py_scanstring(s, end, encoding=None, strict=True,
content, terminator = chunk.groups()
# Content is contains zero or more unescaped string characters
if content:
if not isinstance(content, unicode):
content = unicode(content, encoding)
if not _PY3 and not isinstance(content, text_type):
content = text_type(content, encoding)
_append(content)
# Terminator is the end of string, a literal control character,
# or a backslash denoting that an escape sequence follows
Expand Down Expand Up @@ -152,23 +154,38 @@ def py_scanstring(s, end, encoding=None, strict=True,
if len(esc) != 4:
msg = "Invalid \\uXXXX escape"
raise JSONDecodeError(msg, s, end)
uni = int(esc, 16)
try:
uni = int(esc, 16)
except ValueError:
msg = "Invalid \\uXXXX escape"
raise JSONDecodeError(msg, s, end)
# Check for surrogate pair on UCS-4 systems
if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
if not s[end + 5:end + 7] == '\\u':
if _maxunicode > 65535:
unimask = uni & 0xfc00
if unimask == 0xd800:
msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
if not s[end + 5:end + 7] == '\\u':
raise JSONDecodeError(msg, s, end)
esc2 = s[end + 7:end + 11]
if len(esc2) != 4:
raise JSONDecodeError(msg, s, end)
try:
uni2 = int(esc2, 16)
except ValueError:
raise JSONDecodeError(msg, s, end)
if uni2 & 0xfc00 != 0xdc00:
msg = "Unpaired high surrogate"
raise JSONDecodeError(msg, s, end)
uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
next_end += 6
elif unimask == 0xdc00:
msg = "Unpaired low surrogate"
raise JSONDecodeError(msg, s, end)
esc2 = s[end + 7:end + 11]
if len(esc2) != 4:
raise JSONDecodeError(msg, s, end)
uni2 = int(esc2, 16)
uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
next_end += 6
char = unichr(uni)
end = next_end
# Append the unescaped character
_append(char)
return u''.join(chunks), end
return _join(chunks), end


# Use speedup if available
Expand All @@ -177,9 +194,10 @@ def py_scanstring(s, end, encoding=None, strict=True,
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
WHITESPACE_STR = ' \t\n\r'

def JSONObject((s, end), encoding, strict, scan_once, object_hook,
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 = {}
Expand All @@ -203,7 +221,9 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
pairs = object_hook(pairs)
return pairs, end + 1
elif nextchar != '"':
raise JSONDecodeError("Expecting property name", s, end)
raise JSONDecodeError(
"Expecting property name enclosed in double quotes",
s, end)
end += 1
while True:
key, end = scanstring(s, end, encoding, strict)
Expand All @@ -214,7 +234,7 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
if s[end:end + 1] != ':':
end = _w(s, end).end()
if s[end:end + 1] != ':':
raise JSONDecodeError("Expecting : delimiter", s, end)
raise JSONDecodeError("Expecting ':' delimiter", s, end)

end += 1

Expand Down Expand Up @@ -244,7 +264,7 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
if nextchar == '}':
break
elif nextchar != ',':
raise JSONDecodeError("Expecting , delimiter", s, end - 1)
raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)

try:
nextchar = s[end]
Expand All @@ -259,7 +279,9 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,

end += 1
if nextchar != '"':
raise JSONDecodeError("Expecting property name", s, end - 1)
raise JSONDecodeError(
"Expecting property name enclosed in double quotes",
s, end - 1)

if object_pairs_hook is not None:
result = object_pairs_hook(pairs)
Expand All @@ -269,7 +291,8 @@ def JSONObject((s, end), encoding, strict, scan_once, object_hook,
pairs = object_hook(pairs)
return pairs, end

def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
def JSONArray(state, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
(s, end) = state
values = []
nextchar = s[end:end + 1]
if nextchar in _ws:
Expand All @@ -293,7 +316,7 @@ def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
if nextchar == ']':
break
elif nextchar != ',':
raise JSONDecodeError("Expecting , delimiter", s, end)
raise JSONDecodeError("Expecting ',' delimiter", s, end)

try:
if s[end] in _ws:
Expand Down Expand Up @@ -381,6 +404,8 @@ def __init__(self, encoding=None, object_hook=None, parse_float=None,
``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
Expand All @@ -394,28 +419,34 @@ def __init__(self, encoding=None, object_hook=None, parse_float=None,
self.memo = {}
self.scan_once = make_scanner(self)

def decode(self, s, _w=WHITESPACE.match):
def decode(self, s, _w=WHITESPACE.match, _PY3=PY3):
"""Return the Python representation of ``s`` (a ``str`` or ``unicode``
instance containing a JSON document)
"""
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
if _PY3 and isinstance(s, binary_type):
s = s.decode(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):
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 _PY3 and not isinstance(s, text_type):
raise TypeError("Input string must be text, not bytes")
try:
obj, end = self.scan_once(s, idx)
obj, end = self.scan_once(s, idx=_w(s, idx).end())
except StopIteration:
raise JSONDecodeError("No JSON object could be decoded", s, idx)
return obj, end
Loading

0 comments on commit b0fdad2

Please sign in to comment.