How to prettyprint a JSON file?
Asked Answered
H

15

1944

How do I pretty-print a JSON file in Python?

Hoagy answered 17/10, 2012 at 21:38 Comment(0)
I
2936

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)
Intercalary answered 17/10, 2012 at 21:54 Comment(9)
For simple pretty-printing this also works without explicit parsing: print json.dumps(your_json_string, indent=4)Retrospective
Without the indent, you just get a single line of ugly text, which is why I came here.Andrel
This is similar to JavaScript var str = JSON.stringify(obj, null, 4); as discussed here #4811341Chiang
@Peterino, it is not working without explicit parsing. It prints an escaped lineWorldling
In JS tool prettier, it will not add 'line break' if the line width less than 80. I am looking for it.Henson
@PeterlitsZo did you find a way to use line wrap 80 for example not to make it look this silly?Goatsucker
@Goatsucker Sorry but no. Do you think it will be good if I write a tool for it? I want to find a tool but I can't.Henson
Yea in my case I would really like a tool that would take a line length as option and then tries to fit more on one line. Kinda tricky though, because if you have {"a": 1, "b": 2, "c"3} maybe because it is so short it would still be better spread out over multiple lines?Goatsucker
How to do this when the objects are unserializable? Like just print its to string.Wouldst
L
474

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.

Luscious answered 26/8, 2015 at 13:42 Comment(10)
JQ is great but there is a max limit so its useless for large files. (i.e. blows up handling a 1.15mb file) github.com/stedolan/jq/issues/1041Ornie
yeah, man, definitely, if you are writing jq filters with more than 10K lines of code I think you're trying something like going to mars with a bicycle.Luscious
lol :D @gismo-ranas The json.tool version piped to a file works really really well on large files; and is stupidly fast. I like JQ but formatting anything beyond a small payload (which you could do in most text editors) is beyond its reach :) Random addition: json-generator.com is a neat tool to make test dataOrnie
or just: jq '' < some.jsonWickham
I don't think that Python's json lib will output the u"some-key" with the uPolypropylene
Plus with curl -s option you can hide sometime useless speed statistic.Prudery
Actually I strongly recommend using python3 -m json.tool <IN >OUT, as this keeps the original order of the fields in JSON dicts. The python interpreter version 2 sorts the fields in alphabetically ascending order, which often is not, what you want.Darindaring
It's worth noting that python -m json.tool does work, though, and is better than nothing. I know it's 2019 already, but there are still plenty of systems around that don't have python3 installed!Shellans
Also, note that there is no need for the shell file redirections: python3 -m json.tool in_file [out_file] works directly (I updated the answer).Accelerate
Unfortunately, python3 kills my non-ASCII characters, while jq handles them fine. Too bad python3 still cannot handle UTF-8 out of the box.Rupp
B
150

After reading the data with the json standard library module, use the pprint standard library module to display the parsed data. Example:

import json
import pprint

json_data = None
with open('file_name.txt', 'r') as f:
    data = f.read()
    json_data = json.loads(data)

# print json to screen with human-friendly formatting
pprint.pprint(json_data, compact=True)

# write json to file with human-friendly formatting
pretty_json_str = pprint.pformat(json_data, compact=True).replace("'",'"')

with open('file_name.json', 'w') as f:
    f.write(pretty_json_str)

The default indent is 1, so you may want to specify your own.

By default, pprint will output lists like this:

'not compact': ['pprint',
                'will',
                'output',
                'lists',
                'like',
                'this'],

And that is no better than json.dump() or json.dumps() with an indent specified.

With compact=True, pprint will output lists something like this:

'compact': ['pprint', 'with compact=True', 'will', 'output',
            'lists', 'like', 'this'],

Note that you can specify where it will wrap with the width argument.

It is necessary to replace 'single quotes' with 'double quotes' in the string returned by pprint.pformat(), because single quotes are not valid json. When you look at the file in your text editor, it may be unable to highlight the json properly.

In any case, you may want to save it as valid json, so that you can as a human can simply read your json files comfortably, if it is not more important that they are formatted without spacing so they can be computer-processed with blinding speed.

