Miscellaneous

Timer

Use timer as a standalone class so you have full control on when to call a lap (most useful in while loops)…

N = 50
t = Timer(N)
info = None

for i in range(N):
    time.sleep(0.01)
    t(info=info)  # Lap and present the time
    if i == N // 2:
        print()
        info = f"My Info: {i*3.122}"
26/50 (0.32s - 0.30s remaining - 80.72 iters/s)          
My Info: 78.05  50/50 (0.62s - 0.00s remaining - 80.88 iters/s)          

Track2

… or use track2 to directly track a for loop

N = 50
info = None

for i in (tracker := track2(range(N), total=N)):
    time.sleep(0.01)
    info = f"My Info: {i*3.122:.2f}"
    if i == N // 2:
        print()
    if i >= N // 2:
        tracker.send(info)
25/50 (0.30s - 0.30s remaining - 83.74 iters/s)          
My Info: 152.98 50/50 (0.60s - 0.00s remaining - 83.91 iters/s)          

Warning! NEVER RUN tracker.send(None) as this will skip variables silently

Try Catch with a single line

@tryy
def do(a, b, c):
    return 1 / 0


x = do(1, 2, c=10)
assert x is None  # tryy returns None by default
[09/08/24 21:15:31] WARNING  Error for `do` with                                                                                                      2770652618.py:inner:26
                             args()                                                                                                                                         
                               0 - 1 (🏷️ int)                                                                                                                                
                               1 - 2 (🏷️ int)                                                                                                                                
                             kwargs                                                                                                                                         
                               c - 10 (🏷️ int)                                                                                                                               
                                                                                                                                                                            
                             ZeroDivisionError: division by zero                                                                                                            

Use your own default on failure

@tryy(output_to_return_on_fail="😔")
def do(a, b, c):
    return 1 / 0


do(1, 2, c=10)
                    WARNING  Error for `do` with                                                                                                      2770652618.py:inner:26
                             args()                                                                                                                                         
                               0 - 1 (🏷️ int)                                                                                                                                
                               1 - 2 (🏷️ int)                                                                                                                                
                             kwargs                                                                                                                                         
                               c - 10 (🏷️ int)                                                                                                                               
                                                                                                                                                                            
                             ZeroDivisionError: division by zero                                                                                                            
'😔'

Optionally print the full stacktrace if needed

@tryy(print_traceback=True, output_to_return_on_fail="😔")
def do(a, b, c):
    return 1 / 0


do(1, 2, c=10)
                    WARNING  Error for `do` with                                                                                                      2770652618.py:inner:34
                             args()                                                                                                                                         
                               0 - 1 (🏷️ int)                                                                                                                                
                               1 - 2 (🏷️ int)                                                                                                                                
                             kwargs                                                                                                                                         
                               c - 10 (🏷️ int)                                                                                                                               
                                                                                                                                                                            
                             Traceback (most recent call last):                                                                                                             
                               File "/var/folders/1_/71dqv9vx2750gmyz77q_f45w0000gn/T/ipykernel_19659/2770652618.py", line 21, in inner                                     
                                 return f(*args, **kwargs)                                                                                                                  
                                        ^^^^^^^^^^^^^^^^^^                                                                                                                  
                               File "/var/folders/1_/71dqv9vx2750gmyz77q_f45w0000gn/T/ipykernel_19659/580638143.py", line 3, in do                                          
                                 return 1 / 0                                                                                                                               
                                        ~~^~~                                                                                                                               
                             ZeroDivisionError: division by zero                                                                                                            
                                                                                                                                                                            
                             Traceback (most recent call last):                                                                                                             
                               File "/var/folders/1_/71dqv9vx2750gmyz77q_f45w0000gn/T/ipykernel_19659/2770652618.py", line 21, in inner                                     
                                 return f(*args, **kwargs)                                                                                                                  
                               File "/var/folders/1_/71dqv9vx2750gmyz77q_f45w0000gn/T/ipykernel_19659/580638143.py", line 3, in do                                          
                                 return 1 / 0                                                                                                                               
                             ZeroDivisionError: division by zero                                                                                                            
                                                                                                                                                                            
                             ╭───────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────╮                       
                              in inner:21                                                                                                                                 
                                                                                                                                                                          
                                18 │   │                                                                                                                                  
                                19 │   │   def inner(*args, **kwargs):                                                                                                    
                                20 │   │   │   try:                                                                                                                       
                              21 │   │   │   │   return f(*args, **kwargs)                                                                                              
                                22 │   │   │   except Exception as e:                                                                                                     
                                23 │   │   │   │   if not silence_errors:                                                                                                 
                                24 │   │   │   │   │   if not print_traceback:                                                                                            
                                                                                                                                                                          
                              in do:3                                                                                                                                     
                                                                                                                                                                          
                                1 @tryy(print_traceback=True, output_to_return_on_fail="😔")                                                                              
                                2 def do(a, b, c):                                                                                                                        
                              3 return 1 / 0                                                                                                                        
                                4                                                                                                                                         
                                5                                                                                                                                         
                                6 do(1, 2, c=10)                                                                                                                          
                             ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯                       
                             ZeroDivisionError: division by zero                                                                                                            
