fork download
  1. import json
  2. from json.encoder import * # Don't do this though
  3.  
  4.  
  5. def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
  6. _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
  7. ## HACK: hand-optimized bytecode; turn globals into locals
  8. ValueError=ValueError,
  9. basestring=basestring,
  10. dict=dict,
  11. float=float,
  12. id=id,
  13. int=int,
  14. isinstance=isinstance,
  15. list=list,
  16. long=long,
  17. str=str,
  18. tuple=tuple,
  19. ):
  20.  
  21. if _indent is not None and not isinstance(_indent, str):
  22. _indent = ' ' * _indent
  23.  
  24. def _iterencode_list(lst, _current_indent_level):
  25. if not lst:
  26. yield '[]'
  27. return
  28. if markers is not None:
  29. markerid = id(lst)
  30. if markerid in markers:
  31. raise ValueError("Circular reference detected")
  32. markers[markerid] = lst
  33. buf = '['
  34. if _indent is not None:
  35. _current_indent_level += 1
  36. newline_indent = '\n' + _indent * _current_indent_level
  37. separator = _item_separator + newline_indent
  38. buf += newline_indent
  39. else:
  40. newline_indent = None
  41. separator = _item_separator
  42. first = True
  43. for value in lst:
  44. if first:
  45. first = False
  46. else:
  47. buf = separator
  48. if isinstance(value, basestring):
  49. yield buf + _encoder(value)
  50. elif value is None:
  51. yield buf + 'null'
  52. elif value is True:
  53. yield buf + 'true'
  54. elif value is False:
  55. yield buf + 'false'
  56. elif isinstance(value, (int, long)):
  57. yield buf + str(value)
  58. elif isinstance(value, float):
  59. yield buf + _floatstr(value)
  60. else:
  61. yield buf
  62. if isinstance(value, (list, tuple)):
  63. chunks = _iterencode_list(value, _current_indent_level)
  64. elif isinstance(value, dict):
  65. chunks = _iterencode_dict(value, _current_indent_level)
  66. else:
  67. chunks = _iterencode(value, _current_indent_level)
  68. for chunk in chunks:
  69. yield chunk
  70. if newline_indent is not None:
  71. _current_indent_level -= 1
  72. yield '\n' + _indent * _current_indent_level
  73. yield ']'
  74. if markers is not None:
  75. del markers[markerid]
  76.  
  77. def _iterencode_dict(dct, _current_indent_level):
  78. if not dct:
  79. yield '{}'
  80. return
  81. if markers is not None:
  82. markerid = id(dct)
  83. if markerid in markers:
  84. raise ValueError("Circular reference detected")
  85. markers[markerid] = dct
  86. yield '{'
  87. if _indent is not None:
  88. _current_indent_level += 1
  89. newline_indent = '\n' + _indent * _current_indent_level
  90. item_separator = _item_separator + newline_indent
  91. yield newline_indent
  92. else:
  93. newline_indent = None
  94. item_separator = _item_separator
  95. first = True
  96. if _sort_keys:
  97. items = sorted(dct.items(), key=lambda kv: kv[0])
  98. else:
  99. items = dct.iteritems()
  100. for key, value in items:
  101. if isinstance(key, basestring):
  102. pass
  103. # JavaScript is weakly typed for these, so it makes sense to
  104. # also allow them. Many encoders seem to do something like this.
  105. elif isinstance(key, float):
  106. key = _floatstr(key)
  107. elif key is True:
  108. key = 'true'
  109. elif key is False:
  110. key = 'false'
  111. elif key is None:
  112. key = 'null'
  113. elif isinstance(key, (int, long)):
  114. key = str(key)
  115. elif _skipkeys:
  116. continue
  117. else:
  118. raise TypeError("key " + repr(key) + " is not a string")
  119. if first:
  120. first = False
  121. else:
  122. yield item_separator
  123. yield _encoder(key)
  124. yield _key_separator
  125. if isinstance(value, basestring):
  126. yield _encoder(value)
  127. elif value is None:
  128. yield 'null'
  129. elif value is True:
  130. yield 'true'
  131. elif value is False:
  132. yield 'false'
  133. elif isinstance(value, (int, long)):
  134. yield str(value)
  135. elif isinstance(value, float):
  136. yield _floatstr(value)
  137. else:
  138. if isinstance(value, (list, tuple)):
  139. chunks = _iterencode_list(value, _current_indent_level)
  140. elif isinstance(value, dict):
  141. chunks = _iterencode_dict(value, _current_indent_level)
  142. else:
  143. chunks = _iterencode(value, _current_indent_level)
  144. for chunk in chunks:
  145. yield chunk
  146. if newline_indent is not None:
  147. _current_indent_level -= 1
  148. yield '\n' + _indent * _current_indent_level
  149. yield '}'
  150. if markers is not None:
  151. del markers[markerid]
  152.  
  153. def _iterencode(o, _current_indent_level):
  154. if isinstance(o, basestring):
  155. yield _encoder(o)
  156. elif o is None:
  157. yield 'null'
  158. elif o is True:
  159. yield 'true'
  160. elif o is False:
  161. yield 'false'
  162. elif isinstance(o, (int, long)):
  163. yield str(o)
  164. elif isinstance(o, float):
  165. yield _floatstr(o)
  166. elif isinstance(o, (list, tuple)):
  167. for chunk in _iterencode_list(o, _current_indent_level):
  168. yield chunk
  169. elif isinstance(o, dict):
  170. for chunk in _iterencode_dict(o, _current_indent_level):
  171. yield chunk
  172. else:
  173. if markers is not None:
  174. markerid = id(o)
  175. if markerid in markers:
  176. raise ValueError("Circular reference detected")
  177. markers[markerid] = o
  178. o = _default(o)
  179. for chunk in _iterencode(o, _current_indent_level):
  180. yield chunk
  181. if markers is not None:
  182. del markers[markerid]
  183.  
  184. return _iterencode
  185.  
  186.  
  187. class CustomJSONEncoder(JSONEncoder):
  188. def iterencode(self, o, _one_shot=False):
  189. """Encode the given object and yield each string
  190. representation as available.
  191.  
  192. For example::
  193.  
  194. for chunk in JSONEncoder().iterencode(bigobject):
  195. mysocket.write(chunk)
  196.  
  197. """
  198. if self.check_circular:
  199. markers = {}
  200. else:
  201. markers = None
  202. if self.ensure_ascii:
  203. _encoder = encode_basestring_ascii
  204. else:
  205. _encoder = encode_basestring
  206. if self.encoding != 'utf-8':
  207. def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
  208. if isinstance(o, str):
  209. o = o.decode(_encoding)
  210. return _orig_encoder(o)
  211.  
  212. def floatstr(o, allow_nan=self.allow_nan,
  213. _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
  214. # Check for specials. Note that this type of test is processor
  215. # and/or platform-specific, so do tests which don't depend on the
  216. # internals.
  217.  
  218. if o != o:
  219. text = 'NaN'
  220. elif o == _inf:
  221. text = 'Infinity'
  222. elif o == _neginf:
  223. text = '-Infinity'
  224. else:
  225. return _repr(o)
  226.  
  227. if not allow_nan:
  228. raise ValueError(
  229. "Out of range float values are not JSON compliant: " +
  230. repr(o))
  231.  
  232. return text
  233.  
  234.  
  235. if (_one_shot and c_make_encoder is not None
  236. and self.indent is None and not self.sort_keys):
  237. _iterencode = c_make_encoder(
  238. markers, self.default, _encoder, self.indent,
  239. self.key_separator, self.item_separator, self.sort_keys,
  240. self.skipkeys, self.allow_nan)
  241. else:
  242. _iterencode = _make_iterencode(
  243. markers, self.default, _encoder, self.indent, floatstr,
  244. self.key_separator, self.item_separator, self.sort_keys,
  245. self.skipkeys, _one_shot)
  246.  
  247. return _iterencode(o, 0)
  248.  
  249. data = {'a': {'b': {'c': 1}}}
  250. print repr(json.dumps(data, cls=CustomJSONEncoder, indent='\t'))
Success #stdin #stdout 0s 25552KB
stdin
Standard input is empty
stdout
'{\n\t"a": {\n\t\t"b": {\n\t\t\t"c": 1\n\t\t}\n\t}\n}'