{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Virtual environments\n",
    "\n",
    "A virtual environment is a self-contained Python — a private\n",
    "directory with its own copy of the interpreter, its own `pip`, and\n",
    "its own `site-packages`. Using one per project is the difference\n",
    "between dependency hygiene and dependency chaos.\n",
    "\n",
    "**Time commitment:** 10-15 minutes\n",
    "\n",
    "**Prerequisites:**\n",
    "\n",
    "- Comfortable with the basics of `pip install`\n",
    "- You can open a terminal\n",
    "\n",
    "## Learning objectives\n",
    "\n",
    "By the end of this tutorial, you will be able to:\n",
    "\n",
    "- Create, activate, and deactivate a virtual environment with `venv`\n",
    "- Explain what activation actually does\n",
    "- Adopt a per-project workflow that keeps installs isolated"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "!!! note \"Browser note\"\n",
    "    The commands below run in your terminal, not in this page's browser kernel.\n",
    "    Pyodide doesn't expose a shell, so the bash blocks here are for reference —\n",
    "    copy them into a real terminal to follow along."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Why isolation matters\n",
    "\n",
    "Without virtual environments, every `pip install` adds to a single\n",
    "shared `site-packages` directory. Two projects that both depend on\n",
    "`requests` are fine; two projects that need *different versions* of\n",
    "`requests` are not. And `pip install` for the system Python on Linux\n",
    "or macOS is a recipe for breaking system tools that depend on\n",
    "specific package versions.\n",
    "\n",
    "A virtual environment gives each project its own sealed bubble.\n",
    "Installs go into that bubble; the system Python is untouched."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating a venv\n",
    "\n",
    "Python 3 ships with the `venv` module. From the root of your project:\n",
    "\n",
    "```bash\n",
    "python -m venv .venv\n",
    "```\n",
    "\n",
    "This creates a directory called `.venv` containing a Python\n",
    "interpreter and an empty `site-packages`. The leading dot is\n",
    "conventional — it suggests \"machine-specific, don't commit\", and\n",
    "most editors recognise the name automatically. Add `.venv/` to\n",
    "your `.gitignore`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Activating\n",
    "\n",
    "Activating a venv updates your shell's `PATH` so that `python` and\n",
    "`pip` resolve to the venv's copies, not the system ones. The\n",
    "activation command differs by shell:\n",
    "\n",
    "```bash\n",
    "# macOS / Linux (bash, zsh)\n",
    "source .venv/bin/activate\n",
    "\n",
    "# Windows (PowerShell)\n",
    ".venv\\Scripts\\Activate.ps1\n",
    "\n",
    "# Windows (cmd)\n",
    ".venv\\Scripts\\activate.bat\n",
    "```\n",
    "\n",
    "Most shells will then prefix your prompt with `(.venv)` so you can\n",
    "see at a glance that the environment is active."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What changes when you activate\n",
    "\n",
    "```bash\n",
    "which python      # /your/project/.venv/bin/python\n",
    "python --version  # whatever Python you used to create the venv\n",
    "pip list          # only pip and setuptools — a clean slate\n",
    "```\n",
    "\n",
    "Anything you `pip install` from now on lands in\n",
    "`.venv/lib/.../site-packages/`. When you `python my_script.py`,\n",
    "you're using the venv's interpreter, which can only see its own\n",
    "installed packages."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Deactivating\n",
    "\n",
    "```bash\n",
    "deactivate\n",
    "```\n",
    "\n",
    "That's a function provided by the activation script — there's\n",
    "nothing to install. Your `PATH` reverts to whatever it was before."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Per-project workflow\n",
    "\n",
    "The reliable pattern, applied identically to every Python project:\n",
    "\n",
    "```bash\n",
    "cd my-project\n",
    "python -m venv .venv\n",
    "source .venv/bin/activate\n",
    "pip install -r requirements.txt   # or pip install -e .\n",
    "```\n",
    "\n",
    "And on subsequent days:\n",
    "\n",
    "```bash\n",
    "cd my-project\n",
    "source .venv/bin/activate\n",
    "# … work …\n",
    "deactivate\n",
    "```\n",
    "\n",
    "Some teams find activation tedious and reach for a tool that does it\n",
    "automatically — direnv, mise, or one of the unified tools below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Beyond `venv`\n",
    "\n",
    "`venv` is in the standard library and Just Works. A few alternatives\n",
    "worth knowing about:\n",
    "\n",
    "- **uv.** A fast, all-in-one tool that handles venvs, dependency\n",
    "  resolution, and lock files with a single command. Increasingly the\n",
    "  default in modern Python tooling.\n",
    "- **conda.** Used heavily in scientific Python; manages non-Python\n",
    "  dependencies (CUDA, system libraries) alongside Python ones.\n",
    "- **pipx.** Specifically for installing Python *applications* (CLIs\n",
    "  like `black` or `ruff`) into their own venvs without you having to\n",
    "  manage them.\n",
    "- **Poetry, Hatch, PDM.** Project managers that wrap venv creation\n",
    "  alongside packaging.\n",
    "\n",
    "For learning Python — and for everything in this guide — `venv` is\n",
    "enough. Pick one of the above when a project's needs warrant it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recap and next steps\n",
    "\n",
    "- One venv per project; create with `python -m venv .venv`.\n",
    "- Activate to switch your shell to the venv's `python` and `pip`.\n",
    "- Add `.venv/` to `.gitignore`.\n",
    "\n",
    "Now that you can install things cleanly, the next step is putting\n",
    "your *own* code into installable shape —\n",
    "[Authoring a package](https://agilearn.co.uk/guides/packages-and-packaging/learn/05-authoring-a-package)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}