Skip to content

Commit 89ccc73

Browse files
committed
fix: run student code inside a virtualenv with deps installed
Before running the entry point, create a venv and install deps from pyproject.toml (editable) or requirements.txt so imports don't fail. Surface install errors in section 5 of the verification report.
1 parent 4823f87 commit 89ccc73

1 file changed

Lines changed: 44 additions & 4 deletions

File tree

.github/scripts/verify_submission.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,41 @@ def get_dependencies(repo_path):
9797
return deps
9898

9999

100-
def try_run(repo_path, entry_point):
100+
def setup_venv(repo_path, tmpdir):
101+
"""Create a venv and install project dependencies. Returns (python_bin, error_msg)."""
102+
venv_dir = os.path.join(tmpdir, 'venv')
103+
r = run(['python', '-m', 'venv', venv_dir])
104+
if r.returncode != 0:
105+
return None, f"No se pudo crear el virtualenv: {r.stderr[:200]}"
106+
107+
python_bin = os.path.join(venv_dir, 'bin', 'python')
108+
pip_bin = os.path.join(venv_dir, 'bin', 'pip')
109+
path = Path(repo_path)
110+
111+
if (path / 'pyproject.toml').exists():
112+
r = run([pip_bin, 'install', '-e', '.', '--quiet'], cwd=repo_path, timeout=120)
113+
if r.returncode == 0:
114+
return python_bin, ""
115+
# Fall through to requirements.txt if editable install fails
116+
err = r.stderr[:200]
117+
else:
118+
err = ""
119+
120+
if (path / 'requirements.txt').exists():
121+
r = run([pip_bin, 'install', '-r', 'requirements.txt', '--quiet'], cwd=repo_path, timeout=120)
122+
if r.returncode == 0:
123+
return python_bin, ""
124+
err = r.stderr[:200]
125+
126+
# No deps or install failed — still return the venv python so stdlib code runs
127+
return python_bin, err
128+
129+
130+
def try_run(repo_path, entry_point, python_bin='python'):
101131
"""Try to run a Python file with a short timeout. Returns (ran_ok, output_snippet)."""
102132
try:
103133
r = subprocess.run(
104-
['python', entry_point, '--help'],
134+
[python_bin, entry_point, '--help'],
105135
capture_output=True, text=True, timeout=8,
106136
cwd=repo_path, input=''
107137
)
@@ -110,7 +140,7 @@ def try_run(repo_path, entry_point):
110140
return True, out or "(sin salida)"
111141
# Try without --help
112142
r2 = subprocess.run(
113-
['python', entry_point],
143+
[python_bin, entry_point],
114144
capture_output=True, text=True, timeout=5,
115145
cwd=repo_path, input='\n'
116146
)
@@ -218,6 +248,10 @@ def build_report(repo_url, results):
218248

219249
# Execution
220250
lines.append("### 5. Ejecución")
251+
install_err = results.get('install_error', '')
252+
if install_err:
253+
lines.append(f"{warn} Error al instalar dependencias en el virtualenv:")
254+
lines.append(f"\n```\n{install_err}\n```")
221255
if entry:
222256
ran_ok = results.get('ran_ok', False)
223257
run_output = results.get('run_output', '')
@@ -305,9 +339,15 @@ def main():
305339
entry = find_entry_point(dest)
306340
results['entry_point'] = entry
307341

342+
# Set up virtualenv and install deps before running
343+
python_bin, install_err = setup_venv(dest, tmpdir)
344+
results['install_error'] = install_err
345+
if python_bin is None:
346+
python_bin = 'python'
347+
308348
# Try to run
309349
if entry:
310-
ran_ok, run_output = try_run(dest, entry)
350+
ran_ok, run_output = try_run(dest, entry, python_bin)
311351
results['ran_ok'] = ran_ok
312352
results['run_output'] = run_output
313353

0 commit comments

Comments
 (0)