Python Engineering Guide
Modern Python development is about more than just writing code; it's about building reproducible, maintainable, and high-performance systems. This guide focuses on the modern Astral (uv/Ruff) stack.
The Modern Stack (2024+)
We recommend a unified toolchain to minimize "tool sprawl" and maximize performance.
| Category | Tool | Why? |
|---|---|---|
| Package Manager | uv | 10-100x faster than pip/poetry; unified venv/python manager. |
| Linter/Formatter | Ruff | Replaces Flake8, Black, isort, and Bandit with a single Rust-based tool. |
| Type Checker | MyPy | Industry standard for static type analysis. |
| Testing | pytest | Feature-rich, modular testing framework. |
| Config | pyproject.toml | The single source of truth for project metadata and tool config. |
Project Structure
A standardized layout ensures team members and tools can navigate the codebase easily.
project-name/
├── pyproject.toml # Configuration (The heart of the project)
├── uv.lock # Deterministic lockfile (Commit this!)
├── .python-version # Pinned Python version (e.g., 3.12)
├── src/ # Source code (using src-layout)
│ └── my_package/
│ ├── __init__.py
│ └── main.py
├── tests/ # Test suite
│ ├── conftest.py
│ └── test_main.py
└── .github/ # CI/CD workflows
└── workflows/ci.yml
Dependency Management with uv
uv is a drop-in replacement for pip, pip-tools, and poetry.
Core Workflow
# Initialize a new project
uv init --lib
# Add dependencies
uv add requests fastapi
uv add --dev pytest ruff mypy
# Sync environment with lockfile
uv sync
Always commit uv.lock. It ensures every developer and CI runner uses the exact same versions of every dependency, including transitive ones.
Code Quality (Ruff & MyPy)
Ruff Configuration
Ruff replaces Flake8, isort, Black, and Bandit with a single, extremely fast tool. Consolidate all rules in pyproject.toml:
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = [
"E", "F", "W", # Default flake8
"I", # isort (import sorting)
"UP", # pyupgrade
"S", # bandit (security)
"B", # bugbear
]
# Import-specific configuration
[tool.ruff.lint.isort]
known-first-party = ["my_package"]
force-sort-within-sections = true # Sort within import groups
combine-as-imports = true # Merge: from x import a; from x import b -> from x import a, b
lines-after-imports = 2 # PEP 8 standard
The "I" rule enables automatic import sorting (replaces isort):
- Groups: stdlib → third-party → local
- Sorts alphabetically within groups
- Detects unused imports (F401)
- Flags
from module import *(F403)
Type Checking
Use MyPy to catch logic errors before they reach production:
uv run mypy src/
Continuous Integration (GitHub Actions)
Automate your quality gates. A typical ci.yml using setup-uv:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- name: Install & Check
run: |
uv sync
uv run ruff check .
uv run mypy src/
uv run pytest
Code Organization
Python Import System
Understanding Python's import mechanism is crucial for building scalable applications. Key concepts include:
- Absolute vs Relative Imports: Use absolute imports for clarity, relative imports within packages
__init__.py: Control package-level API and initialization- Avoiding Circular Imports: Use
TYPE_CHECKINGor refactor dependencies - Import Performance: Consider lazy imports for heavy dependencies
# ✅ Recommended: Absolute imports
from my_package.utils import load_config
from my_package.core import Engine
# ✅ Acceptable: Explicit relative imports
from .utils import load_config
from ..core import Engine
Configure Ruff to enforce PEP 8 import ordering and detect circular dependencies automatically.
Engineering Resources
- 📄 Python Import System — Comprehensive guide to imports, modules, and best practices.
- 📄 Complete Guide to
uv— Deep dive into package management. - 📄
pyproject.tomlGuide — Comprehensive config reference. - 📄 Tooling Introduction — Comparing the ecosystem.
- 📄 Infrastructure Setup — Deploying Python apps.