doc: Add git-cola-1.4.0.4 release notes
[git-cola.git] / jsonpickle / __init__.py
blobbb28a4219d19b2d6d407dbb3ef280b7df0319a5d
1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2008 John Paulett (john -at- 7oars.com)
4 # All rights reserved.
6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution.
9 """Python library for serializing any arbitrary object graph into
10 `JSON <http://www.json.org/>`_. It can take almost any Python object and turn
11 the object into JSON. Additionally, it can reconstitute the object back into
12 Python.
14 >>> import jsonpickle
15 >>> from jsonpickle.tests.classes import Thing
17 Create an object.
19 >>> obj = Thing('A String')
20 >>> print obj.name
21 A String
23 Use jsonpickle to transform the object into a JSON string.
25 >>> pickled = jsonpickle.encode(obj)
26 >>> print pickled
27 {"py/object": "jsonpickle.tests.classes.Thing", "name": "A String", "child": null}
29 Use jsonpickle to recreate a Python object from a JSON string
31 >>> unpickled = jsonpickle.decode(pickled)
32 >>> str(unpickled.name)
33 'A String'
35 .. warning::
37 Loading a JSON string from an untrusted source represents a potential
38 security vulnerability. jsonpickle makes no attempt to sanitize the input.
40 The new object has the same type and data, but essentially is now a copy of
41 the original.
43 >>> obj == unpickled
44 False
45 >>> obj.name == unpickled.name
46 True
47 >>> type(obj) == type(unpickled)
48 True
50 If you will never need to load (regenerate the Python class from JSON), you can
51 pass in the keyword unpicklable=False to prevent extra information from being
52 added to JSON.
54 >>> oneway = jsonpickle.encode(obj, unpicklable=False)
55 >>> print oneway
56 {"name": "A String", "child": null}
58 """
60 from jsonpickle.pickler import Pickler
61 from jsonpickle.unpickler import Unpickler
63 __version__ = '0.2.0'
64 __all__ = ('encode', 'decode')
67 class JSONPluginMgr(object):
68 """The JSONPluginMgr handles encoding and decoding.
70 It tries these modules in this order:
71 cjson, json, simplejson, demjson
73 cjson is the fastest, and is tried first.
74 json comes with python2.6 and is tried second.
75 simplejson is a very popular backend and is tried third.
76 demjson is the most permissive backend and is tried last.
77 """
78 def __init__(self):
79 ## The names of backends that have been successfully imported
80 self._backend_names = []
82 ## A dictionary mapping backend names to encode/decode functions
83 self._encoders = {}
84 self._decoders = {}
86 ## Options to pass to specific encoders
87 self._encoder_options = {}
89 ## The exception class that is thrown when a decoding error occurs
90 self._decoder_exceptions = {}
92 ## Whether we've loaded any backends successfully
93 self._verified = False
95 ## Try loading cjson, simplejson and demjson
96 self.load_backend('cjson', 'encode', 'decode', 'DecodeError')
97 self.load_backend('json', 'dumps', 'loads', ValueError)
98 self.load_backend('simplejson', 'dumps', 'loads', ValueError)
99 self.load_backend('demjson', 'encode', 'decode', 'JSONDecodeError')
101 def _verify(self):
102 """Ensures that we've loaded at least one JSON backend.
104 if self._verified:
105 return
106 raise AssertionError('jsonpickle requires at least one of the '
107 'following:\n'
108 ' cjson, python2.6, simplejson, or demjson')
110 def load_backend(self, name, encode_name, decode_name, decode_exc):
111 """Loads a backend by name.
113 This method loads a backend and sets up references to that
114 backend's encode/decode functions and exception classes.
116 encode_name is the name of the backend's encode method.
117 The method should take an object and return a string.
119 decode_name names the backend's method for the reverse
120 operation -- returning a Python object from a string.
122 decode_exc can be either the name of the exception class
123 used to denote decoding errors, or it can be a direct reference
124 to the appropriate exception class itself. If it is a name,
125 then the assumption is that an exception class of that name
126 can be found in the backend module's namespace.
128 try:
129 ## Load the JSON backend
130 mod = __import__(name)
131 except ImportError:
132 return
134 try:
135 ## Handle submodules, e.g. django.utils.simplejson
136 components = name.split('.')
137 for comp in components[1:]:
138 mod = getattr(mod, comp)
139 except AttributeError:
140 return
142 try:
143 ## Setup the backend's encode/decode methods
144 self._encoders[name] = getattr(mod, encode_name)
145 self._decoders[name] = getattr(mod, decode_name)
146 except AttributeError:
147 self.remove_backend(name)
148 return
150 try:
151 if type(decode_exc) is str:
152 ## This backend's decoder exception is part of the backend
153 self._decoder_exceptions[name] = getattr(mod, decode_exc)
154 else:
155 ## simplejson uses the ValueError exception
156 self._decoder_exceptions[name] = decode_exc
157 except AttributeError:
158 self.remove_backend(name)
159 return
161 ## Setup the default args and kwargs for this encoder
162 self._encoder_options[name] = ([], {})
164 ## Add this backend to the list of candidate backends
165 self._backend_names.append(name)
167 ## Indicate that we successfully loaded a JSON backend
168 self._verified = True
170 def remove_backend(self, name):
171 """Removes all entries for a particular backend.
173 self._encoders.pop(name, None)
174 self._decoders.pop(name, None)
175 self._decoder_exceptions.pop(name, None)
176 self._encoder_options.pop(name, None)
177 if name in self._backend_names:
178 self._backend_names.remove(name)
179 self._verified = bool(self._backend_names)
181 def encode(self, obj):
182 """Attempts to encode an object into JSON.
184 This tries the loaded backends in order and passes along the last
185 exception if no backend is able to encode the object.
187 self._verify()
188 for idx, name in enumerate(self._backend_names):
189 try:
190 optargs, kwargs = self._encoder_options[name]
191 args = (obj,) + tuple(optargs)
192 return self._encoders[name](*args, **kwargs)
193 except:
194 if idx == len(self._backend_names) - 1:
195 raise
197 def decode(self, string):
198 """Attempts to decode an object from a JSON string.
200 This tries the loaded backends in order and passes along the last
201 exception if no backends are able to decode the string.
203 self._verify()
204 for idx, name in enumerate(self._backend_names):
205 try:
206 return self._decoders[name](string)
207 except self._decoder_exceptions[name], e:
208 if idx == len(self._backend_names) - 1:
209 raise e
210 else:
211 pass # and try a more forgiving encoder, e.g. demjson
213 def set_preferred_backend(self, name):
214 """Sets the preferred json backend.
216 If a preferred backend is set then jsonpickle tries to use it
217 before any other backend.
219 For example,
220 set_preferred_backend('simplejson')
222 If the backend is not one of the built-in jsonpickle backends
223 (cjson, json/simplejson, or demjson) then you must load the
224 backend prior to calling set_preferred_backend. An AssertionError
225 exception is raised if the backend has not been loaded.
227 if name in self._backend_names:
228 self._backend_names.remove(name)
229 self._backend_names.insert(0, name)
230 else:
231 errmsg = 'The "%s" backend has not been loaded.' % name
232 raise AssertionError(errmsg)
234 def set_encoder_options(self, name, *args, **kwargs):
235 """Associates encoder-specific options with an encoder.
237 After calling set_encoder_options, any calls to jsonpickle's
238 encode method will pass the supplied args and kwargs along to
239 the appropriate backend's encode method.
241 For example,
242 set_encoder_options('simplejson', sort_keys=True, indent=4)
243 set_encoder_options('demjson', compactly=False)
245 See the appropriate encoder's documentation for details about
246 the supported arguments and keyword arguments.
248 self._encoder_options[name] = (args, kwargs)
250 # Initialize a JSONPluginMgr
251 json = JSONPluginMgr()
253 # Export specific JSONPluginMgr methods into the jsonpickle namespace
254 set_preferred_backend = json.set_preferred_backend
255 set_encoder_options = json.set_encoder_options
256 load_backend = json.load_backend
257 remove_backend = json.remove_backend
260 def encode(value, unpicklable=True, max_depth=None, **kwargs):
261 """Returns a JSON formatted representation of value, a Python object.
263 The keyword argument 'unpicklable' defaults to True.
264 If set to False, the output will not contain the information
265 necessary to turn the JSON data back into Python objects.
267 The keyword argument 'max_depth' defaults to None.
268 If set to a non-negative integer then jsonpickle will not recurse
269 deeper than 'max_depth' steps into the object. Anything deeper
270 than 'max_depth' is represented using a Python repr() of the object.
272 >>> encode('my string')
273 '"my string"'
274 >>> encode(36)
275 '36'
277 >>> encode({'foo': True})
278 '{"foo": true}'
280 >>> encode({'foo': True}, max_depth=0)
281 '"{\\'foo\\': True}"'
283 >>> encode({'foo': True}, max_depth=1)
284 '{"foo": "True"}'
288 j = Pickler(unpicklable=unpicklable,
289 max_depth=max_depth)
290 return json.encode(j.flatten(value))
292 def decode(string):
293 """Converts the JSON string into a Python object.
295 >>> str(decode('"my string"'))
296 'my string'
297 >>> decode('36')
300 j = Unpickler()
301 return j.restore(json.decode(string))