diff options
author | Rune Halvorsen <runefh@gmail.com> | 2009-07-22 23:09:58 +0200 |
---|---|---|
committer | Rune Halvorsen <runefh@gmail.com> | 2009-07-22 23:09:58 +0200 |
commit | 717da58bd5b608817afcc3c5fd40294a4a54baa3 (patch) | |
tree | f12da38dd1001ce2e92e92b8b669730bcdedaef9 /anyjson/__init__.py | |
parent | e8fcac117741da9752805d0160e3e0190ab98c68 (diff) | |
download | anyjson-717da58bd5b608817afcc3c5fd40294a4a54baa3.tar.gz |
Created a package rather than a module, so the metadata can live separately.
Diffstat (limited to 'anyjson/__init__.py')
-rw-r--r-- | anyjson/__init__.py | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/anyjson/__init__.py b/anyjson/__init__.py new file mode 100644 index 0000000..7578c61 --- /dev/null +++ b/anyjson/__init__.py @@ -0,0 +1,141 @@ +""" +Wraps the best available JSON implementation available in a common interface +""" + +__version__ = "0.2.1" +__author__ = "Rune Halvorsen <runefh@gmail.com>" +__homepage__ = "http://bitbucket.org/runeh/anyjson/" +__docformat__ = "restructuredtext" + +""" + +.. function:: serialize(obj) + + Serialize the object to JSON. + +.. function:: deserialize(str) + + Deserialize JSON-encoded object to a Python object. + +.. function:: force_implementation(name) + + Load a specific json module. This is useful for testing and not much else + +.. attribute:: implementation + + The json implementation object. This is probably not useful to you, + except to get the name of the implementation in use. The name is + available through `implementation.name`. +""" + +import sys + +implementation = None + +""" +.. data:: _modules + + List of known json modules, and the names of their serialize/unserialize + methods, as well as the exception they throw. Exception can be either + an exception class or a string. +""" +_modules = [("cjson", "encode", "EncodeError", "decode", "DecodeError"), + ("jsonlib2", "write", "WriteError", "read", "ReadError"), + ("jsonlib", "write", "WriteError", "read", "ReadError"), + ("simplejson", "dumps", TypeError, "loads", ValueError), + ("json", "dumps", TypeError, "loads", ValueError), + ("django.utils.simplejson", "dumps", TypeError, "loads", + ValueError)] +_fields = ("modname", "encoder", "encerror", "decoder", "decerror") + + +class _JsonImplementation(object): + """Incapsulates a JSON implementation""" + + def __init__(self, modspec): + modinfo = dict(zip(_fields, modspec)) + + # No try block. We want importerror to end up at caller + module = self._attempt_load(modinfo["modname"]) + + self.implementation = modinfo["modname"] + self._encode = getattr(module, modinfo["encoder"]) + self._decode = getattr(module, modinfo["decoder"]) + self._encode_error = modinfo["encerror"] + self._decode_error = modinfo["decerror"] + + if isinstance(modinfo["encerror"], basestring): + self._encode_error = getattr(module, modinfo["encerror"]) + if isinstance(modinfo["decerror"], basestring): + self._decode_error = getattr(module, modinfo["decerror"]) + + self.name = modinfo["modname"] + + def _attempt_load(self, modname): + """Attempt to load module name modname, returning it on success, + throwing ImportError if module couldn't be imported""" + __import__(modname) + return sys.modules[modname] + + def serialize(self, data): + """Serialize the datastructure to json. Returns a string. Raises + TypeError if the object could not be serialized.""" + try: + return self._encode(data) + except self._encode_error, exc: + raise TypeError(*exc.args) + + def deserialize(self, s): + """deserialize the string to python data types. Raises + ValueError if the string vould not be parsed.""" + try: + return self._decode(s) + except self._decode_error, exc: + raise ValueError(*exc.args) + + +def force_implementation(modname): + """Forces anyjson to use a specific json module if it's available""" + global implementation + for name, spec in [(e[0], e) for e in _modules]: + if name == modname: + implementation = _JsonImplementation(spec) + return + raise ImportError("No module named: %s" % modname) + + + +def main(): + installed = [] + for modspec in _modules: + try: + __import__(modspec[0]) + installed.append(modspec[0]) + except ImportError: + pass + + if installed: + print "Supported JSON modules found:", ", ".join(installed) + return 0 + else: + print "No supported JSON modules found" + return 1 + +if __name__ == "__main__": + # If run as a script, we simply print what is installed that we support. + # We do NOT try to load a compatible module because that may throw an + # exception, which renders the package uninstallable with easy_install + # (It trys to execfile the script when installing, to make sure it works) + sys.exit(main()) +else: + for modspec in _modules: + try: + implementation = _JsonImplementation(modspec) + break + except ImportError: + pass + else: + raise ImportError("No supported JSON module found") + + serialize = lambda value: implementation.serialize(value) + deserialize = lambda value: implementation.deserialize(value) |