Python & FastAPI · Lesson 1 of 10
Environment Setup: venv, pip, and pyproject.toml
Why Environment Setup Matters
Every broken Python project starts the same way: pip install pandas run globally, three projects fighting over package versions, "it works on my machine" becoming a weekly complaint.
Professional Python work means one isolated environment per project. This lesson sets you up the right way from day one.
1. Python Version Management with pyenv
Before creating any environment, control which Python version you're running.
Install pyenv (Linux/macOS):
curl https://pyenv.run | bashInstall pyenv-win (Windows):
pip install pyenv-win --target $HOME\.pyenvCommon pyenv commands:
pyenv install 3.12.3 # install a specific version
pyenv global 3.12.3 # set default for your shell
pyenv local 3.11.9 # set version for this directory only (writes .python-version)
pyenv versions # list all installed versions
python --version # verify active versionA .python-version file checked into your repo pins the Python version for every collaborator automatically.
2. Virtual Environments with venv
venv is built into Python 3.3+. No install needed.
Creating and Activating
# create
python -m venv .venv
# activate — Linux/macOS
source .venv/bin/activate
# activate — Windows PowerShell
.venv\Scripts\Activate.ps1
# activate — Windows CMD
.venv\Scripts\activate.bat
# verify — you should see (.venv) in your prompt
which python # Linux/macOS: /your/project/.venv/bin/python
where python # WindowsDeactivating
deactivateWhat's Inside .venv
.venv/
bin/ # python, pip, and installed script entry points
lib/ # site-packages — where installed packages live
pyvenv.cfg # metadata: which Python version, base prefixAlways add .venv/ to .gitignore. Never commit it.
3. pip: Installing and Managing Packages
Basic Operations
pip install requests # latest version
pip install requests==2.31.0 # pin exact version
pip install "requests>=2.28,<3" # version range
pip install -r requirements.txt # install from file
pip install -e . # editable install (local package)
pip uninstall requests # remove
pip list # show installed packages
pip show requests # details on one package
pip outdated # packages with newer versionsrequirements.txt
pip freeze > requirements.txt # capture current state
pip install -r requirements.txt # restore exact stateA requirements.txt locks your full dependency tree including transitive dependencies. Good for deployment, not great for library development (use version ranges in pyproject.toml instead).
requirements split by environment
requirements/
base.txt # runtime dependencies
dev.txt # -r base.txt, plus: pytest, black, ruff, mypy
prod.txt # -r base.txt, plus: gunicorn, sentry-sdkpip install -r requirements/dev.txt4. pyproject.toml: The Modern Standard
pyproject.toml replaces setup.py and setup.cfg. It's the single config file for your project.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-pipeline-tool"
version = "0.1.0"
description = "Internal ETL pipeline toolkit"
requires-python = ">=3.11"
dependencies = [
"requests>=2.28",
"pandas>=2.0",
"pydantic>=2.0",
"typer>=0.12",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-cov",
"ruff",
"mypy",
"black",
]
[project.scripts]
my-tool = "my_pipeline_tool.cli:app" # CLI entry point
[tool.ruff]
line-length = 100
select = ["E", "F", "I", "UP"]
[tool.mypy]
strict = true
python_version = "3.11"
[tool.pytest.ini_options]
testpaths = ["tests"]Install in editable mode with all dev extras:
pip install -e ".[dev]"5. Poetry: Dependency Management Done Right
Poetry is the most popular tool for managing Python project dependencies with a lockfile.
Install Poetry
curl -sSL https://install.python-poetry.org | python3 -Start a new project
poetry new my-project # creates folder with structure
cd my-project
poetry shell # activates the managed venvAdd dependencies
poetry add requests pandas # add runtime deps
poetry add --group dev pytest ruff # add dev-only deps
poetry add "fastapi>=0.110" # with version constraint
poetry remove requests # remove a depInstall from lockfile
poetry install # install everything
poetry install --only main # skip dev deps (CI/prod)Key files Poetry manages
pyproject.toml # your declared dependencies (human-edited)
poetry.lock # exact pinned versions of everything (commit this!)The lockfile guarantees identical installs across every machine. Always commit poetry.lock.
Common workflow
poetry install # after cloning a repo
poetry add <pkg> # add a new dep
poetry update # update deps within constraints
poetry run pytest # run a command inside the venv
poetry build # build a distributable package
poetry publish # publish to PyPI6. Project Structure for Professional Python
This is the layout used for automation tools, pipelines, and internal packages:
my-project/
├── .python-version # pins Python version (pyenv)
├── .venv/ # virtual environment (git-ignored)
├── .env # local secrets (git-ignored)
├── .env.example # template for .env (committed)
├── .gitignore
├── pyproject.toml # project metadata + tool config
├── poetry.lock # pinned dependency tree
├── README.md
│
├── src/
│ └── my_project/ # main package (use underscores)
│ ├── __init__.py
│ ├── cli.py # Typer CLI entry point
│ ├── config.py # Settings from environment
│ ├── pipeline.py # core logic
│ └── utils.py # shared helpers
│
├── tests/
│ ├── conftest.py # pytest fixtures
│ ├── test_pipeline.py
│ └── test_utils.py
│
├── scripts/
│ └── seed_data.py # one-off scripts, not part of package
│
└── Makefile # common task shortcutsMinimal Makefile
.PHONY: install dev test lint typecheck
install:
poetry install --only main
dev:
poetry install
test:
poetry run pytest --cov=src --cov-report=term-missing
lint:
poetry run ruff check src tests
typecheck:
poetry run mypy src
format:
poetry run black src tests
poetry run ruff check --fix src tests7. Environment Variables and .env
Never hardcode secrets or environment-specific config.
.env file
DATABASE_URL=postgresql://user:pass@localhost/mydb
API_KEY=sk-secret-key
DEBUG=true
LOG_LEVEL=INFOLoading .env with python-dotenv
from dotenv import load_dotenv
import os
load_dotenv() # reads .env from current directory
db_url = os.environ["DATABASE_URL"]
debug = os.getenv("DEBUG", "false").lower() == "true"Typed settings with Pydantic
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
api_key: str
debug: bool = False
log_level: str = "INFO"
class Config:
env_file = ".env"
settings = Settings() # validates and loads at startup
print(settings.database_url)8. Code Quality Tools
Install these in every project:
| Tool | Purpose | Command |
|------|---------|---------|
| ruff | Linting + import sorting (fast) | ruff check . |
| black | Code formatting | black . |
| mypy | Static type checking | mypy src |
| pytest | Testing | pytest |
| pytest-cov | Coverage | pytest --cov=src |
Pre-commit hooks (automated quality gates)
pip install pre-commit.pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/psf/black
rev: 24.3.0
hooks:
- id: blackpre-commit install # installs hooks into .git/hooks
pre-commit run --all-files # run manuallyEvery git commit now auto-lints and formats your code.
9. Checklist: Starting a New Python Project
Copy this every time:
# 1. Set Python version
pyenv local 3.12.3
# 2. Create project with poetry
poetry new my-project && cd my-project
# 3. Add runtime deps
poetry add requests pandas pydantic typer
# 4. Add dev deps
poetry add --group dev pytest pytest-cov ruff black mypy
# 5. Create src layout
mkdir -p src/my_project tests
touch src/my_project/__init__.py tests/conftest.py
# 6. Create .env.example
echo "DATABASE_URL=\nAPI_KEY=" > .env.example
cp .env.example .env
# 7. Install pre-commit
poetry add --group dev pre-commit
poetry run pre-commit install
# 8. Verify
poetry run python -c "import sys; print(sys.version)"
poetry run pytestSummary
| Concept | Tool | Key Command |
|--------|------|------------|
| Python version | pyenv | pyenv local 3.12.3 |
| Isolated env | venv / poetry | python -m venv .venv |
| Install packages | pip / poetry | pip install / poetry add |
| Lock dependencies | poetry.lock | poetry install |
| Project config | pyproject.toml | single file for all tools |
| Secrets | python-dotenv | load_dotenv() |
| Linting | ruff | ruff check . |
| Type checking | mypy | mypy src |
You now have the foundation that every professional Python project needs. Next up: writing clean, typed Python functions.