'😔'

You can also silence the errors completely

@tryy(silence_errors=True, output_to_return_on_fail="😔")
def do(a, b, c):
    return 1 / 0


do(1, 2, c=10)
'😔'

You can collect all your errors in a list

import random

errors = []


@tryy(silence_errors=True, store_errors=errors)
def do(a, b, c):
    if random.randint(0, 100) < 50:
        return 1 / 0
    else:
        raise NotImplementedError("🤔")


for _ in range(4):
    do(1, random.randint(0, 10), c=random.randint(0, 100))

print(errors)
[
```↯ AttrDict ↯
func - do (🏷️ str)
args()
  0 - 1 (🏷️ int)
  1 - 6 (🏷️ int)
kwargs
  c - 23 (🏷️ int)
tb - None (🏷️ NoneType)
err_type - NotImplementedError (🏷️ str)

```
, 
```↯ AttrDict ↯
func - do (🏷️ str)
args()
  0 - 1 (🏷️ int)
  1 - 9 (🏷️ int)
kwargs
  c - 100 (🏷️ int)
tb - None (🏷️ NoneType)
err_type - NotImplementedError (🏷️ str)

```
, 
```↯ AttrDict ↯
func - do (🏷️ str)
args()
  0 - 1 (🏷️ int)
  1 - 6 (🏷️ int)
kwargs
  c - 60 (🏷️ int)
tb - None (🏷️ NoneType)
err_type - ZeroDivisionError (🏷️ str)

```
, 
```↯ AttrDict ↯
func - do (🏷️ str)
args()
  0 - 1 (🏷️ int)
  1 - 2 (🏷️ int)
kwargs
  c - 32 (🏷️ int)
tb - None (🏷️ NoneType)
err_type - NotImplementedError (🏷️ str)

```
]

There’s onlly one usecase where you would want to send in a list by yourself - when you want to append your errors to an existing list. The sensible default is to always store the errors, especially because this is a debugging tool.

Just access all the errors in a dataframe like so

import random

random.seed(10)


@tryy(silence_errors=True)
def do(a, b, c):
    if c < 50:
        return 1 / 0
    else:
        raise NotImplementedError("🤔")


for _ in range(4):
    do(1, random.randint(0, 10), c=random.randint(0, 100))

do.error_summary()
func args kwargs tb err_type
0 do (1, 9) {'c': 4} None ZeroDivisionError
1 do (1, 6) {'c': 61} None NotImplementedError
2 do (1, 9) {'c': 1} None ZeroDivisionError
3 do (1, 3) {'c': 59} None NotImplementedError

and the actual list of errors like so

do.error_store
[
 ```↯ AttrDict ↯
 func - do (🏷️ str)
 args()
   0 - 1 (🏷️ int)
   1 - 9 (🏷️ int)
 kwargs
   c - 4 (🏷️ int)
 tb - None (🏷️ NoneType)
 err_type - ZeroDivisionError (🏷️ str)
 
 ```,
 
 ```↯ AttrDict ↯
 func - do (🏷️ str)
 args()
   0 - 1 (🏷️ int)
   1 - 6 (🏷️ int)
 kwargs
   c - 61 (🏷️ int)
 tb - None (🏷️ NoneType)
 err_type - NotImplementedError (🏷️ str)
 
 ```,
 
 ```↯ AttrDict ↯
 func - do (🏷️ str)
 args()
   0 - 1 (🏷️ int)
   1 - 9 (🏷️ int)
 kwargs
   c - 1 (🏷️ int)
 tb - None (🏷️ NoneType)
 err_type - ZeroDivisionError (🏷️ str)
 
 ```,
 
 ```↯ AttrDict ↯
 func - do (🏷️ str)
 args()
   0 - 1 (🏷️ int)
   1 - 3 (🏷️ int)
 kwargs
   c - 59 (🏷️ int)
 tb - None (🏷️ NoneType)
 err_type - NotImplementedError (🏷️ str)
 
 ```]

Finally, you want to run the function (without try) to reproduce the error and actually start debugging. Just use the .F attribute to access the original function that you created

ix = 2
data = do.error_store[ix]
try:
    do.F(*data.args, **data.kwargs)
except Exception as e:
    print(f"ERROR: ", e)
ERROR:  division by zero