Programming with PythonPython Setup and First Programs › Day 43

Hands-on lab — Day 43: Installing Python and Virtual Environments

Commands

Setup

cd labs/sections/programming-with-python/day-043-installing-python-and-virtual-environments

Run

bash examples/venv_demo.sh
bash starter/venv_demo.sh

Test

bash tests/run_tests.sh

File tree

examples/venv_demo.sh
expected-output/FIELDS.md
expected-output/sample-macos.txt
metadata.yml
README.md
requirements/README.md
security.md
starter/venv_demo.sh
starter/venv-worksheet.md
tests/run_tests.sh
troubleshooting.md

Lab README

Day 043 lab — Create and Verify a Virtual Environment

Lesson

Purpose

Day 43's lesson explains why every project should keep its packages isolated in a virtual environment. This lab makes that concrete and offline: you create a venv with python3 -m venv, activate it, and watch which python and sys.prefix move inside the environment — proof, on your own machine, that the isolation is real. No packages are downloaded and no network is used.

Learning objectives

  • Create a virtual environment with python3 -m venv .venv.
  • Activate and deactivate it, and explain what activation changes.
  • Prove isolation by inspecting which python and sys.prefix before and after activation.
  • Record a project's dependencies in a requirements.txt file.
  • Run an automated test script and interpret its pass/fail output.

Prerequisites

  • The Day 43 lesson (read it first — it explains every concept this lab demonstrates).
  • Course 1 fluency: the terminal, PATH (Day 11), and package managers (Day 13).
  • Python 3 installed (python3 --version prints 3.x). See requirements/README.md if it is missing.

Supported operating systems

  • macOS — fully supported (tested on macOS with Apple Silicon, Python 3.14.0).
  • Linux — fully supported (any distribution with python3 and the venv module; install python3-venv on minimal Debian/Ubuntu).
  • Windows — use .venv\Scripts\activate in PowerShell, or run the scripts unchanged inside WSL (recommended). See troubleshooting.md.

Hardware requirements

Any computer made in roughly the last 15 years. The lab creates a tiny, empty environment in a temp directory; it needs no meaningful RAM, disk, or GPU.

Required software

  • python3 ≥ 3.8 with the venv module (bundled since Python 3.3).
  • bash ≥ 3.2 (preinstalled on macOS and Linux).

No PyPI packages, accounts, API keys, or network access are required.

Free and open-source options

Everything in this lab is free and open source: Python, the venv module, and pip all ship with Python at no cost, and PyPI (used in later labs, not this one) is a free public repository. No purchase or account is ever needed.

Installation

None beyond Python itself. Copy this directory (or clone the repository) and change into it:

cd labs/sections/programming-with-python/day-043-installing-python-and-virtual-environments

File structure

day-043-installing-python-and-virtual-environments/
├── README.md                       ← you are here
├── metadata.yml                    ← machine-readable lab metadata
├── starter/
│   ├── venv_demo.sh                ← YOUR working file (4 exercises)
│   └── venv-worksheet.md           ← worksheet for the practice assignment
├── examples/
│   └── venv_demo.sh                ← completed reference implementation
├── tests/
│   └── run_tests.sh                ← automated, offline checks
├── expected-output/
│   ├── sample-macos.txt            ← real captured run (macOS, Apple Silicon)
│   └── FIELDS.md                   ← required behaviour on every platform
├── requirements/
│   └── README.md                   ← dependency statement (just Python 3)
├── troubleshooting.md
└── security.md

How to run

From this directory:

## 1. See the finished result first
bash examples/venv_demo.sh

## 2. Your task: complete the four exercises in the starter, then run it
bash starter/venv_demo.sh

## 3. Check your work
bash tests/run_tests.sh

What the commands do

  • bash examples/venv_demo.sh — the reference script. It makes a temp directory, prints the interpreter version, creates .venv with python3 -m venv .venv, shows which python before activation, activates the venv, then shows which python, which pip, and sys.prefix all pointing inside .venv, writes a requirements.txt, deactivates, and deletes the temp directory on exit.
  • bash starter/venv_demo.sh — the same scaffolding with four numbered exercises for you to fill in: (1) create the venv, (2) activate it, (3) prove isolation by printing which python and sys.prefix, (4) deactivate. Each exercise comment names the exact command.
  • bash tests/run_tests.sh — offline checks: python3 is available, a venv can be created, sys.prefix points inside it, activation redirects which python, cleanup leaves nothing behind, the example runs and confirms isolation, and the starter still ships its four exercises.

