Codebase Orientation
How to read a Python service repository - folder structure, ownership, conventions, and the fastest path from clone to confident navigation.
Recipe
service/
├── src/billing/ # application package
├── tests/ # mirrors src layout
├── alembic/ # DB migrations (if SQLAlchemy)
├── pyproject.toml # deps, ruff, pytest config
├── uv.lock # reproducible resolve
├── docs/ # ADRs, onboarding, runbooks
└── .github/workflows/ # CI truth sourceWhen to reach for this:
- First week on a new team or service
- Returning after long leave or reorg
- Planning a refactor across modules
- Reviewing a large PR outside your usual area
Working Example
# Orientation session script (30-60 min self-guided)
tree -L 2 src/ tests/
rg -l "router|Blueprint|urlpatterns" src/ # find HTTP entrypoints
cat pyproject.toml | rg "name|requires-python|scripts"
cat docs/adr/0001-*.md 2>/dev/null || ls docs/
gh api repos/:owner/:repo/contents/CODEOWNERS 2>/dev/null || cat CODEOWNERS
uv run pytest --collect-only -q | head # see test modulesTrace one user story:
- Find route handler (
src/billing/api/routes/orders.py). - Follow service layer (
services/order_service.py). - Find repository/ORM (
repositories/order_repo.py). - Note migration touching same table (
alembic/versions/).
What this demonstrates:
src/layout separates importable package from repo root- Search by framework keywords locates HTTP surface quickly
- ADRs and CODEOWNERS answer "who decides" and "why"
- Test collection maps modules to behavior contracts
Deep Dive
How It Works
- src layout - Package under
src/<name>/avoids accidental imports from repo root onPYTHONPATH. - pyproject.toml - Single manifest for metadata, dependencies, tool config (ruff, pytest, mypy).
- Tests mirror src -
tests/billing/api/test_orders.pymaps tosrc/billing/api/orders.py. - Ownership -
CODEOWNERSauto-requests domain experts on PRs.
What to Read First
| Artifact | Answers |
|---|---|
| README | Quickstart commands |
docs/onboarding.md | Team-specific gotchas |
| ADRs | Framework and schema decisions |
| CI workflow | Required quality gates |
CONTRIBUTING.md | PR and commit rules |
Python Notes
# Discover package version and entrypoints programmatically
import importlib.metadata as m
m.version("billing")
# console_scripts from pyproject [project.scripts]Gotchas
- Assuming Django when FastAPI - Wrong middleware and settings patterns. Fix: read ADR or
pyprojectframeworks list. - Ignoring monorepo paths - Editing wrong service copy. Fix: confirm remote URL and directory name.
- Undocumented env vars -
.env.examplestale. Fix: file doc bug on first missing key. - Skipping tests as spec - Tests show real contracts better than stale wiki. Fix: read tests for module you touch.
- Big bang directory read - Overwhelming. Fix: one vertical slice trace.
- Tribal knowledge only - Buddy unavailable later. Fix: capture answers in
docs/onboarding.md.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Architecture diagram wiki | High-level only | Diagram stale vs code |
pydeps / import graphs | Untangling cycles | First hour on repo |
| Code search IDE | Symbol jump | No local clone yet |
| Pairing tour | Complex legacy | Self-serve onboarding scale |
FAQs
Monorepo multiple packages?
Read root README for package list; cd services/billing-api per service with own uv.lock.
Where is business logic?
Teams use services/ layer or domain package - avoid fat route handlers; search class *Service.
Generated code?
Check Makefile / scripts/generate - do not hand-edit OpenAPI client output.
Feature flags?
Search settings or LaunchDarkly SDK init - flags hide incomplete paths.
Shared internal library?
Follow git submodule or monorepo libs/ - note separate version bump process.
Legacy scripts/ folder?
May be pre-src migration - README should say migration status; prefer src/ for new code.
Who owns infra/terraform?
CODEOWNERS on infra/ or platform team tag in README.
How fresh are ADRs?
Date in filename - if older than 2 years, verify still true with buddy.
Django apps layout?
Each apps/* is bounded context - start at urls.py and models.py per app.
Finding Celery tasks?
rg "@app.task" src/ or celery.py include list.
Related
- Onboarding Devs Checklist - timeline
- Conventions & Style Guide - idioms
- src Layout and Package Structure - architecture
- Architecture Decision Records - ADR process
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.