On Thu, Apr 10, 2008 at 3:57 PM, Martin Langhoff
<[EMAIL PROTECTED]> wrote:
> Attached you'll find a trivial script to concat-and-sort various lease
>  files. This makes life easier for regional teams that deal with
>  various shipments.
>
>  Usage:
>
>     cat-leases.pl */lease.sig  > all_leases.sig

Ok, the script I posted initially didn't work because the leases file
is in Canonical JSON, not any plain old JSON thing. So here's a python
version using the Canonical JSON libs. I have also attached the
json.py file, which I stole from bitfrost. If you have bitfrost
anywhere in your python path, you won't need this additional json.py .

The usage is the same as above, except that a significant "l" changes to a "y".

cheers,




m
-- 
 [EMAIL PROTECTED]
 [EMAIL PROTECTED] -- School Server Architect
 - ask interesting questions
 - don't get distracted with shiny stuff - working code first
 - http://wiki.laptop.org/go/User:Martinlanghoff
#!/usr/bin/python 
#
# Usage:
#
#       cat-leases.pl */lease.sig  > all_leases.sig
#
# cat-leases will concatenate and sort the JSON-encoded
# activation leases (for OLPC XOs of the XO-1 series).
#
#
# NOTE: the json we import here is actually
# "Canonical JSON" reader/writer from the
# bitfrost/util directory.
#
# 
# Blame: Martin Langhoff <[EMAIL PROTECTED]>
# License: GPL v2
#

# if Bitfrost's json.py is in the PYTHONPATH
import json
# if Bitfrost is in the PYTHONPATH
#import bitfrost.util.json as json

import sys

data = {}

# note - we skip the zeroth position
# of argv which has $0
for  n in range(1,len(sys.argv)):
    fn = sys.argv[n]
    file = open(fn, 'r')
    fcontent = file.read()
    file.close()

    # read the data and pull the dict out of the nested
    # structure
    newdata = json.read(fcontent)
    newdata = newdata.pop()
    data.update(newdata)

ordereddata = {}
for k in sorted(newdata.keys()):
    ordereddata[k] = newdata[k]

json.write_to_file(sys.stdout, [1, ordereddata])
#!/usr/bin/python2.5
"""Canonical JSON reader/writer.

See http://wiki.laptop.org/go/Canonical_JSON for specification.

>>> _selfTest()
All tests passed.
"""
import re, types

##    json.py implements a JSON (http://json.org) reader and writer.
##    Copyright (C) 2005  Patrick D. Logan
##    Contact mailto:[EMAIL PROTECTED]
##
##    This library is free software; you can redistribute it and/or
##    modify it under the terms of the GNU Lesser General Public
##    License as published by the Free Software Foundation; either
##    version 2.1 of the License, or (at your option) any later version.
##
##    This library is distributed in the hope that it will be useful,
##    but WITHOUT ANY WARRANTY; without even the implied warranty of
##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
##    Lesser General Public License for more details.
##
##    You should have received a copy of the GNU Lesser General Public
##    License along with this library; if not, write to the Free Software
##    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

##    HACKED TO PIECES by C. Scott Ananian, 2007.
##    to support "canonical JSON" format (and only that!)



class _StringGenerator(object):
    def __init__(self, string):
        self.string = string
        self.index = 0 # first unread character
    def peek(self):
        i = self.index
        if i < len(self.string):
            return self.string[i]
        else:
            return None
    def next(self):
        if self.index < len(self.string):
            c = self.string[self.index]
            self.index += 1
            return c
        else:
            raise StopIteration
    def read_re(self, regex, group=0):
        m = regex.match(self.string, self.index)
        if m is None:
            raise ReadException("Trying to read %s: '%s'" % (regex, self.string[self.index:]))
        self.index = m.end()
        return m.group(group)
    def all(self):
        return self.string

class WriteException(Exception):
    pass

class ReadException(Exception):
    pass

