1
2
3
4
5
6
7
8
9
10
11 import json as _json
12 import re
13 from array import array
14
27
28
30 """
31 Casts all unicode objects as strings. This is necessary until Zope is less
32 stupid.
33 """
37
39 """A simple class that represents a JavaScript literal that should not be JSON encoded."""
42
45
47 """A simple class that represents a JavaScript Regex literal that should not be JSON encoded."""
49 return '/' + self.value + '/'
50
61
63 """A JavaScript encoder based on JSON. It encodes like normal JSON except it passes JavaScript objects un-encoded."""
64
65 _js_start = '__js_start__'
66 _js_end = '__js_end__'
67 _js_re = re.compile(r'\["%s", (.*?), "%s"\]' % (_js_start, _js_end))
68
74
76
77
78 def fix(matchobj):
79 return _json.loads(matchobj.group(1))
80
81 return self._js_re.sub(fix, jsonstr)
82
85
87 """
88 JSONEncoder doesn't allow overriding the encoding of built-in types
89 (in particular strings), and allows specifying an encoding but not
90 a policy for errors when decoding strings to UTF-8. This function
91 replaces all strings in a nested collection with unicode strings
92 with 'replace' as the error policy.
93 """
94 newvalue = value
95 if isinstance(value,str):
96 newvalue = value.decode('utf8', errors)
97 elif isinstance(value, dict):
98 newvalue = {}
99 for k, v in value.iteritems():
100 if isinstance(v, (str,set,list,dict,tuple)):
101 newvalue[k] = _sanitize_value(v)
102 else:
103 newvalue[k] = v
104 elif isinstance(value,(list,tuple)):
105 newvalue = []
106 for v in value:
107 if isinstance(v, (str,set,list,dict,tuple)):
108 newvalue.append(_sanitize_value(v))
109 else:
110 newvalue.append(v)
111 elif isinstance(value,set):
112 newvalue = set()
113 for v in value:
114 if isinstance(v, (str,set,list,dict,tuple)):
115 newvalue.add(_sanitize_value(v))
116 else:
117 newvalue.add(v)
118
119 return newvalue
120
121 -def json(value, **kw):
122 """
123 Serialize C{value} into a JSON string.
124
125 If C{value} is callable, a decorated version of C{value} that serializes its
126 return value will be returned.
127
128 >>> value = (dict(a=1L), u"123", 123)
129 >>> print json(value)
130 [{"a": 1}, "123", 123]
131 >>> @json
132 ... def f():
133 ... return value
134 ...
135 >>> print f()
136 [{"a": 1}, "123", 123]
137 >>> from array import array
138 >>> a1 = array('i', list(range(10)))
139 >>> a2 = array('c', 'XYZZY')
140 >>> a3 = (array('u',[unichr(i) for i in range(250,260)]))
141 >>> [json(s) for s in (a1, a2, a3)]
142 ['[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]', '"XYZZY"', '"\\\\u00fa\\\\u00fb\\\\u00fc\\\\u00fd\\\\u00fe\\\\u00ff\\\\u0100\\\\u0101\\\\u0102\\\\u0103"']
143 >>> json([a1, a2, a3])
144 '[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], "XYZZY", "\\\\u00fa\\\\u00fb\\\\u00fc\\\\u00fd\\\\u00fe\\\\u00ff\\\\u0100\\\\u0101\\\\u0102\\\\u0103"]'
145 >>> json({'properties' : [{ 'key' : 'a1', 'value' : a1 },{ 'key' : 'a2', 'value' : a2 },{ 'key' : 'a3', 'value' : a3 },] })
146 '{"properties": [{"value": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], "key": "a1"}, {"value": "XYZZY", "key": "a2"}, {"value": "\\\\u00fa\\\\u00fb\\\\u00fc\\\\u00fd\\\\u00fe\\\\u00ff\\\\u0100\\\\u0101\\\\u0102\\\\u0103", "key": "a3"}]}'
147
148 @param value: An object to be serialized
149 @type value: dict, list, tuple, str, etc. or callable
150 @return: The JSON representation of C{value} or a decorated function
151 @rtype: str, func
152 """
153 if callable(value):
154
155 def inner(*args, **kwargs):
156 return json(value(*args, **kwargs))
157
158 inner.__name__ = value.__name__
159 inner.__dict__.update(value.__dict__)
160 inner.__doc__ = value.__doc__
161 return inner
162 else:
163
164 try:
165 return _json.dumps(value, cls=ObjectEncoder, **kw)
166 except UnicodeDecodeError:
167 sanitized = _sanitize_value(value)
168 return _json.dumps(sanitized, cls=ObjectEncoder, **kw)
169
171 """A JavaScript encoder based on JSON. It encodes like normal JSON except it passes JavaScript objects un-encoded."""
172 if callable(value):
173
174 def inner(*args, **kwargs):
175 return javascript(value(*args, **kwargs))
176
177 inner.__name__ = value.__name__
178 inner.__dict__.update(value.__dict__)
179 inner.__doc__ = value.__doc__
180 return inner
181 else:
182
183 return _json.dumps(value, cls=JavaScriptEncoder)
184
186 """
187 Create the Python object represented by the JSON string C{value}.
188
189 >>> jsonstr = '[{"a": 1}, "123", 123]'
190 >>> print unjson(jsonstr)
191 [{'a': 1}, '123', 123]
192
193 @param value: A JSON string
194 @type value: str
195 @return: The object represented by C{value}
196 """
197 if 'cls' not in kw:
198 kw['cls'] = StringifyingDecoder
199 return _json.loads(value, **kw)
200