Ultimately, the output will look like this:

{'address': {'city': 'New York',
             'postalCode': '10021-3100',
             'state': 'NY',
             'streetAddress': '21 2nd Street'},
 'age': 27,
 'children': [],
 'firstName': 'John',
 'isAlive': True,
 'lastName': 'Smith'}
Bouquet answered 5/1, 2018 at 10:12 Comment(6)
Problem with this is that pprint will use single and double quotes interchangably, but json requires double quotes only, so your pprinted json may no longer parse as valid json.Spermatic
Yes, but it's only to output a json file. Not to take the output and write it again in a file.Bouquet
question specifically says to pretty print a json file, not a python representation of a json fileLennon
@DanielFarrell You are right. Thanks. I updated my answer.Bouquet
This solution has so many issues I can't even start. There's zero guarantee to be valid JSON, in fact, very often it won't be valid at all. Not only it will mix up the quotes all over, but also pprint will output many string representations that only make sense to Python. None, datetime, all sorts of objects, even when they have well defined ways to be JSON serializable. Replacing the single to double quotes only makes it worse, it will potentially not even be valid Python anymore, all you need is a double quote in any string.Joelie
It's not my job as an editor to correct the technical details, but simply swapping single quotes for double quotes is definitely not sufficient to turn pprint.pformat output (just like repr output) into valid JSON, even if the data originally came from JSON. Trivial example: round-tripping the valid file contents "\"" (representing, in JSON, a string containing a backslash) will produce """ (which is neither valid JSON nor a valid Python literal). Round-tripping the valid file contents null will produce a file containing None.Ninebark
S
63

Pygmentize is a powerful tool for coloring the output of terminal commands.

Here is an example of using it to add syntax highlighting to the json.tool output:

echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l json

The result will look like:

demo

In a previous Stack Overflow answer, I show in detail how to install and use pygmentize.

Scincoid answered 27/8, 2015 at 10:30 Comment(2)
In your example -g is not actually working ;) Since input comes from stdin, pygmentize is not able to make a good guess. You need to specify lexer explicitly: echo '{"foo": "bar"}' | python -m json.tool | pygmentize -l jsonAncelin
@DenisTheMenace It used to work in 2015 when I created this example image. It doesn't seem to be working now on my system as well.Scincoid
P
47

Use this function and don't sweat having to remember if your JSON is a str or dict again - just look at the pretty print:

import json

def pp_json(json_thing, sort=True, indents=4):
    if type(json_thing) is str:
        print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents))
    else:
        print(json.dumps(json_thing, sort_keys=sort, indent=indents))
    return None

pp_json(your_json_string_or_dict)
Pilothouse answered 10/6, 2016 at 21:25 Comment(3)
This seems like just putting a nice interface on existing answers and not really engaging with the substance of the question. The key point here is the use of the indent keyword parameter, which is already well covered. Aside from that, it's valid for a JSON document to represent a single string. Determining which processing to use with the input should be the programmer's responsiblity, from applying logical reasoning - while Python is designed to allow this kind of flexibility, doing explicit type checking and coercion is generally discouraged.Ninebark
The people just want to inspect their JSON, my dude.Pilothouse
This is by far the best solution! jq is great for command line, but this is the best programmatic solution. Should be the top answer now.Mcgough
J
24

Use pprint: https://docs.python.org/3.6/library/pprint.html

import pprint
pprint.pprint(json)

print() compared to pprint.pprint()

print(json)
{'feed': {'title': 'W3Schools Home Page', 'title_detail': {'type': 'text/plain', 'language': None, 'base': '', 'value': 'W3Schools Home Page'}, 'links': [{'rel': 'alternate', 'type': 'text/html', 'href': 'https://www.w3schools.com'}], 'link': 'https://www.w3schools.com', 'subtitle': 'Free web building tutorials', 'subtitle_detail': {'type': 'text/html', 'language': None, 'base': '', 'value': 'Free web building tutorials'}}, 'entries': [], 'bozo': 0, 'encoding': 'utf-8', 'version': 'rss20', 'namespaces': {}}

