Use the indent= parameter of json.dump() or json.dumps() to specify how many spaces to indent by:
>>> import json
>>> your_json = '["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4))
[
"foo",
{
"bar": [
"baz",
null,
1.0,
2
]
}
]
To parse a file, use json.load():
with open('filename.txt', 'r') as handle:
parsed = json.load(handle)
Answer from Blender on Stack OverflowUse the indent= parameter of json.dump() or json.dumps() to specify how many spaces to indent by:
>>> import json
>>> your_json = '["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> parsed = json.loads(your_json)
>>> print(json.dumps(parsed, indent=4))
[
"foo",
{
"bar": [
"baz",
null,
1.0,
2
]
}
]
To parse a file, use json.load():
with open('filename.txt', 'r') as handle:
parsed = json.load(handle)
You can do this on the command line:
python3 -m json.tool some.json
(as already mentioned in the commentaries to the question, thanks to @Kai Petzke for the python3 suggestion).
Actually python is not my favourite tool as far as json processing on the command line is concerned. For simple pretty printing is ok, but if you want to manipulate the json it can become overcomplicated. You'd soon need to write a separate script-file, you could end up with maps whose keys are u"some-key" (python unicode), which makes selecting fields more difficult and doesn't really go in the direction of pretty-printing.
You can also use jq:
jq . some.json
and you get colors as a bonus (and way easier extendability).
Addendum: There is some confusion in the comments about using jq to process large JSON files on the one hand, and having a very large jq program on the other. For pretty-printing a file consisting of a single large JSON entity, the practical limitation is RAM. For pretty-printing a 2GB file consisting of a single array of real-world data, the "maximum resident set size" required for pretty-printing was 5GB (whether using jq 1.5 or 1.6). Note also that jq can be used from within python after pip install jq.
Here is a way to do it with as least amount of modifications as possible:
import json
from json import JSONEncoder
import re
class MarkedList:
_list = None
def __init__(self, l):
self._list = l
z = {
"rows_parsed": [
MarkedList([
"a",
"b",
"c",
"d"
]),
MarkedList([
"e",
"f",
"g",
"i"
]),
]
}
class CustomJSONEncoder(JSONEncoder):
def default(self, o):
if isinstance(o, MarkedList):
return "##<{}>##".format(o._list)
b = json.dumps(z, indent=2, separators=(',', ':'), cls=CustomJSONEncoder)
b = b.replace('"##<', "").replace('>##"', "")
print(b)
Basically the lists that you want formatted in that way you make instance of
MarkedList and they get parsed as strings with hopefully unique enough sequence
that is later stripped from the output of dumps. This is done to eliminate the quotes that are put around a json string.
Another much more efficient way to do it, but a much more ugly one is to monkey patch
json.encoder._make_iterencode._iterencode with something like:
def _iterencode(o, _current_indent_level):
if isinstance(o, str):
yield _encoder(o)
elif o is None:
yield 'null'
elif o is True:
yield 'true'
elif o is False:
yield 'false'
elif isinstance(o, int):
# see comment for int/float in _make_iterencode
yield _intstr(o)
elif isinstance(o, float):
# see comment for int/float in _make_iterencode
yield _floatstr(o)
elif isinstance(o, MarkedList):
yield _my_custom_parsing(o)
elif isinstance(o, (list, tuple)):
yield from _iterencode_list(o, _current_indent_level)
elif isinstance(o, dict):
yield from _iterencode_dict(o, _current_indent_level)
else:
if markers is not None:
markerid = id(o)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = o
o = _default(o)
yield from _iterencode(o, _current_indent_level)
if markers is not None:
del markers[markerid]
I don't see how you could do it in the json.dumps. After a bit of searching I came across a few options: One option would be to do some post-processing with a custom function:
def fix_json_indent(text, indent=3):
space_indent = indent * 4
initial = " " * space_indent
json_output = []
current_level_elems = []
all_entries_at_level = None # holder for consecutive entries at exact space_indent level
for line in text.splitlines():
if line.startswith(initial):
if line[space_indent] == " ":
# line indented further than the level
if all_entries_at_level:
current_level_elems.append(all_entries_at_level)
all_entries_at_level = None
item = line.strip()
current_level_elems.append(item)
if item.endswith(","):
current_level_elems.append(" ")
elif current_level_elems:
# line on the same space_indent level
# no more sublevel_entries
current_level_elems.append(line.strip())
json_output.append("".join(current_level_elems))
current_level_elems = []
else:
# line at the exact space_indent level but no items indented further
if all_entries_at_level:
# last pending item was not the start of a new sublevel_entries.
json_output.append(all_entries_at_level)
all_entries_at_level = line.rstrip()
else:
if all_entries_at_level:
json_output.append(all_entries_at_level)
all_entries_at_level = None
if current_level_elems:
json_output.append("".join(current_level_elems))
json_output.append(line)
return "\n".join(json_output)
Another possibility is a regex but it is quite ugly and depends on the structure of the code you posted:
def fix_json_indent(text):
import re
return re.sub('{"', '{\n"', re.sub('\[\[', '[\n[', re.sub('\]\]', ']\n]', re.sub('}', '\n}', text))))
You should check out pprint, a Python module for Python data-structures. The following code should give you the print you want:
# x -> your json dict
import pprint
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(x)
Ok, coded myself. Some hacks to print \n instead of real linefeed.
def fwriteKeyVals(data, f, indent=0):
if isinstance(data, list):
try:
gotdata = isinstance(data[0], list)
except IndexError:
gotdata = False
if gotdata:
f.write( "\n" + " " * indent + "[" )
for i in range(len(data) ):
if ( i == 0):
f.write( "[" )
else:
f.write( " " * indent + " [" )
for j in range(len(data[0])):
f.write( "%3d" % data[i][j] )
f.write( "," ) if j != len(data[0])-1 else (f.write( "]," ) if i != len(data)-1 else f.write( "]" ))
f.write( "\n" ) if i != len(data)-1 else f.write( "]" )
else:
try:
gotdata = data[0]
except IndexError:
gotdata = 'False'
if gotdata is not 'False':
f.write( " [" )
for i in range(len(data) ):
if isinstance(data[i], Number):
f.write( "%3d" % data[i] )
else:
dataListLf = data[i].split("\n")
dataToWrite = dataListLf[0]
for line in dataListLf[1:]:
dataToWrite += '\\n'+line
f.write( "\"" + dataToWrite + "\"")
f.write( "," ) if i != len(data)-1 else f.write( "]" )
else:
f.write( " [\"\"]" )