Debugging¶
-
tap
(value, label=None)¶ Prints value and then returns it. Useful to tap into some functional pipeline for debugging:
fields = (f for f in fields_for(category) if section in tap(tap(f).sections)) # ... do something with fields
If
label
is specified then it’s printed before corresponding value:squares = {tap(x, 'x'): tap(x * x, 'x^2') for x in [3, 4]} # x: 3 # x^2: 9 # x: 4 # x^2: 16 # => {3: 9, 4: 16}
-
@
log_calls
(print_func, errors=True, stack=True)¶ -
@
print_calls
(errors=True, stack=True)¶ Will log or print all function calls, including arguments, results and raised exceptions. Can be used as decorator or tapped into call expression:
sorted_fields = sorted(fields, key=print_calls(lambda f: f.order))
If
errors
is set toFalse
then exceptions are not logged. This could be used to separate channels for normal and error logging:@log_calls(log.info, errors=False) @log_errors(log.exception) def some_suspicious_function(...): # ... return result
-
@
log_enters
(print_func)¶ -
@
print_enters
¶ -
@
log_exits
(print_func, errors=True, stack=True)¶ -
@
print_exits
(errors=True, stack=True)¶ Will log or print every time execution enters or exits the function. Should be used same way as
@log_calls()
and@print_calls()
when you need to track only one event per function call.
-
@
log_errors
(print_func, label=None, stack=True)¶ -
@
print_errors
(label=None, stack=True)¶ Will log or print all function errors providing function arguments causing them. If
stack
is set toFalse
then each error is reported with simple one line message.Can be combined with
@silent
or@ignore()
to trace occasionally misbehaving function:@silent @log_errors(logging.warning) def guess_user_id(username): initial = first_guess(username) # ...
Can also be used as context decorator:
with print_errors('initialization', stack=False): load_this() load_that() # ... # SomeException: a bad thing raised in initialization
-
@
log_durations
(print_func, label=None)¶ -
@
print_durations
(label=None)¶ Will time each function call and log or print its duration:
@log_durations(logging.info) def do_hard_work(n): samples = range(n) # ... # 121 ms in do_hard_work(10) # 143 ms in do_hard_work(11) # ...
A block of code could be timed with a help of context manager:
with print_durations('Creating models'): Model.objects.create(...) # ... # 10.2 ms in Creating models
-
log_iter_durations
(seq, print_func, label=None)¶ -
print_iter_durations
(seq, label=None)¶ Wraps iterable
seq
into generator logging duration of processing of each item:for item in print_iter_durations(seq, label='hard work'): do_smth(item) # 121 ms in iteration 0 of hard work # 143 ms in iteration 1 of hard work # ...