pprint.pprint(json)
{'bozo': 0,
 'encoding': 'utf-8',
 'entries': [],
 'feed': {'link': 'https://www.w3schools.com',
          'links': [{'href': 'https://www.w3schools.com',
                     'rel': 'alternate',
                     'type': 'text/html'}],
          'subtitle': 'Free web building tutorials',
          'subtitle_detail': {'base': '',
                              'language': None,
                              'type': 'text/html',
                              'value': 'Free web building tutorials'},
          'title': 'W3Schools Home Page',
          'title_detail': {'base': '',
                           'language': None,
                           'type': 'text/plain',
                           'value': 'W3Schools Home Page'}},
 'namespaces': {},
 'version': 'rss20'}
Journalism answered 9/4, 2019 at 18:27 Comment(5)
pprint does not produce a valid JSON document.Meit
@Meit what does that mean and why does that matter?Tachycardia
@CharlieParker I expect they meant that knowing you have a valid JSON document is pretty useful. Sure, you can use the json module to work with the data and dictionary keys work the same with double- or single-quoted strings, but some tools, e.g. Postman and JSON Editor Online, both expect keys and values to be double-quoted (as per the JSON spec). In any case, json.org specifies the use of double quotes, which pprint doesn't produce. E.g. pprint.pprint({"name": "Jane"}) produces {'name': 'Jane'}.Selfinduction
@CharlieParker an example would be the 'language': None, in the result above, which should be "language": null. Note the null and the double quotes. What you do is pretty-printing a Python object.Rigmarole
Yes, that's what I meant. Thanks for clarifying. :-)Meit
L
21

To be able to pretty print from the command line and be able to have control over the indentation etc. you can set up an alias similar to this:

alias jsonpp="python -c 'import sys, json; print json.dumps(json.load(sys.stdin), sort_keys=True, indent=2)'"

And then use the alias in one of these ways:

cat myfile.json | jsonpp
jsonpp < myfile.json
Legist answered 28/3, 2017 at 14:58 Comment(1)
The json module provides json.tool explicitly to avoid the need for this kind of thing.Ninebark
P
12
def saveJson(date,fileToSave):
    with open(fileToSave, 'w+') as fileToSave:
        json.dump(date, fileToSave, ensure_ascii=True, indent=4, sort_keys=True)

It works to display or save it to a file.

Perreault answered 11/10, 2019 at 15:8 Comment(1)
This seems entirely redundant with the top answers.Ninebark
H
10

You could try pprintjson.


Installation

$ pip3 install pprintjson

Usage

Pretty print JSON from a file using the pprintjson CLI.

$ pprintjson "./path/to/file.json"

Pretty print JSON from a stdin using the pprintjson CLI.

$ echo '{ "a": 1, "b": "string", "c": true }' | pprintjson

Pretty print JSON from a string using the pprintjson CLI.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }'

Pretty print JSON from a string with an indent of 1.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -i 1

Pretty print JSON from a string and save output to a file output.json.

$ pprintjson -c '{ "a": 1, "b": "string", "c": true }' -o ./output.json

Output

enter image description here

Heartbeat answered 2/10, 2019 at 5:9 Comment(2)
how is your soln different from import pprint pprint.pprint(json)?Tachycardia
@CharlieParker I think it produces a valid json document, as opposed to pprint which uses single-quotes instead of double-quotesDoublefaced
N
9

Here's a simple example of pretty printing JSON to the console in a nice way in Python, without requiring the JSON to be on your computer as a local file:

import pprint
import json 
from urllib.request import urlopen # (Only used to get this example)

# Getting a JSON example for this example 
r = urlopen("https://mdn.github.io/fetch-examples/fetch-json/products.json")
text = r.read() 

