summaryrefslogtreecommitdiff
path: root/anyjson/__init__.py
diff options
context:
space:
mode:
authorRune Halvorsen <runefh@gmail.com>2009-07-22 23:09:58 +0200
committerRune Halvorsen <runefh@gmail.com>2009-07-22 23:09:58 +0200
commit717da58bd5b608817afcc3c5fd40294a4a54baa3 (patch)
treef12da38dd1001ce2e92e92b8b669730bcdedaef9 /anyjson/__init__.py
parente8fcac117741da9752805d0160e3e0190ab98c68 (diff)
downloadanyjson-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__.py141
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)