tree representation of Python data

Thomas Passin list1 at tompassin.net
Sun Jan 22 12:11:20 EST 2023


On 1/21/2023 10:03 AM, Dino wrote:
> 
> I have a question that is a bit of a shot in the dark. I have this nice 
> bash utility installed:
> 
> $ tree -d unit/
> unit/
> ├── mocks
> ├── plugins
> │   ├── ast
> │   ├── editor
> │   ├── editor-autosuggest
> │   ├── editor-metadata
> │   ├── json-schema-validator
> │   │   └── test-documents
> │   └── validate-semantic
> │       ├── 2and3
> │       ├── bugs
> │       └── oas3
> └── standalone
>      └── topbar-insert
> 
> I just thought that it would be great if there was a Python utility that 
> visualized a similar graph for nested data structures.
> Of course I am aware of indent (json.dumps()) and pprint, and they are 
> OK options for my need. It's just that the compact, improved 
> visualization would be nice to have. Not so nice that I would go out of 
> my way to build, but nice enough to use an exising package.

It's not clear to me whether you want to display JSON structures or 
Python objects.  However, Python dictionaries are so similar to JSON 
structures that a dictionary example should be pretty close.

This can actually be a tricky problem because for complicated nesting, 
it's not that easy to work out how to display the elements.  The 
examples posted in this thread so far have been somewhat obscured by the 
use of leader lines, etc, so that it's a little hard to discern the 
simple core of the algorithm.

Below I include code that displays each leaf element on its own indented 
line, can only display keys and simple leaf values, and does not 
construct leader lines so as to keep the code easy to read.  In this 
form it can only display Python dictionaries but could be modified for 
JSON without too much work.

"""Display nested objects as an indented list."""
INDENT = ' ' * 3
DICT = {'a': {'aa':'AA', 'ab':'AB'},
         'b': {'ba': {'baa': 'BAA', 'bab': 'BAB'},
               'bb':'BB'},
         'c': ['CA', 'CB'],
         'd': 'D' }
SIMPLE_TYPES = (int, float, str, bytes)

def unroll(obj, indent = ''):
     if isinstance(obj, dict):
         unroll_dict(obj, indent)
     else:
         """unroll other kinds of objects (not implemented)."""
         print(indent, 'Can only unroll nested dictionaries')

def unroll_dict(dct, indent = ''):
     """Unroll a dictionary whose values can be either simple or
        nested.
     """
     for k, v in dct.items():
         g.es(indent, k)
         new_indent = indent + INDENT
         if type(v) in SIMPLE_TYPES:
             print(new_indent, v)
         else:
             unroll(v, new_indent)
             # print(f'{new_indent}{v}')

unroll(DICT)

Output:
a
     aa
        AA
     ab
        AB
b
     ba
        baa
           BAA
        bab
           BAB
     bb
        BB
c
     Can only unroll nested dictionaries
d
     D

If you change the last else block, you can make use of the object's 
internal representation (not for JSON, of course).  Change the block to 
read:

             # unroll(v, new_indent)
             print(f'{new_indent}{v}')

This change gives the following output:

a
    {'aa': 'AA', 'ab': 'AB'}
b
    {'ba': {'baa': 'BAA', 'bab': 'BAB'}, 'bb': 'BB'}
c
    ['CA', 'CB']
d
     D


In practice, I would collect the text fragments into a list instead of 
printing them, then print the joined list at the end.


More information about the Python-list mailing list