# To print it
pprint.pprint(json.loads(text))
Nineteen answered 23/1, 2018 at 8:19 Comment(2)
I get the following error message in Python 3: "TypeError: the JSON object must be str, not 'bytes'"Knowles
"without requiring the JSON to be on your computer as a local file: " - the question explicitly asked about a file, though. While it could potentially be useful to others to show how to grab the data from an Internet source, that is a separate problem pertaining to a separate question. (If someone had asked how to download a JSON file and pretty-print it, that would have been closed for lack of focus; it's blatantly two questions in one.) As it happens, that other question is already very well covered.Ninebark
F
8

TL;DR: many ways, also consider print(yaml.dump(j, sort_keys=False))

For most uses, indent should do it:

print(json.dumps(parsed, indent=2))

A Json structure is basically tree structure. While trying to find something fancier, I came across this nice paper depicting other forms of nice trees that might be interesting: https://blog.ouseful.info/2021/07/13/exploring-the-hierarchical-structure-of-dataframes-and-csv-data/.

It has some interactive trees and even comes with some code including this collapsing tree from so: enter image description here

Other samples include using plotly Here is the code example from plotly:

import plotly.express as px
fig = px.treemap(
    names = ["Eve","Cain", "Seth", "Enos", "Noam", "Abel", "Awan", "Enoch", "Azura"],
    parents = ["", "Eve", "Eve", "Seth", "Seth", "Eve", "Eve", "Awan", "Eve"]
)
fig.update_traces(root_color="lightgrey")
fig.update_layout(margin = dict(t=50, l=25, r=25, b=25))
fig.show()

enter image description here enter image description here

And using treelib. On that note, This github also provides nice visualizations. Here is one example using treelib:

#%pip install treelib
from treelib import Tree

country_tree = Tree()
# Create a root node
country_tree.create_node("Country", "countries")

# Group by country
for country, regions in wards_df.head(5).groupby(["CTRY17NM", "CTRY17CD"]):
    # Generate a node for each country
    country_tree.create_node(country[0], country[1], parent="countries")
    # Group by region
    for region, las in regions.groupby(["GOR10NM", "GOR10CD"]):
        # Generate a node for each region
        country_tree.create_node(region[0], region[1], parent=country[1])
        # Group by local authority
        for la, wards in las.groupby(['LAD17NM', 'LAD17CD']):
            # Create a node for each local authority
            country_tree.create_node(la[0], la[1], parent=region[1])
            for ward, _ in wards.groupby(['WD17NM', 'WD17CD']):
                # Create a leaf node for each ward
                country_tree.create_node(ward[0], ward[1], parent=la[1])

# Output the hierarchical data
country_tree.show()

enter image description here

I have, based on this, created a function to convert json to a tree:

from treelib import Node, Tree, node

def create_node(tree, s, counter_byref, verbose, parent_id=None):
    node_id = counter_byref[0]
    if verbose:
        print(f"tree.create_node({s}, {node_id}, parent={parent_id})")
    tree.create_node(s, node_id, parent=parent_id)
    counter_byref[0] += 1
    return node_id

def to_compact_string(o):
    if type(o) == dict:
        if len(o)>1:
            raise Exception()
        k,v =next(iter(o.items()))
        return f'{k}:{to_compact_string(v)}'
    elif type(o) == list:
        if len(o)>1:
            raise Exception()
        return f'[{to_compact_string(next(iter(o)))}]'
    else:
        return str(o)

def to_compact(tree, o, counter_byref, verbose, parent_id):
    try:
        s = to_compact_string(o)
        if verbose:
            print(f"# to_compact({o}) ==> [{s}]")
        create_node(tree, s, counter_byref, verbose, parent_id=parent_id)
        return True
    except:
        return False

def json_2_tree(o , parent_id=None, tree=None, counter_byref=[0], verbose=False, compact_single_dict=False, listsNodeSymbol='+'):
    if tree is None:
        tree = Tree()
        parent_id = create_node(tree, '+', counter_byref, verbose)
    if compact_single_dict and to_compact(tree, o, counter_byref, verbose, parent_id):
        # no need to do more, inserted as a single node
        pass
    elif type(o) == dict:
        for k,v in o.items():
            if compact_single_dict and to_compact(tree, {k:v}, counter_byref, verbose, parent_id):
                # no need to do more, inserted as a single node
                continue
            key_nd_id = create_node(tree, str(k), counter_byref, verbose, parent_id=parent_id)
            if verbose:
                print(f"# json_2_tree({v})")
            json_2_tree(v , parent_id=key_nd_id, tree=tree, counter_byref=counter_byref, verbose=verbose, listsNodeSymbol=listsNodeSymbol, compact_single_dict=compact_single_dict)
    elif type(o) == list:
        if listsNodeSymbol is not None:
            parent_id = create_node(tree, listsNodeSymbol, counter_byref, verbose, parent_id=parent_id)
        for i in o:
            if compact_single_dict and to_compact(tree, i, counter_byref, verbose, parent_id):
                # no need to do more, inserted as a single node
                continue
            if verbose:
                print(f"# json_2_tree({i})")
            json_2_tree(i , parent_id=parent_id, tree=tree, counter_byref=counter_byref, verbose=verbose,listsNodeSymbol=listsNodeSymbol, compact_single_dict=compact_single_dict)
    else: #node
        create_node(tree, str(o), counter_byref, verbose, parent_id=parent_id)
    return tree

Then for example:

import json
j = json.loads('{"2": 3, "4": [5, 6], "7": {"8": 9}}')
json_2_tree(j ,verbose=False,listsNodeSymbol='+' ).show()  

gives:

+
├── 2
│   └── 3
├── 4
│   └── +
│       ├── 5
│       └── 6
└── 7
    └── 8
        └── 9

While

json_2_tree(j ,listsNodeSymbol=None, verbose=False ).show()  
+
├── 2
│   └── 3
├── 4
│   ├── 5
│   └── 6
└── 7
    └── 8
        └── 9

And

json_2_tree(j ,compact_single_dict=True,listsNodeSymbol=None).show() 
+
├── 2:3
├── 4
│   ├── 5
│   └── 6
└── 7:8:9

As you see, there are different trees one can make depending on how explicit vs. compact he wants to be. One of my favorites, and one of the most compact ones might be using yaml:

import yaml
j = json.loads('{"2": "3", "4": ["5", "6"], "7": {"8": "9"}}')
print(yaml.dump(j, sort_keys=False))

Gives the compact and unambiguous:

'2': '3'
'4':
- '5'
- '6'
'7':
  '8': '9'
Fiddling answered 3/12, 2022 at 8:42 Comment(0)
J
7

A very simple way is using rich. with this method you can also highlight the json

This method reads data from a json file called config.json

from rich import print_json

setup_type = open('config.json')
data = json.load(setup_type)
print_json(data=data)

The Final Output will look like this. enter image description here

Jacquelynnjacquenetta answered 6/1, 2023 at 17:44 Comment(2)
Could you provide what the output would look like?Lind
Ive edited the answer to inclue the output image.Jacquelynnjacquenetta
S
4

I think that's better to parse the json before, to avoid errors:

def format_response(response):
    try:
        parsed = json.loads(response.text)
    except JSONDecodeError:
        return response.text
    return json.dumps(parsed, ensure_ascii=True, indent=4)
Shalandashale answered 26/4, 2019 at 7:24 Comment(0)
S
3

I had a similar requirement to dump the contents of json file for logging, something quick and easy:

print(json.dumps(json.load(open(os.path.join('<myPath>', '<myjson>'), "r")), indent = 4 ))

if you use it often then put it in a function:

def pp_json_file(path, file):
    print(json.dumps(json.load(open(os.path.join(path, file), "r")), indent = 4))
Sediment answered 12/11, 2020 at 22:36 Comment(1)
What does this really add over the top answers? A particular interface?Ninebark
P
-10

It's far from perfect, but it does the job.

data = data.replace(',"',',\n"')

you can improve it, add indenting and so on, but if you just want to be able to read a cleaner json, this is the way to go.

Pard answered 1/4, 2020 at 14:50 Comment(3)
AttributeError: 'dict' object has no attribute 'replace'Vista
Won't this screw up the file if you have a comma in a string?Doublefaced
This doesn't even remotely address the problem. Even in the best case, the output will look nothing like what OP presumably wanted.Ninebark

© 2022 - 2024 — McMap. All rights reserved.