Expected output

See expected-output/sample-macos.txt — a real captured run. The key lines:

--- Step 4: activate and prove isolation ---
which python -> /private/var/folders/.../venv-demo.qPEavX/.venv/bin/python
sys.prefix   -> /private/var/folders/.../venv-demo.qPEavX/.venv
OK: sys.prefix is inside the .venv — the environment is isolated.

Your temp path will differ on every run — only the shape matters. expected-output/FIELDS.md lists the required behaviour and documents platform differences.

Validation steps

  1. Run bash examples/venv_demo.sh — it must exit without errors and print OK: sys.prefix is inside the .venv.
  2. Complete starter/venv_demo.sh (replace all four EXERCISE_*_NOT_DONE lines) and run it; confirm activation changes which python.
  3. Fill in starter/venv-worksheet.md with your real before/after paths.
  4. Run the tests (next section) — all checks must pass.

Tests

bash tests/run_tests.sh

Expected final line: 11 checks, 0 failure(s). The command exits 0 on success and non-zero on any failure, so it can run in CI. It needs no network.

Cleanup

Nothing to clean up: both scripts do all their work in a temporary directory and remove it on exit (via a cleanup trap), even if a step fails. To reset your edited starter, restore it from git: git checkout -- starter/venv_demo.sh.

Troubleshooting

See troubleshooting.md for the full list (python vs python3, activation per shell and on Windows, missing python3-venv, keeping .venv out of git).

Security notes

See security.md. Short version: the scripts run no network calls, need no elevated privileges, work only in a temp directory, and never commit anything. Never commit a .venv folder; pin your dependencies.

Extension exercises

  1. With a venv active, run pip list and pip freeze — note that a fresh venv has almost nothing installed, which is the point of starting clean.
  2. Create two venvs in two folders and confirm, with sys.prefix, that each is independent of the other.
  3. Add a real .gitignore containing .venv/ to a scratch project and verify with git status that the environment is ignored while requirements.txt is tracked.
  • Previous day: Day 42 — Section Review: Your Computing Foundations Toolkit (labs/sections/computing-foundations/day-042-section-review-your-computing-foundations-toolkit/).
  • Next day: Day 44 — Variables and Types (labs/sections/programming-with-python/day-044-variables-and-types/, to be written).

Expected output

FIELDS.md

# Required behaviour (all platforms)

A correct run of `examples/venv_demo.sh` must, on any supported system:

