Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
probml
GitHub Repository: probml/pyprobml
Path: blob/master/tests/test_notebooks.py
1191 views
1
import pytest
2
import os
3
import re
4
import subprocess
5
import warnings
6
from time import time
7
import shutil
8
from testbook import testbook
9
10
# Global variables
11
TIMEOUT = 1200 # seconds
12
TEST_DIR = "test_results"
13
os.environ["FIG_DIR"] = "figures"
14
os.environ["LATEXIFY"] = "" # To enable latexify code
15
os.environ["DUAL_SAVE"] = "" # To save both .pdf and .png
16
17
#get IGNORE_LIST of notebooks
18
IGNORE_LIST = []
19
with open("internal/ignored_notebooks.txt") as fp:
20
notebooks = fp.readlines()
21
for nb in notebooks:
22
IGNORE_LIST.append(nb.strip().split("/")[-1])
23
24
def in_ignore_list(nb_path):
25
nb_name = nb_path.split("/")[-1]
26
return nb_name in IGNORE_LIST
27
28
# Load notebooks
29
cmd = "git ls-files 'notebooks/book**.ipynb' -z | xargs -0 -n1 -I{} -- git log -1 --format='%at {}' {}"
30
notebooks_raw = subprocess.run(cmd, check=True, shell=True, capture_output=True, text=True)
31
if notebooks_raw.stderr:
32
warnings.warn(notebooks_raw.stderr)
33
timestamped_notebooks = []
34
for entry in notebooks_raw.stdout.split("\n"):
35
if entry:
36
ts, notebook = entry.split(" ")
37
if in_ignore_list(notebook):
38
print(f"******** {notebook} skiped!! *********")
39
continue # don't execute these notebooks
40
timestamped_notebooks.append((int(ts), notebook))
41
timestamped_notebooks.sort(reverse=True) # execute newer notebooks first
42
43
44
if "PYPROBML_GA_RUNNER_ID" in os.environ:
45
# we are in execute_all_notebooks
46
notebooks = [
47
notebook
48
for i, (_, notebook) in enumerate(timestamped_notebooks)
49
if i % 20 == int(os.environ["PYPROBML_GA_RUNNER_ID"])
50
]
51
else:
52
# we are in execute_latest_notebooks
53
notebooks = []
54
oldest_ts, _ = timestamped_notebooks[-1]
55
for ts, notebook in timestamped_notebooks:
56
if ts > oldest_ts:
57
notebooks.append(notebook)
58
59
# To make subprocess stdout human readable
60
# https://stackoverflow.com/a/38662876
61
def escape_ansi(line):
62
ansi_escape = re.compile(r"(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]")
63
return ansi_escape.sub("", line)
64
65
66
# To update workflow status for a figure
67
def save_status(full_path, icon):
68
full_path = os.path.join(TEST_DIR, full_path)
69
if not os.path.exists(os.path.dirname(full_path)):
70
os.makedirs(os.path.dirname(full_path))
71
save_name = full_path.replace(".ipynb", ".png")
72
shutil.copy("tests/icons/{}.png".format(icon), save_name)
73
74
75
# Parameterize notebooks
76
@pytest.mark.parametrize("notebook", notebooks)
77
def test_run_notebooks(notebook):
78
"""
79
Test notebooks
80
"""
81
init = time()
82
try:
83
84
@testbook(notebook, execute=True, timeout=TIMEOUT)
85
def check(tb):
86
pass
87
88
check()
89
save_status(notebook, "right")
90
print("passed in {:.2f} seconds: {} ".format(time() - init, notebook))
91
except Exception as e:
92
save_status(notebook, "wrong")
93
print("failed after {:.2f} seconds: {} ".format(time() - init, notebook))
94
with open(f"{TEST_DIR}/{notebook.replace('.ipynb', '.log')}", "w") as f:
95
f.write(escape_ansi(str((e))))
96
raise e
97
98