With exception handling and logging in place, the next step is managing your environment so your code runs the same way for your teammates and servers. We'll walk the core loop of "create a virtualenv → declare dependencies in pyproject.toml → install via uv", then outline optional extensions such as CI and pre-commit.
Key terms
- pyproject.toml: The standard file for declaring package metadata and dependencies.
- uv.lock: The lockfile created by
uvthat pins exact dependency versions for reproducibility. - Environment variable: A key-value supplied at runtime to store secrets such as API keys or file paths.
Core ideas
Study memo
- Time: 50–60 minutes
- Prereqs: Familiarity with virtualenv/uv setup and requests-based scripts
- Goal: Control dependencies and env vars through
pyproject.tomlplusuvcommands
Virtual environments isolate execution per project, while pyproject.toml gathers dependency declarations. Think of it as “keep everything in one folder” for your runtime.
Code examples
Why virtualenv matters (Core)
Installing libraries globally causes version clashes and makes parity between local and server environments painful. A virtualenv gives each project its own site-packages. If that feels abstract, treat it as "use a dedicated folder that only this project touches."
uv venv .venv
source .venv/bin/activate
python --version
On CI or servers, you can skip activation and run uv run python app.py to keep commands consistent.
Shape pyproject.toml (Core)
[project]
name = "mealbot"
version = "0.1.0"
description = "Meal notification bot"
requires-python = ">=3.12"
[project.dependencies]
requests = "^2.31.0"
python-dotenv = "^1.0.1"
[tool.uv]
dev-dependencies = ["pytest", "ruff"]
pyproject.toml centralizes metadata and dependencies. Start with name, version, and a couple of dependencies—simplicity beats perfection at this stage.
📦 What is pyproject.toml? A single configuration file that replaces scattered
setup.pyscripts by keeping build tools, metadata, and dependencies together.
Manage dependencies with uv (Core)
uv add requests typer
uv add --dev pytest
uv pip list
uv add updates both the pyproject and lockfile. Master uv add <package> and uv run python main.py first, then graduate to uv lock or uv sync --frozen for stricter reproducibility.
Handle environment variables (Core → Plus)
cp .env.example .env
Document keys in .env.example but leave values blank. At runtime, point uv to the file:
uv run --env-file .env python scripts/send_meal.py
This makes it trivial to swap between school accounts or personal accounts.
Suggested project layout (Optional)
mealbot/
├── pyproject.toml
├── uv.lock
├── src/mealbot/__init__.py
├── tests/
├── scripts/
└── README.md
Using a src layout helps catch incorrect imports before packaging. If that feels heavy, start by managing just pyproject.toml and uv.lock, then adopt the layout later.
CI and pre-commit hooks (Optional)
- Reuse cached virtualenvs in GitHub Actions with
uv setup-python. - Wire
uv run ruff checkanduv run pytestinto pre-commit hooks for consistent local/CI behavior.
Treat these as add-ons for collaboration rather than requirements for solo study.
Why it matters
Project hygiene ensures "works on my machine" never becomes a blocker. Managing pyproject.toml and uv.lock prevents version drift, and .env files keep sensitive values safe while sharing structure.
Practice
- Follow along: In a blank folder, run
uv init,uv add requests, anduv add --dev pytest, then inspectpyproject.toml. - Extend: Create
.env.exampleand capture logs fromuv run --env-fileto prove env vars load correctly. - Debug: Run
uv sync --frozen, editpyproject, trigger an error, then resolve it by updating the lockfile or reverting. - Done when:
pyproject,uv.lock, and.env.examplesit together and a single command reproduces the environment anywhere.
Wrap up
With virtualenvs and pyproject management in place, you eliminate package conflicts and "but it works locally" moments. Next we'll leverage this environment to automate testing and raise the confidence bar again.
💬 댓글
이 글에 대한 의견을 남겨주세요