Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ Thumbs.db
# hyf
.hyf/score.json

# Python virtual environments
.venv/
venv/
env/
ENV/

# Python bytecode and caches
__pycache__/
*.pyc
*.pyo
*.pyd
.pytest_cache/
.ruff_cache/
.mypy_cache/

# Python build / dist artifacts
*.egg-info/
build/
dist/

# Editor and IDE settings
.vscode/
.idea/
Expand Down
51 changes: 49 additions & 2 deletions .hyf/grader_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ check_gitignore_python() {
# Warns when Python cache patterns are absent from .gitignore.
local gi="${1:-.gitignore}"
if [[ ! -f "$gi" ]]; then
warn ".gitignore is missing — add one so __pycache__/ and *.pyc are not committed"
warn ".gitignore is missing — add one so __pycache__/, *.pyc, and .venv/ are not committed"
return 0
fi
local ok=true
Expand All @@ -117,7 +117,54 @@ check_gitignore_python() {
warn ".gitignore missing .env — secret files should not be committed"
ok=false
fi
if [[ "$ok" = true ]]; then pass ".gitignore correctly excludes __pycache__/, *.pyc, and .env"; fi
# Either .venv/ or venv/ must be excluded (the two common conventions).
if ! grep -qE "^\.?venv/?$" "$gi"; then
warn ".gitignore missing .venv/ (or venv/) — virtual environment folder must not be committed"
ok=false
fi
if [[ "$ok" = true ]]; then pass ".gitignore correctly excludes __pycache__/, *.pyc, .env, and .venv/"; fi
return 0
}

check_no_venv_committed() {
# Usage: check_no_venv_committed
# Fails when a virtual-environment folder is tracked by git. The venv is a
# per-machine artefact: committing it bloats the repo, leaks local paths,
# and breaks the moment a teammate on another OS clones the repo.
# Detection prefers `git ls-files` (only flags tracked entries); falls back
# to a filesystem check when git is unavailable.
local found=""
if command -v git &>/dev/null && git rev-parse --is-inside-work-tree &>/dev/null; then
found=$(git ls-files | grep -E "^(\.venv|venv|env|ENV)/" | head -3 || true)
else
for d in .venv venv env ENV; do
[[ -d "$d" ]] && found="$d/"
done
fi
if [[ -n "$found" ]]; then
fail "virtual environment folder is committed — add .venv/ to .gitignore and 'git rm -r --cached .venv' to remove it from history. Tracked entries:
${found}"
else
pass "no virtual environment folder committed"
fi
return 0
}

check_lockfile_present() {
# Usage: check_lockfile_present
# Warns when neither requirements.txt nor uv.lock nor pyproject.toml exists
# at the repo root. The lockfile is the *recipe* a fresh venv needs to
# reproduce the student's environment — without it CI cannot install
# whatever the student's code imports.
if [[ -f requirements.txt ]] || [[ -f uv.lock ]] || [[ -f pyproject.toml ]]; then
local seen=()
[[ -f requirements.txt ]] && seen+=("requirements.txt")
[[ -f uv.lock ]] && seen+=("uv.lock")
[[ -f pyproject.toml ]] && seen+=("pyproject.toml")
pass "lockfile present: ${seen[*]}"
else
warn "no requirements.txt / uv.lock / pyproject.toml at repo root — run 'pip freeze > requirements.txt' inside your activated venv and commit it (see Week 1 Ch1)"
fi
return 0
}

Expand Down
10 changes: 9 additions & 1 deletion .hyf/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,17 @@ if [ -s task-2/AI_DEBUG.md ]; then
fi
fi

# .gitignore should exclude Python cache files.
# .gitignore should exclude Python cache files + the venv folder.
check_gitignore_python ".gitignore"

# Virtual environment folders (.venv/, venv/) must not be committed.
# Curriculum: Week 1 Ch1 "Don't commit the venv folder".
check_no_venv_committed

# A lockfile (requirements.txt / uv.lock / pyproject.toml) must exist at the
# repo root so a fresh venv can be reproduced from it.
check_lockfile_present

print_results "Week 1 Autograder"

# ── Final score ──────────────────────────────────────────────────────────────
Expand Down