Project Setup
Getting a reproducible development environment off the ground
Concepts
- A virtual environment is an isolated copy of Python
with its own set of packages
- Installing something for one project does not affect any other project on the same machine
- Why do research projects need virtual environments if we're just writing scripts for our own use?
- uv manages both the virtual environment and the packages inside it
uv addinstalls a package and records it inpyproject.tomluv syncrecreates the environment from that recorduv run somethingruns in the environment- Or activate it with
source .venv/bin/activateand runsomething - Explain what adding a dependency with
uv addactually does topyproject.tomlanduv.lock
uv.lockpins the exact version of every package (including transitive dependencies) so that anyone who runsuv syncgets bit-for-bit the same environment you tested with- What would go wrong if two researchers are working on the same project but have different versions of a shared library?
pyproject.tomlis the single source of truth for project metadata, dependencies, and tool configuration- Show me what a minimal
pyproject.tomllooks like for a Python web application
- Show me what a minimal
- The
[tool.taskipy.tasks]section ofpyproject.tomlstores the shell commands needed to build, test, and run the project so that no one has to remember or retype themtask <name>runs any task by name.- What taskipy tasks should a research Python project have by default?
Create the project with uv
- Why uv instead of pip or conda for research projects
- What are the disadvantages of uv versus pip or conda for managing a research project?
uv init- Walk me through what
uv initcreates and what each generated file does
- Walk me through what
- Structure of a minimal
pyproject.toml- Explain each field in a minimal
pyproject.tomlfor a Python web application
- Explain each field in a minimal
Add dependencies
uv addfor runtime packages- Add litestar, htpy, and snailz as runtime dependencies to this project
uv add --devfor linting and testing- Add ruff and pytest as development dependencies using uv
- Checking
uv.lockinto version control and why it matters- What would go wrong if I added
uv.lockto.gitignore?
- What would go wrong if I added
- PEP 723 headers
- What is a PEP 723 header and when would I use one in a research script?
Automate tasks with taskipy
- Storing tasks in
pyproject.tomlalongside dependencies and tool configuration so the project has a single configuration file- Add a taskipy task to update all dependencies in the project to their latest allowed versions
- Writing taskipy tasks for running the server, tests, and linters
- Write a taskipy tasks for running the ruff linter for this project
Lay out project
- Directories for source code, tests, static assets, and data
- Describe a layout for a simple Python web application that separates source code, tests, static assets, and data
- Prompting an LLM to propose a layout and evaluating the result
- What questions should I ask to decide whether an LLM's suggested project layout is well-organized?
- Finish with a "hello world" script that imports each major dependency
and run it to confirm everything is wired up
- Write a hello world script that imports litestar, htpy, and snailz and prints their version numbers to confirm they are all installed correctly
Check for Understanding
Why does pinning exact package versions in a lock file matter for reproducibility?
A package like litestar may release a new version that changes behavior or breaks an API.
If you only record litestar>=0.1,
anyone who installs the project later may get a different version than you tested with,
and the code may fail in ways that are hard to diagnose.
A lock file records the exact version such as litestar==2.14.0 so every installation is identical.
What is the difference between uv add and uv add --dev?
uv add installs a package as a runtime dependency:
something the application needs to run.
uv add --dev installs a package as a development dependency:
something only needed during development,
such as linters, test frameworks, type checkers.
Development dependencies are not installed when someone deploys or imports the package in another project.
If you delete your .venv directory, what command recreates it with the same package versions?
uv sync reads pyproject.toml and uv.lock and recreates the environment
with exactly the same versions that were pinned.
You do not need to remember which packages to install or which versions to use.
Why use taskipy rather than just writing the commands down in a README?
Taskipy makes commands executable with a single short name like task test or task run
rather than requiring the user to copy-paste from the README,
remember flags,
or navigate to the right directory.
It also serves as living documentation that is always up to date,
because if the command changes,
pyproject.toml changes too.
Exercises
Extend the tasks
Add two new tasks to the [tool.taskipy.tasks] section of pyproject.toml:
one that opens a Python REPL inside the virtual environment,
and one that prints the exact Python version in use.
Run both to confirm they work.
Ask the LLM to help,
then read the generated task definitions
and make sure you understand what each one does before accepting it.
Explore dependency trees
Run uv tree and examine the output.
Identify which of your runtime dependencies pulls in the most transitive packages.
Ask the LLM to explain why that dependency has so many sub-dependencies
and evaluate whether the explanation makes sense given what you know about the package.
Reproduce from scratch
Clone the repository into a fresh directory on your machine
(or ask a classmate to do it on theirs).
Prompt an LLM to set up an environment using the instructions in pyproject.toml and the README,
then check that the "hello world" script runs.
Pin a specific version
Prompt the LLM to change the snailz dependency to a specific older version.
Observe what changes in pyproject.toml and uv.lock,
then restore the original constraint
and explain the difference between a version constraint and a pinned version in one sentence.