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