class CJsonReader(object):
    hex_digits = {'a': 10,'b': 11,'c': 12,'d': 13,'e': 14,'f':15}

    def read(self, s):
        self._generator = _StringGenerator(s)
        result = self._read()
        if self._generator.peek() is not None:
            raise ReadException("String incompletely read.")
        return result

    def _read(self):
        peek = self._generator.peek()
        if peek is None:
            raise ReadException("Nothing to read: '%s'" % self._generator.all())
        if peek == '{':
            return self._readObject()
        elif peek == '[':
            return self._readArray()            
        elif peek == '"':
            return self._readString()
        elif peek == '-' or peek.isdigit():
            return self._readNumber()
        elif peek == 't':
            return self._readTrue()
        elif peek == 'f':
            return self._readFalse()
        elif peek == 'n':
            return self._readNull()
        else:
            raise ReadException("Input is not valid canonical JSON: '%s'" % self._generator.all())

    __true_regex=re.compile(r'true')
    def _readTrue(self):
        self._generator.read_re(CJsonReader.__true_regex)
        return True

    __false_regex=re.compile(r'false')
    def _readFalse(self):
        self._generator.read_re(CJsonReader.__false_regex)
        return False

    __null_regex=re.compile(r'null')
    def _readNull(self):
        self._generator.read_re(CJsonReader.__null_regex)
        return None

    def _assertNext(self, ch, target):
        if self._generator.next() != ch:
            raise ReadException("Trying to read %s: '%s'" % (target, self._generator.all()))

    __num_regex=re.compile(r'0|(-?[1-9][0-9]*)')
    def _readNumber(self):
        result = self._generator.read_re(CJsonReader.__num_regex)
        peek = self._generator.peek()
        if peek is not None and peek.isdigit():
            raise ReadException("Leading zeros not allowed")
        try:
            return int(result)
        except ValueError:
            raise ReadException("Not a valid JSON number: '%s'" % result)

    __str1_regex=re.compile(r'"((?:[^"\\]+|\\["\\])*)"')
    __str2_regex=re.compile(r'\\(["\\])')
    def _readString(self):
        result = self._generator.read_re(CJsonReader.__str1_regex, 1)
        result = CJsonReader.__str2_regex.sub(r'\1', result)
        return result

    def _hexDigitToInt(self, ch):
        try:
            result = self.hex_digits[ch]
        except KeyError:
            try:
                result = int(ch)
            except ValueError:
                raise ReadException("The character %s is not a lowercase hex digit." % ch)
        return result

    def _readArray(self):
        result = []
        assert self._generator.next() == '['
        done = self._generator.peek() == ']'
        while not done:
            item = self._read()
            result.append(item)
            done = self._generator.peek() == ']'
            if not done:
                ch = self._generator.next()
                if ch != ",":
                    raise ReadException("Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch))
        assert ']' == self._generator.next()
        return result

    def _readObject(self):
        lastkey = None
        result = {}
        assert self._generator.next() == '{'
        done = self._generator.peek() == '}'
        while not done:
            key = self._read()
            if type(key) is not types.StringType and type(key) is not types.UnicodeType:
                raise ReadException("Not a valid JSON object key (should be a string): %s" % key)
            if lastkey is not None and key <= lastkey:
                raise ReadException("Keys are not sorted (not canonical form)")
            else:
                lastkey = key
            ch = self._generator.next()
            if ch != ":":
                raise ReadException("Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch))
            val = self._read()
            result[key] = val
            done = self._generator.peek() == '}'
            if not done:
                ch = self._generator.next()
                if ch != ",":
                    raise ReadException("Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch))
        assert self._generator.next() == "}"
        return result

class CJsonWriter(object):
        
    def write(self, obj):
        results = []
        self._append = lambda s: results.append(s)
        self._write(obj)
        return "".join(results)
    def write_to_file(self, f, obj):
        self._append = lambda s: f.write(s)
        self._write(obj)

    __str_regex=re.compile(r'([^"\\]+)|["\\]')
    def _write(self, obj):
        ty = type(obj)
        if ty is types.DictType:
            n = len(obj)
            self._append("{")
            for k in sorted(obj.keys()):
                if not (type(k) is types.StringType or type(k) is types.UnicodeType):
                    raise WriteException("Keys must be strings.")
                self._write(k)
                self._append(":")
                self._write(obj[k])
                n = n - 1
                if n > 0:
                    self._append(",")
            self._append("}")
        elif ty is types.ListType or ty is types.TupleType:
            n = len(obj)
            self._append("[")
            for item in obj:
                self._write(item)
                n = n - 1
                if n > 0:
                    self._append(",")
            self._append("]")
        elif ty is types.StringType or ty is types.UnicodeType:
            self._append('"')
            if ty is types.UnicodeType:
                try:
                    import unicodedata
                    obj = unicodedata.normalize("NFD", obj).encode('utf-8')
                except ImportError:
                    raise WriteException("Package unicodedata not found: no support for writing unicode string: %s" % obj)
            for m in CJsonWriter.__str_regex.finditer(obj):
                c = m.group()
                if c[0] == "\\" or c[0] == '"':
                    self._append("\\"+c[0])
                else:
                    self._append(c) # no escaping needed for this piece
            self._append('"')
        elif ty is types.IntType or ty is types.LongType:
            self._append(str(obj))
        elif obj is True:
            self._append("true")
        elif obj is False:
            self._append("false")
        elif obj is None:
            self._append("null")
        else:
            raise WriteException("Cannot write in canonical JSON: %s" % repr(obj))

def write(obj):
    """Return a string representing `obj` encoded using canonical JSON."""
    return CJsonWriter().write(obj)

def write_to_file(f, obj):
    """Write the canonical JSON encoding of `obj` to the file-like object
    `f`."""
    return CJsonWriter().write_to_file(f, obj)

def read(s):
    """Read a canonical-JSON-encoded string `s` and return its value as an
    object."""
    return CJsonReader().read(s)

## self-test code
def _selfTest():
    """Self-test code."""
    def expectReadFail(s):
        try:
            read(s)
            raise AssertionError("Expected read of %s to fail." % s)
        except ReadException:
            pass # this is what should happen
    def expectWriteFail(o):
        try:
            s = write(o)
            raise AssertionError("Expected write to fail, but yielded %s." % s)
        except WriteException:
            pass # this is what should happen
    def expectWrite(obj, expect_str):
        assert write(obj) == expect_str
    def expectRead(s, result):
        expectWrite(read(s), write(result))

    # okay, here are the tests
    expectReadFail('')
    
    expectRead('0', 0)
    expectRead('-1', -1)
    expectRead('10', 10)
    expectReadFail('01')
    expectReadFail('-0')
    expectReadFail('00')
    expectReadFail('0x00')
    expectWrite(-0, '0')

    expectWrite({'c':'d','a':'b'}, '{"a":"b","c":"d"}')
    expectRead('[0,1,2,3,4,5]',[0,1,2,3,4,5])

    expectReadFail('{ }')
    expectReadFail('[ ]')
    expectReadFail('0 ')
    expectReadFail('[0,]')

    expectRead('"foo"','foo')
    expectRead('"foo\\"\'\\\\bar"', "foo\"\'\\bar")
    expectRead('"nin\xcc\x83a"', u'ni\xf1a')
    expectWrite('"', '"\\\""')
    expectReadFail('"\\u0000"')
    expectReadFail('"\\x1f"')
    expectReadFail('"""')

    # no floats allowed
    expectWriteFail(1.2)
    # only string keys allowed
    expectWriteFail({1:2})
    
    expectRead('[1,"a",{},[30,null]]',[1,"a",{},[30,None]])

    # don't try to normalize unnormalized UTF-8
    # (from fig 4 of http://www.unicode.org/reports/tr15/)
    expectRead('"\xc5"', '\xc5') # not canonicalized
    expectRead('"\xf4"', '\xf4') # not canonicalized
    # but normalize unicode values written.
    expectWrite(u'\u00C5', '"A\xcc\x8a"')
    expectWrite(u'\u00F4', '"o\xcc\x82"')

    return "All tests passed."

if __name__ == '__main__':
    print _selfTest()
_______________________________________________
Devel mailing list
Devel@lists.laptop.org
http://lists.laptop.org/listinfo/devel

Reply via email to