Rich Logging and printing

Ez logging

Logging is packed in these 5 functions

reset_logger("trace", console_width=80)
Trace("Testing {1,2,3}")
Debug("TESTING {1,2,3}")
Info("TESTING {1,2,3}")
Warn("TESTING {1,2,3}")
Excep("TESTING {1,2,3}")
[08/24/24 12:16:05] TRACE    Testing {1,2,3}            1838145784.py:<module>:2
                    DEBUG    TESTING {1,2,3}            1838145784.py:<module>:3
                    INFO     TESTING {1,2,3}            1838145784.py:<module>:4
                    WARNING  TESTING {1,2,3}            1838145784.py:<module>:5
                    ERROR    TESTING {1,2,3}            1838145784.py:<module>:6
                             NoneType: None                                     
                                                                                
                                                                                

Excep will also print a traceback

def do():
    try:
        1 / 0
    except Exception as e:
        Excep(e)


def do2():
    do()


do2()
[08/24/24 12:16:07] ERROR    division by zero                 1923207781.py:do:5
                             ZeroDivisionError: division by                     
                             zero                                               
                                                                                
                             ╭─ Traceback (most recent call─╮                   
                              in do:3                                         
                                                                              
                                 1 def do():                                  
                                 2 try:                                   
                               3 │   │   1 / 0                              
                                 4 except Exception as                    
                                 5 │   │   Excep(e)                           
                                 6                                            
                             ╰──────────────────────────────╯                   
                             ZeroDivisionError: division by                     
                             zero                                               

All logging functions have an optional depth that will be helpful to raise the context level to outer functions

def do():
    Info("In do")


do()
[08/24/24 12:16:15] INFO     In do                             809811040.py:do:2
def do2():
    Info("Log will still say it is from `do2` now, to the right of log print")


def do():
    do2()


do()
[08/24/24 12:17:13] INFO     Log will still say it is from   2099333876.py:do2:2
                             `do2` now, to the right of log                     
                             print                                              
def do2():
    Info("But now, log will still say it is from do", depth=1)


def do():
    do2()


do()
[08/24/24 12:17:25] INFO     But now, log will still say it   4054019042.py:do:5
                             is from do                                         

Logging Level and context


in_logger_mode

 in_logger_mode (level:str)

return’s T/F, checking if logger is in a specific mode or not


logger_mode

 logger_mode (level)

temporarily, using with context, set the level to something else


get_logger_level

 get_logger_level ()

get the current logger’s level

Let’s log every level in the do function below. We can control what we need to log from outside the function’s context by
using with <level>_model():

def do():
    Trace(0)
    Debug(1)
    Info(2)
    Warn(3)
    Excep(4)


def line(x):
    sep = "=" * 20
    print(f"{sep}{x}{sep}")
    print(f"{in_excep_mode()=}")
    print(f"{in_warn_mode()=}")
    print(f"{in_info_mode()=}")
    print(f"{in_debug_mode()=}")
    print(f"{in_trace_mode()=}")


reset_logger()

with excep_mode():
    line("Excep mode")
    do()

with warn_mode():
    line("Warn mode")
    do()

with info_mode():
    line("Info mode")
    do()

with debug_mode():
    line("Debug mode")
    do()

with trace_mode():
    line("Trace mode")
    do()
====================Excep mode====================
in_excep_mode()=True
in_warn_mode()=False
in_info_mode()=False
in_debug_mode()=False
in_trace_mode()=False
[08/24/24 12:13:08] ERROR    4                                                                                                                            3432048509.py:do:6
                             NoneType: None                                                                                                                                 
                                                                                                                                                                            
                                                                                                                                                                            
====================Warn mode====================
in_excep_mode()=False
in_warn_mode()=True
in_info_mode()=False
in_debug_mode()=False
in_trace_mode()=False
[08/24/24 12:13:08] WARNING  3                                                                                                                            3432048509.py:do:5
                    ERROR    4                                                                                                                            3432048509.py:do:6
                             NoneType: None                                                                                                                                 
                                                                                                                                                                            
                                                                                                                                                                            
====================Info mode====================
in_excep_mode()=False
in_warn_mode()=False
in_info_mode()=True
in_debug_mode()=False
in_trace_mode()=False
[08/24/24 12:13:08] INFO     2                                                                                                                            3432048509.py:do:4
                    WARNING  3                                                                                                                            3432048509.py:do:5
                    ERROR    4                                                                                                                            3432048509.py:do:6
                             NoneType: None                                                                                                                                 
                                                                                                                                                                            
                                                                                                                                                                            
====================Debug mode====================
in_excep_mode()=False
in_warn_mode()=False
in_info_mode()=False
in_debug_mode()=True
in_trace_mode()=False
[08/24/24 12:13:08] DEBUG    1                                                                                                                            3432048509.py:do:3
                    WARNING  3                                                                                                                            3432048509.py:do:5
                    ERROR    4                                                                                                                            3432048509.py:do:6
                             NoneType: None                                                                                                                                 
                                                                                                                                                                            
                                                                                                                                                                            
====================Trace mode====================
in_excep_mode()=False
in_warn_mode()=False
in_info_mode()=False
in_debug_mode()=False
in_trace_mode()=True
[08/24/24 12:13:08] TRACE    0                                                                                                                            3432048509.py:do:2
                    WARNING  3                                                                                                                            3432048509.py:do:5
                    ERROR    4                                                                                                                            3432048509.py:do:6
                             NoneType: None                                                                                                                                 
                                                                                                                                                                            
                                                                                                                                                                            

The in_<level>_mode gives an additional layer of control, to be used for debugging dynamically. Let’s say, you want to show an image (for the sake of debugging)

def do(im_path):
    from torch_snippets import show, read

    im = read(im_path)
    show(im, sz=3)
    print(im.mean())


do("assets/Preamble.png")

145.5542982442515

But now you are happy with your code and don’t want the show, say the code is going to production. A common way out is to just comment that line

def do(im_path):
    from torch_snippets import show, read

    im = read(im_path)
    # show(im, sz=3) # line is commented, but will need to be re-uncommented any time it needs debugging
    print(im.mean())


do("assets/Preamble.png")
145.5542982442515

But if you want to re-check, it’s a pain to again uncomment. Not to mention this method is not scalable to 100s of lines of code. The simple way to deal with such transient code that needs to activate only when you want it to, is to enclose in an if in_<level>_mode conditional like so

def do(im_path):
    from torch_snippets import show, read

    im = read(im_path)
    if in_debug_mode():
        show(im, sz=3)
    print(im.mean())


do("assets/Preamble.png")
145.5542982442515

This way, you can always activate the show by calling do with a temporary with_debug_mode context

with debug_mode():
    do("assets/Preamble.png")

145.5542982442515

Notify Waiting

reset_logger(console_width=100)

with trace_mode():
    with notify_waiting("Downloading"):
        time.sleep(10)

with notify_waiting("Downloading", spinner="guess_the_movie"):
    time.sleep(10)

with notify_waiting("One more message", spinner="earth"):
    time.sleep(3)
[08/24/24 12:36:51] TRACE    Available Spinners: dict_keys(['dots', 'dots2', 'dots3', 'dots4', 'dots5', 'dots6', 'dots7', 'dots8', 'dots9',  3340474699.py:notify_waiting:41
                             'dots10', 'dots11', 'dots12', 'dots8Bit', 'line', 'line2', 'pipe', 'simpleDots', 'simpleDotsScrolling', 'star',                                
                             'star2', 'flip', 'hamburger', 'growVertical', 'growHorizontal', 'balloon', 'balloon2', 'noise', 'bounce',                                      
                             'boxBounce', 'boxBounce2', 'triangle', 'arc', 'circle', 'squareCorners', 'circleQuarters', 'circleHalves',                                     
                             'squish', 'toggle', 'toggle2', 'toggle3', 'toggle4', 'toggle5', 'toggle6', 'toggle7', 'toggle8', 'toggle9',                                    
                             'toggle10', 'toggle11', 'toggle12', 'toggle13', 'arrow', 'arrow2', 'arrow3', 'bouncingBar', 'bouncingBall',                                    
                             'smiley', 'monkey', 'hearts', 'clock', 'earth', 'material', 'moon', 'runner', 'pong', 'shark', 'dqpb',                                         
                             'weather', 'christmas', 'grenade', 'point', 'layer', 'betaWave', 'aesthetic', 'guess', 'guess_the_movie'])                                     
                                                                                                                                                                            
                             Using: clock                                                                                                                                   

[08/24/24 12:37:01] INFO     Downloading - Completed in 10.01 s                                                                                   contextlib.py:__exit__:144

[08/24/24 12:37:11] INFO     Downloading - Completed in 10.01 s                                                                                   contextlib.py:__exit__:144

[08/24/24 12:37:14] INFO     One more message - Completed in 3.00 s                                                                               contextlib.py:__exit__:144