106 lines
3.0 KiB
Python
106 lines
3.0 KiB
Python
#!/usr/bin/env python
|
|
# pylint: disable=W0212
|
|
|
|
import codecs
|
|
from collections import OrderedDict
|
|
import json
|
|
import os
|
|
|
|
import six
|
|
|
|
|
|
def to_json(self, path, key=None, newline=False, indent=None, **kwargs):
|
|
"""
|
|
Write this table to a JSON file or file-like object.
|
|
|
|
:code:`kwargs` will be passed through to the JSON encoder.
|
|
|
|
:param path:
|
|
File path or file-like object to write to.
|
|
:param key:
|
|
If specified, JSON will be output as an hash instead of a list. May
|
|
be either the name of a column from the this table containing
|
|
unique values or a :class:`function` that takes a row and returns
|
|
a unique value.
|
|
:param newline:
|
|
If `True`, output will be in the form of "newline-delimited JSON".
|
|
:param indent:
|
|
If specified, the number of spaces to indent the JSON for
|
|
formatting.
|
|
"""
|
|
if key is not None and newline:
|
|
raise ValueError('key and newline may not be specified together.')
|
|
|
|
if newline and indent is not None:
|
|
raise ValueError('newline and indent may not be specified together.')
|
|
|
|
key_is_row_function = hasattr(key, '__call__')
|
|
|
|
json_kwargs = {
|
|
'ensure_ascii': False,
|
|
'indent': indent
|
|
}
|
|
|
|
if six.PY2:
|
|
json_kwargs['encoding'] = 'utf-8'
|
|
|
|
# Pass remaining kwargs through to JSON encoder
|
|
json_kwargs.update(kwargs)
|
|
|
|
json_funcs = [c.jsonify for c in self._column_types]
|
|
|
|
close = True
|
|
f = None
|
|
|
|
try:
|
|
if hasattr(path, 'write'):
|
|
f = path
|
|
close = False
|
|
else:
|
|
if os.path.dirname(path) and not os.path.exists(os.path.dirname(path)):
|
|
os.makedirs(os.path.dirname(path))
|
|
f = open(path, 'w')
|
|
|
|
if six.PY2:
|
|
f = codecs.getwriter('utf-8')(f)
|
|
|
|
def dump_json(data):
|
|
json.dump(data, f, **json_kwargs)
|
|
|
|
if newline:
|
|
f.write('\n')
|
|
|
|
# Keyed
|
|
if key is not None:
|
|
output = OrderedDict()
|
|
|
|
for row in self._rows:
|
|
if key_is_row_function:
|
|
k = key(row)
|
|
else:
|
|
k = str(row[key]) if six.PY3 else unicode(row[key])
|
|
|
|
if k in output:
|
|
raise ValueError('Value %s is not unique in the key column.' % six.text_type(k))
|
|
|
|
values = tuple(json_funcs[i](d) for i, d in enumerate(row))
|
|
output[k] = OrderedDict(zip(row.keys(), values))
|
|
dump_json(output)
|
|
# Newline-delimited
|
|
elif newline:
|
|
for row in self._rows:
|
|
values = tuple(json_funcs[i](d) for i, d in enumerate(row))
|
|
dump_json(OrderedDict(zip(row.keys(), values)))
|
|
# Normal
|
|
else:
|
|
output = []
|
|
|
|
for row in self._rows:
|
|
values = tuple(json_funcs[i](d) for i, d in enumerate(row))
|
|
output.append(OrderedDict(zip(row.keys(), values)))
|
|
|
|
dump_json(output)
|
|
finally:
|
|
if close and f is not None:
|
|
f.close()
|