Skip to content

Commit b5ece0f

Browse files
setup script that creates a uv environment requiring only the existence of a uv_executable
1 parent 93fcff9 commit b5ece0f

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

setup_notebooks.py

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env python
2+
3+
import argparse
4+
import subprocess
5+
import sys
6+
import tempfile
7+
from pathlib import Path
8+
9+
def run_command(command, cwd):
10+
"""Runs a command and prints its output."""
11+
print(f"Running command: {' '.join(command)} in {cwd}")
12+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd, text=True)
13+
for line in iter(process.stdout.readline, ''):
14+
print(line, end='')
15+
process.wait()
16+
if process.returncode != 0:
17+
raise subprocess.CalledProcessError(process.returncode, command)
18+
19+
def setup_env(outdir,
20+
commit,
21+
python_version,
22+
nbfiles,
23+
uv_executable,
24+
nbmake_timeout,
25+
nbmake_kernel,
26+
nbmake_allow_errors,
27+
nbmake_rerun):
28+
"""
29+
Sets up a student environment for ISLP_labs.
30+
31+
Parameters
32+
----------
33+
outdir : Path
34+
Output directory.
35+
commit : str
36+
Commit hash or tag to checkout.
37+
python_version : str
38+
Python version to use for the virtual environment.
39+
nbfiles : list
40+
List of notebook files to run with nbmake.
41+
uv_executable : str
42+
The `uv` executable.
43+
nbmake_timeout : int
44+
Timeout for running notebooks with nbmake.
45+
nbmake_kernel : str
46+
Kernel to use for running notebooks with nbmake.
47+
nbmake_allow_errors : bool
48+
Allow errors when running notebooks with nbmake.
49+
nbmake_rerun : int
50+
Number of times to rerun notebooks with nbmake.
51+
"""
52+
repo_url = 'https://github.com/intro-stat-learning/ISLP_labs.git'
53+
54+
if outdir is None:
55+
with tempfile.TemporaryDirectory() as tmpdir:
56+
setup_env(Path(tmpdir),
57+
commit,
58+
python_version,
59+
nbfiles,
60+
uv_executable,
61+
nbmake_timeout,
62+
nbmake_kernel,
63+
nbmake_allow_errors,
64+
nbmake_rerun)
65+
return
66+
67+
if not outdir.exists():
68+
outdir.mkdir(parents=True)
69+
70+
try:
71+
print(f"Initializing repository in {outdir}...")
72+
run_command(['git', 'init'], cwd=str(outdir))
73+
run_command(['git', 'remote', 'add', 'origin', repo_url], cwd=str(outdir))
74+
75+
print(f"Fetching commit {commit}...")
76+
run_command(['git', 'fetch', 'origin', commit, '--depth=1'], cwd=str(outdir))
77+
78+
print(f"Checking out commit {commit}...")
79+
run_command(['git', 'checkout', 'FETCH_HEAD'], cwd=str(outdir))
80+
81+
print(f"Setting up Python {python_version} with {uv_executable}...")
82+
run_command([uv_executable, 'python', 'install', python_version], cwd=str(outdir))
83+
84+
print("Creating virtual environment...")
85+
run_command([uv_executable, 'venv', '--python', python_version, '--seed'], cwd=str(outdir))
86+
87+
print("Installing requirements...")
88+
venv_dir = Path('.venv')
89+
uv_bin = venv_dir / 'Scripts' if sys.platform == 'win32' else venv_dir / 'bin'
90+
91+
run_command([str(uv_bin / 'pip'), 'install', '-r', 'requirements.txt', 'jupyterlab'], cwd=str(outdir))
92+
93+
if nbfiles:
94+
run_command([str(uv_bin / 'pip'), 'install', 'pytest', 'nbmake'], cwd=str(outdir))
95+
for nbfile in nbfiles:
96+
notebook_path = outdir / nbfile
97+
if not notebook_path.exists():
98+
print(f"Error: Notebook '{nbfile}' not found in the repository.", file=sys.stderr)
99+
continue
100+
101+
print(f"Running notebook {notebook_path}...")
102+
pytest_command = [str(uv_bin / 'pytest'), '--nbmake', f'--nbmake-timeout={nbmake_timeout}', '-vv', str(nbfile)]
103+
if nbmake_kernel:
104+
pytest_command.append(f'--nbmake-kernel={nbmake_kernel}')
105+
if nbmake_allow_errors:
106+
pytest_command.append('--nbmake-allow-errors')
107+
if nbmake_rerun > 0:
108+
pytest_command.append(f'--nbmake-rerun={nbmake_rerun}')
109+
110+
run_command(pytest_command, cwd=str(outdir))
111+
112+
print("Setup completed successfully.")
113+
print(f"Environment is in: {outdir}")
114+
if sys.platform == 'win32':
115+
print(f"Activate it with: .\\{outdir.name}\\.venv\\Scripts\\activate")
116+
else:
117+
print(f"Activate it with: source {outdir.name}/.venv/bin/activate")
118+
119+
120+
except subprocess.CalledProcessError as e:
121+
print(f"An error occurred: {e}", file=sys.stderr)
122+
sys.exit(1)
123+
124+
def main():
125+
parser = argparse.ArgumentParser(description='Setup a student environment for ISLP_labs.')
126+
parser.add_argument('--outdir', type=Path, default=None, help='The output directory to checkout the labs (default: a temporary directory)')
127+
parser.add_argument('--commit', default='main', help='The git commit, tag, or branch to checkout (default: main)')
128+
parser.add_argument('--python-version', default='3.11', help='Python version to use (default: 3.11)')
129+
parser.add_argument('--uv-executable', default='uv', help='The `uv` executable to use (default: "uv")')
130+
parser.add_argument('--nbmake-timeout', type=int, default=3600, help='Timeout for running notebooks with nbmake (default: 3600)')
131+
parser.add_argument('--nbmake-kernel', default=None, help='Kernel to use for running notebooks with nbmake')
132+
parser.add_argument('--nbmake-allow-errors', action='store_true', help='Allow errors when running notebooks with nbmake')
133+
parser.add_argument('--nbmake-rerun', type=int, default=0, help='Number of times to rerun notebooks with nbmake')
134+
135+
parser.add_argument('nbfiles', nargs='*', help='Optional list of notebooks to run using nbmake.')
136+
137+
args = parser.parse_args()
138+
139+
setup_env(args.outdir,
140+
args.commit,
141+
args.python_version,
142+
args.nbfiles,
143+
args.uv_executable,
144+
args.nbmake_timeout,
145+
args.nbmake_kernel,
146+
args.nbmake_allow_errors,
147+
args.nbmake_rerun)
148+
149+
if __name__ == '__main__':
150+
main()

0 commit comments

Comments
 (0)