1. Print the interpreter version (`Python 3.x.y`).
2. Create a `.venv` directory containing an `activate` script and its own
   `python` (in `.venv/bin/` on macOS and Linux, `.venv\Scripts\` on Windows).
3. Show `which python` pointing at the **global** interpreter before
   activation and at `.../.venv/bin/python` after activation.
4. Report `sys.prefix` as a path that ends in `.venv` — the proof of
   isolation — and print the `OK: ... the environment is isolated.` line.
5. Write a `requirements.txt` documenting the Python version and the
   standard-library-only note.
6. Deactivate and remove the temporary directory, leaving nothing behind.

`sample-macos.txt` in this directory is a real captured run (macOS, Apple
Silicon, Python 3.14.0, 2026-07-12).

## Platform differences (documented, not fabricated)

- **Temp path.** The working directory is created by `mktemp` and is random;
  every run prints a different path. macOS resolves `/var` to `/private/var`,
  so paths appear under `/private/var/folders/...`; Linux typically uses
  `/tmp/venv-demo.XXXXXX`.
- **Global interpreter path.** Before activation, `which python` reflects
  wherever your Python came from — e.g. `/opt/homebrew/...` (Homebrew on Apple
  Silicon), `/usr/bin/python3` (system), or a `pyenv` shim. Only the *change*
  on activation matters, not the exact path.
- **`.venv/bin` contents.** Newer Python versions add extra convenience
  symlinks (for example Python 3.14 adds a `𝜋thon` alias). The essential
  entries are `activate`, `python`, `pip`.
- **Windows.** Activation is `.venv\Scripts\activate` and the interpreter is
  `.venv\Scripts\python.exe`. Run the equivalent commands in PowerShell, or run
  the scripts unchanged inside WSL, where the Linux paths apply.

sample-macos.txt

Real captured run of `bash examples/venv_demo.sh` on macOS (Apple Silicon,
Python 3.14.0, 2026-07-12). The temp path is randomly generated, so yours will
differ — only the shape matters.

=== Virtual Environment Demo ===
Working directory: /private/var/folders/7j/xxxx/T/venv-demo.qPEavX

--- Step 1: the interpreter ---
Python 3.14.0

--- Step 2: create the virtual environment (offline) ---
Created .venv/ — contents of .venv/bin (or Scripts on Windows):
    activate
    pip
    pip3
    python
    python3

--- Step 3: which python BEFORE activation ---
which python -> /opt/homebrew/opt/python@3.14/libexec/bin/python

--- Step 4: activate and prove isolation ---
which python -> /private/var/folders/7j/xxxx/T/venv-demo.qPEavX/.venv/bin/python
which pip    -> /private/var/folders/7j/xxxx/T/venv-demo.qPEavX/.venv/bin/pip
sys.prefix   -> /private/var/folders/7j/xxxx/T/venv-demo.qPEavX/.venv
OK: sys.prefix is inside the .venv — the environment is isolated.

--- Step 5: record dependencies in requirements.txt ---
requirements.txt:
    # Built and verified with Python 3.14.0
    # This project uses only the Python standard library — no PyPI packages required.

--- Step 6: deactivate ---
which python -> /opt/homebrew/opt/python@3.14/libexec/bin/python  (back to global)

=== Demo complete — temp directory will be removed on exit ===


Test run (`bash tests/run_tests.sh`), same machine:

Testing venv creation and isolation (offline) ...
  ok: python3 is available
  ok: python3 -m venv creates an environment
  ok: environment has bin/activate
  ok: environment has its own python
  ok: sys.prefix points inside the venv
  ok: activation redirects 'which python' into the venv
  ok: cleanup leaves nothing behind
  ok: examples/venv_demo.sh exits successfully
  ok: example confirms isolation
  ok: example cleans up its temp directory
  ok: starter ships all four exercises

11 checks, 0 failure(s).

Source files

examples/venv_demo.sh (2683 bytes)
#!/usr/bin/env bash
# Day 043 lab — completed reference implementation.
# Creates a virtual environment in a temporary directory, proves that
# activation isolates python/pip, writes a requirements.txt, then
# deactivates and cleans everything up. Fully OFFLINE: no network needed.
#
# Run from the lab directory:
#   bash examples/venv_demo.sh
set -euo pipefail

# Work in a throwaway temp directory so nothing is left in your project.
# Resolve symlinks (on macOS /var is a link to /private/var) so later path
# comparisons against sys.prefix line up exactly.
work_dir="$(mktemp -d "${TMPDIR:-/tmp}/venv-demo.XXXXXX")"
work_dir="$(cd "${work_dir}" && pwd -P)"
# Always clean up, even if a command fails partway through.
cleanup() {
  # Leaving an active venv is harmless in a subshell, but deactivate if we can.
  type deactivate >/dev/null 2>&1 && deactivate || true
  rm -rf "${work_dir}"
}
trap cleanup EXIT

echo "=== Virtual Environment Demo ==="
echo "Working directory: ${work_dir}"
cd "${work_dir}"

echo
echo "--- Step 1: the interpreter ---"
python3 --version

echo
echo "--- Step 2: create the virtual environment (offline) ---"
python3 -m venv .venv
echo "Created .venv/ — contents of .venv/bin (or Scripts on Windows):"
ls .venv/bin >/dev/null 2>&1 && ls .venv/bin | sed 's/^/    /' || true

echo
echo "--- Step 3: which python BEFORE activation ---"
before="$(command -v python || echo '(no python on PATH)')"
echo "which python -> ${before}"

echo
echo "--- Step 4: activate and prove isolation ---"
# shellcheck disable=SC1091
source .venv/bin/activate
after="$(command -v python)"
echo "which python -> ${after}"
echo "which pip    -> $(command -v pip)"
prefix="$(python -c 'import sys; print(sys.prefix)')"
echo "sys.prefix   -> ${prefix}"

# Confirm sys.prefix really points inside our .venv folder.
case "${prefix}" in
  "${work_dir}"/.venv*) echo "OK: sys.prefix is inside the .venv — the environment is isolated." ;;
  *) echo "WARNING: sys.prefix is not inside .venv" ; exit 1 ;;
esac

echo
echo "--- Step 5: record dependencies in requirements.txt ---"
# A fresh venv installs no third-party packages; document that we rely on the
# standard library only, and pin the Python version used to build it.
{
  echo "# Built and verified with $(python --version)"
  echo "# This project uses only the Python standard library — no PyPI packages required."
} > requirements.txt
echo "requirements.txt:"
sed 's/^/    /' requirements.txt

echo
echo "--- Step 6: deactivate ---"
deactivate
echo "which python -> $(command -v python || echo '(no python on PATH)')  (back to global)"

echo
echo "=== Demo complete — temp directory will be removed on exit ==="
metadata.yml (615 bytes)
lesson_id: D043
day: 43
kind: configuration-activity
languages: [bash, python]
setup_commands:
  - cd labs/sections/programming-with-python/day-043-installing-python-and-virtual-environments
run_commands:
  - bash examples/venv_demo.sh
  - bash starter/venv_demo.sh
test_commands:
  - bash tests/run_tests.sh
cleanup_commands:
  - '# nothing to clean: the scripts use a temp directory and remove it themselves'
requires_network: false
requires_api_key: false
estimated_minutes: 30
last_executed: '2026-07-12'
executed_on: 'macOS (Apple Silicon), Python 3.14.0, bash tests/run_tests.sh → 11 checks, 0 failure(s).'
requirements/README.md (1417 bytes)
# Dependencies — Day 043 lab

**Just Python 3 and a POSIX shell.** There are no PyPI packages to install and
no network access is required at any step — creating a virtual environment uses
only tools that ship with Python.

- `python3` **≥ 3.8** (any modern 3.x is fine; the `venv` module has shipped
  with Python since 3.3). Preinstalled on macOS and most Linux distributions.
- `bash` ≥ 3.2 (preinstalled on macOS and Linux).

## Checking what you have

```bash
python3 --version
```

If that prints `Python 3.x.y`, you are ready.

## If Python 3 is missing

Install it once, using the package-manager skills from Day 13:

- **macOS:** `brew install python` (Homebrew), or download the installer from
  the official python.org downloads page.
- **Debian/Ubuntu Linux:** `sudo apt update && sudo apt install python3 python3-venv`
- **Fedora Linux:** `sudo dnf install python3`
- **Windows:** install from the official python.org downloads page (tick "Add
  Python to PATH"), or use WSL and follow the Linux instructions.

On some minimal Debian/Ubuntu systems the `venv` module is packaged
separately — that is why `python3-venv` is listed above. If
`python3 -m venv .venv` complains that `venv` is unavailable, install that
package.

This lab installs nothing else. Later labs will declare their Python packages
in a `requirements.txt`, which is exactly the reproducibility habit this lesson
introduces.
starter/venv_demo.sh (1892 bytes)
#!/usr/bin/env bash
# Day 043 lab — YOUR working file.
#
# The scaffolding (temp directory, cleanup, the interpreter check) is done for
# you. Your job is the four numbered exercises below: replace each placeholder
# line with the single command named in its comment. The completed reference is
# examples/venv_demo.sh — try to do it yourself first, then compare.
#
# Everything here is OFFLINE: no network is needed at any step.
#
# Run from the lab directory:
#   bash starter/venv_demo.sh
set -euo pipefail

# --- Scaffolding (already done for you) ---
work_dir="$(mktemp -d "${TMPDIR:-/tmp}/venv-demo.XXXXXX")"
cleanup() {
  type deactivate >/dev/null 2>&1 && deactivate || true
  rm -rf "${work_dir}"
}
trap cleanup EXIT

echo "=== Virtual Environment Demo (starter) ==="
echo "Working directory: ${work_dir}"
cd "${work_dir}"

echo
echo "--- The interpreter (already done) ---"
python3 --version

echo
echo "--- Exercise 1: create a virtual environment named .venv ---"
# Replace the next line with:  python3 -m venv .venv
echo "EXERCISE_1_NOT_DONE: create the .venv here"

echo
echo "--- Exercise 2: activate the environment ---"
# Replace the next line with:  source .venv/bin/activate
echo "EXERCISE_2_NOT_DONE: activate the .venv here"

echo
echo "--- Exercise 3: prove isolation ---"
# After activating, these two commands prove the environment is active.
# Replace the next line with BOTH commands (one per line):
#   command -v python
#   python -c 'import sys; print("sys.prefix:", sys.prefix)'
echo "EXERCISE_3_NOT_DONE: print 'which python' and sys.prefix here"

echo
echo "--- Exercise 4: deactivate the environment ---"
# Replace the next line with:  deactivate
echo "EXERCISE_4_NOT_DONE: deactivate the .venv here"

echo
echo "=== Done — temp directory will be removed on exit ==="
echo "When all four EXERCISE_*_NOT_DONE lines are replaced, run tests/run_tests.sh."
starter/venv-worksheet.md (1785 bytes)
# Virtual environment worksheet — Day 043

Fill this in for **your** machine as you work through the exercises. The goal is
to see, with your own eyes, that activating a virtual environment changes which
Python you are using.

## 1. Your Python

Run `python3 --version` and record the output:

- My Python version: `____________________`

## 2. `which python` before activation

Before activating any environment, run `which python` (or `command -v python`)
and record the full path:

- Before activation, `which python` prints: `____________________`

## 3. Create and activate

Run these from a scratch folder:

```bash
mkdir venv-demo && cd venv-demo
python3 -m venv .venv
source .venv/bin/activate
```

- Did your prompt gain a `(.venv)` marker? (yes / no): `______`

## 4. `which python` after activation

With the environment active, run `which python` again:

- After activation, `which python` prints: `____________________`
- Is this path different from step 2? (yes / no): `______`

## 5. Prove isolation with `sys.prefix`

Run:

```bash
python -c "import sys; print(sys.prefix)"
```

- `sys.prefix` prints: `____________________`
- Does this path end in `.venv`? (yes / no): `______`

## 6. Explain it (4–6 sentences)

In your own words, what did activation change, and why does `sys.prefix`
pointing inside `.venv` prove your project's packages are isolated from the
global Python?

```
____________________________________________________________________

____________________________________________________________________

____________________________________________________________________
```

## 7. Clean up

```bash
deactivate
cd .. && rm -rf venv-demo
```

- After `deactivate`, `which python` prints: `____________________`
  (it should match step 2 again).
tests/run_tests.sh (3690 bytes)
#!/usr/bin/env bash
# Tests for the Day 043 lab. Run from the lab directory:
#   bash tests/run_tests.sh
#
# Verifies, entirely OFFLINE, that a virtual environment can be created, that
# activation isolates the interpreter (sys.prefix points inside the venv), and
# that cleanup leaves nothing behind. Also checks that the completed example
# script runs and that the starter still ships its four exercises.
set -u

lab_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
failures=0
checks=0

check() {
  local label="$1" ok="$2"
  checks=$((checks + 1))
  if [ "${ok}" = "yes" ]; then
    echo "  ok: ${label}"
  else
    echo "  FAIL: ${label}"
    failures=$((failures + 1))
  fi
}

echo "Testing venv creation and isolation (offline) ..."

# Python 3 must be available.
if command -v python3 >/dev/null 2>&1; then
  check "python3 is available" "yes"
else
  check "python3 is available" "no"
  echo
  echo "${checks} checks, ${failures} failure(s)."
  exit 1
fi

# 1. A venv can be created in a throwaway temp directory.
# Resolve symlinks so the path lines up with what sys.prefix reports.
work_dir="$(mktemp -d "${TMPDIR:-/tmp}/venv-test.XXXXXX")"
work_dir="$(cd "${work_dir}" && pwd -P)"
created="no"
if python3 -m venv "${work_dir}/.venv" >/dev/null 2>&1; then created="yes"; fi
check "python3 -m venv creates an environment" "${created}"

# 2. The environment has an activate script and a python interpreter.
[ -f "${work_dir}/.venv/bin/activate" ] && check "environment has bin/activate" "yes" || check "environment has bin/activate" "no"
[ -x "${work_dir}/.venv/bin/python" ] && check "environment has its own python" "yes" || check "environment has its own python" "no"

# 3. After activation, sys.prefix points INSIDE the venv.
prefix=""
# shellcheck disable=SC1090
if source "${work_dir}/.venv/bin/activate" 2>/dev/null; then
  prefix="$(python -c 'import sys; print(sys.prefix)' 2>/dev/null)"
  which_python="$(command -v python)"
  type deactivate >/dev/null 2>&1 && deactivate || true
fi
case "${prefix}" in
  "${work_dir}"/.venv*) check "sys.prefix points inside the venv" "yes" ;;
  *) check "sys.prefix points inside the venv" "no" ;;
esac
case "${which_python:-}" in
  "${work_dir}"/.venv/bin/python) check "activation redirects 'which python' into the venv" "yes" ;;
  *) check "activation redirects 'which python' into the venv" "no" ;;
esac

# 4. Cleanup leaves nothing behind.
rm -rf "${work_dir}"
[ ! -e "${work_dir}" ] && check "cleanup leaves nothing behind" "yes" || check "cleanup leaves nothing behind" "no"

# 5. The completed example script runs end to end and confirms isolation.
if out="$(bash "${lab_dir}/examples/venv_demo.sh" 2>&1)"; then
  check "examples/venv_demo.sh exits successfully" "yes"
  echo "${out}" | grep -q "the environment is isolated" && check "example confirms isolation" "yes" || check "example confirms isolation" "no"
else
  check "examples/venv_demo.sh exits successfully" "no"
  echo "${out}" | sed 's/^/    /'
fi

# 6. The example leaves no temp directory behind (it cleans up its own).
leftover="$(find "${TMPDIR:-/tmp}" -maxdepth 1 -name 'venv-demo.*' 2>/dev/null | wc -l | tr -d ' ')"
[ "${leftover}" = "0" ] && check "example cleans up its temp directory" "yes" || check "example cleans up its temp directory" "no"

# 7. The starter still ships its four exercises for the learner.
starter="${lab_dir}/starter/venv_demo.sh"
missing=0
for n in 1 2 3 4; do
  grep -q "EXERCISE_${n}_NOT_DONE" "${starter}" || missing=1
done
[ "${missing}" = "0" ] && check "starter ships all four exercises" "yes" || check "starter ships all four exercises" "no"

echo
echo "${checks} checks, ${failures} failure(s)."
[ "${failures}" -eq 0 ]

Troubleshooting

Troubleshooting — Day 043 lab

python3: command not found

Python 3 is not installed or not on your PATH. See requirements/README.md for the one-line install for your system. On Windows, python (not python3) is often the command; if python --version shows a 3.x version, use python in place of python3 for the venv-creation step.

python vs python3 confusion

Outside a virtual environment, prefer python3 — on some systems python still means the old Python 2, or does not exist at all. Inside an active venv, python is correct and points at the venv's interpreter. When in doubt, run which python (macOS/Linux) or where python (Windows) to see exactly which interpreter you are calling.

python3 -m venv fails with "ensurepip is not available"

On some minimal Debian/Ubuntu installs the venv support is a separate package. Install it: sudo apt install python3-venv. No other lab step needs elevated privileges.

source .venv/bin/activate — "no such file or directory"

Either you are not in the folder that contains .venv, or the environment did not build. List it: ls .venv/bin/ should show an activate file. On Windows the activation path is different:

  • PowerShell: .venv\Scripts\Activate.ps1
  • Command Prompt: .venv\Scripts\activate.bat

If PowerShell blocks the script with an execution-policy error, run it inside WSL instead, where the Linux commands apply unchanged.

Activation "doesn't work" — which python looks the same

Activation only affects the shell you run it in. If you opened a new terminal tab or ran the script in a subshell, activate again in the shell you are actually using. Also note: some shells do not show the (.venv) prompt marker even when the venv is active — trust which python and sys.prefix, not the prompt text.

Should I commit .venv to git?

No. A virtual environment is large, machine-specific, and fully rebuildable. Add it to your .gitignore:

.venv/

Commit your requirements.txt instead — that is the portable recipe that lets anyone rebuild an identical environment.

The tests report a failure

Run bash tests/run_tests.sh and read which line says FAIL. Each check names exactly what it verified (venv created, sys.prefix inside the venv, cleanup, the example script). The most common cause is a Python that is too old or a missing python3-venv package — fix that first, then re-run.

Security notes

Security notes — Day 043 lab

  • What the scripts do: create a Python virtual environment inside a throwaway temporary directory, print which interpreter is active, write a small requirements.txt, then deactivate and delete the temp directory. They make no network connections, need no elevated privileges, and write nothing outside their own temp folder.

  • Temp directory only. All work happens in a directory created by mktemp and removed on exit (even if a step fails, via a cleanup trap). Nothing is written into your project or your home directory, so there is nothing to accidentally commit from this lab.

  • Never commit a virtual environment. In your own projects, add .venv/ to .gitignore. A committed venv is large, machine-specific, and can leak local paths; the correct thing to share is the requirements.txt recipe.

  • Pin your dependencies. When you start installing real packages from PyPI, record exact versions (pip freeze > requirements.txt, which writes lines like requests==2.32.3). Pinning is a security practice as well as a reproducibility one: it stops an unexpected or tampered newer version from being pulled in silently under a name you already trust. Install only packages you mean to, and watch for typo-squatted names (e.g. reqeusts for requests).

  • Read before you run. Both scripts here are short and commented — read them first. Running unread shell scripts is a common way developers get compromised; every script in this course is small enough to read before executing.