Search code examples
pythonrich

redirecting rich.inspect to file?


I am trying to troubleshoot why program receiving one set of parameters works (call it v1), while another call with almost the same parameters fails (call that v2).

So I want to diff some complex nested data structures. Trying a yaml dump resulted in errors (there are weakrefs and SQL connection objects). So I used rich.inspect in the pdb debugger and found some issues - rich is smart enough not to get itself in trouble. So now, I want to dump this out to a text file instead.

Is there a more elegant way than redirecting sys.stdout? The code below works, but it's fairly ugly near with open("capture2.txt","w") as sys.stdout:.

cat capture2.txt prints substantially the same output as the rich.inspect, including the colors. So, that's good, but is there a cleaner way to send rich.inspect to a file? The console argument looks like it might, but then again it looks more like a way to specify color and terminal behavior, rather than allowing for redirection.

from rich import inspect
import sys
#just a simple way to get some complexity cheap
from types import SimpleNamespace

foo = SimpleNamespace(
    a = 1,
    name = "Foo",
    bar = SimpleNamespace(b=2, name="Bar!", di = dict(a=1,b=2,c=[1,2,3]))
)
#OK, simple prints to screen
inspect(foo)


# is there a better way here 👇

print("redirect stdout")
#save stdout
bup = sys.stdout
with open("capture2.txt","w") as sys.stdout:
    inspect(foo)
# restore stdout
sys.stdout = bup

#if I don't restore `sys.stdout` from `bup` => IOError
print("coucou")    

Screenshot of output:

enter image description here

p.s. To make diffing easier I did get rid of some of the terminal codes (color and font-related) by using rich.inspect(x,console = Console(force_terminal=False)).


Solution

  • Read The Fine Manual:

    There are a lot of parameters for Console. I managed to miss file:

    class Console:
        """A high level console interface.
    
        Args:
            color_system (str, optional): The color system supported by your terminal,
                either ``"standard"``, ``"256"`` or ``"truecolor"``. Leave as ``"auto"`` to autodetect.
            force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None.  
            ...
          👉file (IO, optional): A file object where the console should write to. Defaults to stdout.
            quiet (bool, Optional): Boolean to suppress all output. Defaults to False.
    
    

    So...

    with open("capture2.txt","w") as fo:
        console = Console(force_terminal=False,file=fo)
        inspect(foo,console=console)
    
    

    I'll leave that out, hopefully someone will find it useful later.