Search code examples
pythonrich

Rich Inspect Discovery


Im trying to dig into the Rich inpsect further to understand how it is doing the following.

If I look at an object (result) like so. I can see that it has the following attributes and methods.

>>> vars(result)
{'name': 'hello_world'}
>>> print(dir(result))
[
    '__class__',
    '__class_getitem__',
    '__contains__',
    '__delattr__',
    '__delitem__',
    '__dict__',
    '__dir__',
    '__doc__',
    '__eq__',
    '__format__',
    '__ge__',
    '__getattribute__',
    '__getitem__',
    '__gt__',
    '__hash__',
    '__init__',
    '__init_subclass__',
    '__iter__',
    '__le__',
    '__len__',
    '__lt__',
    '__module__',
    '__ne__',
    '__new__',
    '__orig_bases__',
    '__parameters__',
    '__reduce__',
    '__reduce_ex__',
    '__repr__',
    '__reversed__',
    '__setattr__',
    '__setitem__',
    '__sizeof__',
    '__slots__',
    '__str__',
    '__subclasshook__',
    '__weakref__',
    '_is_protocol',
    'clear',
    'copy',
    'failed',
    'failed_hosts',
    'fromkeys',
    'get',
    'items',
    'keys',
    'name',
    'pop',
    'popitem',
    'raise_on_error',
    'setdefault',
    'update',
    'values'
]

If I look at the output of Rich like so:

>>> inspect(result)
╭─────────────────────────────────────────────────────────────────────────────── <class 'nornir.core.task.AggregatedResult'> ────────────────────────────────────────────────────────────────────────────────╮
│ It basically is a dict-like object that aggregates the results for all devices.                                                                                                                            │
│ You can access each individual result by doing ``my_aggr_result["hostname_of_device"]``.                                                                                                                   │
│                                                                                                                                                                                                            │
│ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ AggregatedResult (hello_world): {'spine1-nxos': MultiResult: [Result: "hello_world", Result: "ABC1", Result: "ABC1a", Result: "ABC1b"], 'spine2-nxos': MultiResult: [Result: "hello_world", Result:    │ │
│ │ "ABC1", Result: "ABC1a", Result: "ABC1b"]}                                                                                                                                                             │ │
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                                                                                                                            │
│       failed = False                                                                                                                                                                                       │
│ failed_hosts = {}                                                                                                                                                                                          │
│         name = 'hello_world'                                                                                                                                                                               │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

I see that it has correctly only shown be the attributes and methods of interest. Can anyone point to me how Rich determines what to print?

Thanks,


Solution

  • The nice thing about open-source code is that you can just go find the source and read it. For this question, you'll be interested in this file in the rich source code. You're mostly interested in the _render method, though some things are set up in __init__.

    We can break down the output you were seeing, to properly understand it:

    ╭─────────────────────────────────────────────────────────────────────────────── <class 'nornir.core.task.AggregatedResult'> ────────────────────────────────────────────────────────────────────────────────╮
    

    The top line contains the "title" of the object being inspected. In this case, it's the repr of the class of the object.

    │ It basically is a dict-like object that aggregates the results for all devices.                                                                                                                            │
    │ You can access each individual result by doing ``my_aggr_result["hostname_of_device"]``.                                                                                                                   │
    

    This is the docstring of the object.

    │ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
    │ │ AggregatedResult (hello_world): {'spine1-nxos': MultiResult: [Result: "hello_world", Result: "ABC1", Result: "ABC1a", Result: "ABC1b"], 'spine2-nxos': MultiResult: [Result: "hello_world", Result:    │ │
    │ │ "ABC1", Result: "ABC1a", Result: "ABC1b"]}                                                                                                                                                             │ │
    │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
    

    This is the pretty-printed "value" of the object. It's probably based on the object's own repr, but I've not dived too deeply into how rich.pretty.Pretty works, so there might be more to it.

    │       failed = False                                                                                                                                                                                       │
    │ failed_hosts = {}                                                                                                                                                                                          │
    │         name = 'hello_world'                                                                                                                                                                               │
    ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
    

    The rest of the output is a list of attributes and their values. By default, only the non-callable, non-_private, non-__dunder__ attributes will be listed, but you could get a more complete list with different arguments to inspect.