[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r17104: {updater} Stop trying to monkeypatch simplejson to support canonical e (updater/trunk/lib/thandy)
Author: nickm
Date: 2008-10-14 17:07:57 -0400 (Tue, 14 Oct 2008)
New Revision: 17104
Modified:
updater/trunk/lib/thandy/formats.py
Log:
Stop trying to monkeypatch simplejson to support canonical encoding, and just use our own internal canonical encoder when we want that. It is actually less code this way.
Modified: updater/trunk/lib/thandy/formats.py
===================================================================
--- updater/trunk/lib/thandy/formats.py 2008-10-14 21:05:54 UTC (rev 17103)
+++ updater/trunk/lib/thandy/formats.py 2008-10-14 21:07:57 UTC (rev 17104)
@@ -153,60 +153,53 @@
return SignatureStatus(goodSigs, badSigs, unknownSigs, tangentialSigs)
-def _encodeCanonical_makeiter(obj):
- """Return an iterator to encode 'obj' canonically, and a nil
- cleanup function. Works with newer versions of simplejson that
- have a _make_iterencode method.
- """
- def default(o):
- raise TypeError("Can't encode %r", o)
- def floatstr(o):
- raise TypeError("Floats not allowed.")
- def canonical_str_encoder(s):
- return '"%s"' % re.sub(r'(["\\])', r'\\\1', s)
+def _encodeCanonical(obj, outf):
+ # Helper for encodeCanonical. Older versions of simplejson.encoder don't
+ # even let us replace the separators.
- # XXX This is, alas, a hack. I'll submit a canonical JSon patch to
- # the simplejson folks.
- iterator = simplejson.encoder._make_iterencode(
- None, default, canonical_str_encoder, None, floatstr,
- ":", ",", True, False, True)(obj, 0)
-
- return iterator, lambda:None
-
-def _encodeCanonical_monkeypatch(obj):
- """Return an iterator to encode 'obj' canonically, and a cleanup
- function to un-monkeypatch simplejson. Works with older
- versions of simplejson. This is not threadsafe wrt other
- invocations of simplejson, so until we're all upgraded, no
- doing canonical encodings outside of the main thread.
- """
- def default(o):
- raise TypeError("Can't encode %r", o)
- save_floatstr = simplejson.encoder.floatstr
- save_encode_basestring = simplejson.encoder.encode_basestring
- def floatstr(o):
- raise TypeError("Floats not allowed.")
def canonical_str_encoder(s):
- return '"%s"' % re.sub(r'(["\\])', r'\\\1', s)
- simplejson.encoder.floatstr = floatstr
- simplejson.encoder.encode_basestring = canonical_str_encoder
- def unpatch():
- simplejson.encoder.floatstr = save_floatstr
- simplejson.encoder.encode_basestring = save_encode_basestring
+ s = '"%s"' % re.sub(r'(["\\])', r'\\\1', s)
+ if isinstance(s, unicode):
+ return s.encode("utf-8")
+ else:
+ return s
- encoder = simplejson.encoder.JSONEncoder(ensure_ascii=False,
- check_circular=False,
- allow_nan=False,
- sort_keys=True,
- separators=(",",":"),
- default=default)
- return encoder.iterencode(obj), unpatch
+ if isinstance(obj, basestring):
+ outf(canonical_str_encoder(obj))
+ elif obj is True:
+ outf("true")
+ elif obj is False:
+ outf("false")
+ elif obj is None:
+ outf("null")
+ elif isinstance(obj, (int,long)):
+ outf(str(obj))
+ elif isinstance(obj, (tuple, list)):
+ outf("[")
+ if len(obj):
+ for item in obj[:-1]:
+ _encodeCanonical(item, outf)
+ outf(",")
+ _encodeCanonical(obj[-1], outf)
+ outf("]")
+ elif isinstance(obj, dict):
+ outf("{")
+ if len(obj):
+ items = obj.items()
+ items.sort()
+ for k,v in items[:-1]:
+ outf(canonical_str_encoder(k))
+ outf(":")
+ _encodeCanonical(v, outf)
+ outf(",")
+ k, v = items[-1]
+ outf(canonical_str_encoder(k))
+ outf(":")
+ _encodeCanonical(v, outf)
+ outf("}")
+ else:
+ raise thandy.FormatException("I can't encode %r"%obj)
-if hasattr(simplejson.encoder, "_make_iterencode"):
- _encodeCanonical = _encodeCanonical_makeiter
-else:
- _encodeCanonical = _encodeCanonical_monkeypatch
-
def encodeCanonical(obj, outf=None):
"""Encode the object obj in canoncial JSon form, as specified at
http://wiki.laptop.org/go/Canonical_JSON . It's a restricted
@@ -220,6 +213,10 @@
'""'
>>> encodeCanonical([1, 2, 3])
'[1,2,3]'
+ >>> encodeCanonical([])
+ '[]'
+ >>> encodeCanonical({"A": [99]})
+ '{"A":[99]}'
>>> encodeCanonical({"x" : 3, "y" : 2})
'{"x":3,"y":2}'
"""
@@ -229,16 +226,12 @@
result = [ ]
outf = result.append
- iterator, cleanup = _encodeCanonical(obj)
+ _encodeCanonical(obj, outf)
- try:
- for u in iterator:
- outf(u.encode("utf-8"))
- finally:
- cleanup()
if result is not None:
return "".join(result)
+
def getDigest(obj, digestObj=None):
"""Update 'digestObj' (typically a SHA256 object) with the digest of
the canonical json encoding of obj. If digestObj is none,