Logging & Debugging Python Tricks
Logging & Debugging Python Tricks
Logging & Debugging Python Tricks
print(inspect('hello', methods=True))
console = Console()
data = pd.DataFrame({'a': [1, 2, 3], 'b': [4,
5, 6]})
def edit_data(data):
var_1 = 45
var_2 = 30
var_3 = var_1 + var_2
data['a'] = [var_1, var_2, var_3]
console.log(data, log_locals=True)
edit_data(data)
[08:12:24] a b
0 45 4
1 30 5
2 75 6
╭───── locals ─────╮
│ data = a b │
│ 0 45 4 │
│ 1 30 5 │
│ 2 75 6 │
│ var_1 = 45 │
│ var_2 = 30 │
│ var_3 = 75 │
╰──────────────────╯
Link to rich.
loguru: Print Readable Traceback in
Python
$ pip install loguru
logger.add("file_{time}.log", format="{time}
{level} {message}")
@logger.catch
def evaluate_result(y_true: np.array, y_pred:
np.array):
mean_square_err =
mean_squared_error(y_true, y_pred)
root_mean_square_err = mean_square_err **
0.5
y_true = np.array([1, 2, 3])
y_pred = np.array([1.5, 2.2])
evaluate_result(y_true, y_pred)
> File "/tmp/ipykernel_174022/1865479429.py",
line 14, in <module>
evaluate_result(y_true, y_pred)
│ │ └ array([1.5,
2.2])
│ └ array([1, 2, 3])
└ <function evaluate_result at
0x7f279588f430>
File "/tmp/ipykernel_174022/1865479429.py",
line 9, in evaluate_result
mean_square_err =
mean_squared_error(y_true, y_pred)
│ │
└ array([1.5, 2.2])
│ └
array([1, 2, 3])
└ <function
mean_squared_error at 0x7f27958bfca0>
File
"/home/khuyen/book/venv/lib/python3.8/site-
packages/sklearn/utils/validation.py", line
63, in inner_f
return f(*args, **kwargs)
│ │ └ {}
│ └ (array([1, 2, 3]), array([1.5,
2.2]))
└ <function mean_squared_error at
0x7f27958bfb80>
File
"/home/khuyen/book/venv/lib/python3.8/site-
packages/sklearn/metrics/_regression.py", line
335, in mean_squared_error
y_type, y_true, y_pred, multioutput =
_check_reg_targets(
│ │ └
<function _check_reg_targets at
0x7f27958b7af0>
│ └ array([1.5, 2.2])
└ array([1, 2, 3])
File
"/home/khuyen/book/venv/lib/python3.8/site-
packages/sklearn/metrics/_regression.py", line
88, in _check_reg_targets
check_consistent_length(y_true, y_pred)
│ │ └
array([1.5, 2.2])
│ └ array([1, 2, 3])
└ <function check_consistent_length at
0x7f279676e040>
File
"/home/khuyen/book/venv/lib/python3.8/site-
packages/sklearn/utils/validation.py", line
319, in check_consistent_length
raise ValueError("Found input variables
with inconsistent numbers of"
Link to loguru.
Icrecream: Never use print() to debug
again
$ pip install icecream
If you use print or log to debug your code, you might be confused
about which line of code creates the output, especially when there
are many outputs.
def plus_one(num):
return num + 1
ic(plus_one(1))
ic(plus_one(2))
ic| plus_one(1): 2
ic| plus_one(2): 3
Output:
ic| plus_one(1): 2
ic| plus_one(2): 3
Link to icecream
If you want to visualize which lines are executed and how many
times they are executed, try heartrate.
import heartrate
heartrate.trace(browser=True)
def factorial(x):
if x == 1:
return 1
else:
return (x * factorial(x-1))
if __name__ == "__main__":
num = 5
print(f"The factorial of {num} is
{factorial(num)}")
* Serving Flask app 'heartrate.core' (lazy
loading)
* Environment: production
The factorial of 5 is 120
Opening in existing browser session.
You should see something similar to the below when opening the
browser:
Link to heartrate.
snoop : Smart Print to Debug your
Python Function
$ pip install snoop
import snoop
@snoop
def factorial(x):
if x == 1:
return 1
else:
return (x * factorial(x-1))
if __name__ == "__main__":
num = 5
print(f"The factorial of {num} is
{factorial(num)}")
10:19:00.73 >>> Call to factorial in File "
<ipython-input-2-57aff36d5f6d>", line 4
10:19:00.73 ...... x = 5
10:19:00.73 4 | def factorial(x):
10:19:00.73 5 | if x == 1:
10:19:00.73 8 | return (x *
factorial(x-1))
10:19:00.74 >>> Call to factorial in File
"<ipython-input-2-57aff36d5f6d>", line 4
10:19:00.74 ...... x = 4
10:19:00.74 4 | def factorial(x):
10:19:00.74 5 | if x == 1:
10:19:00.74 8 | return (x *
factorial(x-1))
10:19:00.74 >>> Call to factorial in
File "<ipython-input-2-57aff36d5f6d>", line 4
10:19:00.74 ...... x = 3
10:19:00.74 4 | def factorial(x):
10:19:00.74 5 | if x == 1:
10:19:00.75 8 | return (x *
factorial(x-1))
10:19:00.75 >>> Call to factorial
in File "<ipython-input-2-57aff36d5f6d>", line
4
10:19:00.75 ...... x = 2
10:19:00.75 4 | def
factorial(x):
10:19:00.75 5 | if x == 1:
10:19:00.75 8 | return
(x * factorial(x-1))
10:19:00.75 >>> Call to
factorial in File "<ipython-input-2-
57aff36d5f6d>", line 4
10:19:00.75 ...... x = 1
10:19:00.75 4 | def
factorial(x):
10:19:00.76 5 | if x ==
1:
10:19:00.76 6 |
return 1
10:19:00.76 <<< Return value
from factorial: 1
10:19:00.76 8 | return
(x * factorial(x-1))
10:19:00.77 <<< Return value from
factorial: 2
10:19:00.77 8 | return (x *
factorial(x-1))
10:19:00.77 <<< Return value from
factorial: 6
10:19:00.77 8 | return (x *
factorial(x-1))
10:19:00.77 <<< Return value from
factorial: 24
10:19:00.78 8 | return (x *
factorial(x-1))
10:19:00.78 <<< Return value from factorial:
120
When using pandas pipe, you might want to check whether each
pipeline transforms your pandas DataFrame correctly. To
automatically log the information of a pandas DataFrame after each
pipeline, use the decorator sklego.pandas_utils.log_step.
import pandas as pd
from sklego.pandas_utils import log_step
import logging
@log_step(print_fn=logging.info)
def make_copy(df: pd.DataFrame):
return df.copy()
@log_step(print_fn=logging.info)
def drop_column(df: pd.DataFrame):
return df[["col2"]]
@log_step(print_fn=logging.info)
def encode_cat_variables(df: pd.DataFrame):
df["col2"] = df["col2"].map({"a": 1, "b":
2, "c": 3})
return df
df =
df.pipe(make_copy).pipe(drop_column).pipe(enco
de_cat_variables)
INFO:root:[make_copy(df)] time=0:00:00.000239
n_obs=3, n_col=2
INFO:root:[drop_column(df)]
time=0:00:00.002117 n_obs=3, n_col=1
INFO:root:[encode_cat_variables(df)]
time=0:00:00.003217 n_obs=3, n_col=1
If your for loop or list comprehension takes a long time to run, you
might want to know which element is being processed. You can add
clarity to your for-loop by using tqdm. Using tqdm with an iterable
will show a progress bar.
def lower(word):
sleep(1)
print(f"Processing {word}")
return word.lower()
Processing Duck
Processing dog
Processing Flower
Processing fan
Link to tqdm.