Printing a Dict() with Rich

4k Views Asked by At

I'm trying to print a dict() using Pythons Rich. From my understanding, this should output the data on different lines etc. A bit like pprint.

But I'm getting:

>>> from rich import print
>>> print(output)

{'GigabitEthernet0/1': {'description': '## Connected to leaf-2 ##', 'type': 'iGbE', 'oper_status': 'up', 
'phys_address': '5000.0009.0001', 'port_speed': 'auto speed', 'mtu': 1500, 'enabled': True, 'bandwidth': 1000000, 
'flow_control': {'receive': False, 'send': False}, 'mac_address': '5000.0009.0001', 'auto_negotiate': True, 
'port_channel': {'port_channel_member': False}, 'duplex_mode': 'auto', 'delay': 10, 'accounting': {'other': {'pkts_in':
0, 'chars_in': 0, 'pkts_out': 431258, 'chars_out': 25875480}, 'ip': {'pkts_in': 513383, 'chars_in': 42910746, 
'pkts_out': 471188, 'chars_out': 45342027}, 'dec mop': {'pkts_in': 0, 'chars_in': 0, 'pkts_out': 7163, 'chars_out': 
551551}, 'arp': {'pkts_in': 3845, 'chars_in': 230700, 'pkts_out': 3846, 'chars_out': 230760}, 'cdp': {'pkts_in': 72010,
'chars_in': 18866620, 'pkts_out': 79879, 'chars_out': 31221768}}, 'ipv4': {'10.1.1.5/30': {'ip': '10.1.1.5',  ...

Any suggestions?

1

There are 1 best solutions below

1
On

TL;DR If your dictionary turns out to be not a dict, make an explicit conversion.


From contents of your dictionary I assume your output is from network device configuration like Cisco IOS, I'm dark on these areas and can't quite figure out where you've got your data from.

There's chance that module or script you used to get output may have actually returned a dict looking type called MappingProxyType.

I speculate this is why your text is colored but not prettified.


For example lets see what rich.print does with str.__dict__:

>>> from rich import print
>>> print(str.__dict__)

This will look like this, just as yours.

enter image description here

Do note this is xfce4 Terminal running in WSL2, drawn to X410 X-server. A fully capable terminal.

This indeed looks like plain dict, but lets check what it actually is:

>>> type(str.__dict__)
<class 'mappingproxy'>

>>> from types import MappingProxyType
>>> isinstance(str.__dict__, MappingProxyType)
True

>>> isinstance(str.__dict__, dict)
False

As you see, despite it's output looks like a dictionary, it's not.

types.MappingProxyType Is essentially a read-only dictonary which isn't necessarily a dict. Devs of 3rd party libraries like rich might have forgotten existence of such type. If that's the case, then rich.print will do what built-in print() would do: to call __repr__/__str__ - now just treating it as mere string.

We can confirm this behavior by passing string that looks like __repr__ of a method, and that still gets rich text treatment.

enter image description here

And also by creating instance of MappingProxyType yourself.

>>> from types import MappingProxyType
>>> from rich import print

>>> data = {f"{n}": n for n in range(11)}

>>> print(data)
{
    '0': 0,
    '1': 1,
    '2': 2,
    '3': 3,
    '4': 4,
    '5': 5,
    '6': 6,
    '7': 7,
    '8': 8,
    '9': 9,
    '10': 10
}

>>> print(MappingProxyType(data))
{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
'10': 10}

From which you can see how type affects rich.print's output.

To fix, simply convert types.MappingProxyType to dict.

>>> from rich import print
>>> print(dict(str.__dict__))

enter image description here

And that's way more pretty than it used to be - excluding __doc__ value which is a single string and can't be helped.