A good python project should prove resilient under tesam collaboration and in production environments, excelling in four key areas:
- maintainability
- extensibility
- observability
- deliverability
1. Project Layout
Best Practices for Python Project Orginazation
myproject/
├── pyproject.toml
├── README.md
├── .gitignore
├── .env.example # Environment template
├── config/ # YAML/TOML/JSON default configuration
│ ├── default.toml
│ └── logging.yml
├── src/
│ ├── common/ # public package
│ | ├── init.py
│ | ├── utils.py
│ | ├── retry.py
│ | ├── validators.py
│ | ├── converters.py
│ | ├── time.py
│ ├── module1/ # API model
│ | ├── init.py
│ | ├── core.py
│ | ├── api/
│ | │ ├──init.py
│ | │ └── router.py
│ | └── utils/
│ ├── module2/ # data pipline module
│ | ├── init.py
│ | ├── pipline.py
│ └── core/ #
│ ├── init.py
| ├── types.py
│ ├── logging.py
│ ├── exceptions.py
│ ├── security.py
│ └── settings.py # universal configuration center
├── tests/ #pytest scripts
│ ├── conftest.py
│ └── test_core.py
└── scripts/ # Helper script (unpackaged)
- Use some naming convention to seperate public and private variables, like using _ as prefix of private variables.
- Design public api via well config the init.py
- Using pyproject.toml + uv etc. package management tool
- Using pydantic.BaseSettings to read and manage configurations in confg/
1
2
3
4
5
6
7
8
9
10
11
12
13
14# src/mypkg/settings.py
from pathlib import Path
from pydantic import BaseSettings
class Settings(BaseSettings):
debug: bool = False
db_url: str
log_cfg: Path = Path(__file__).with_name("logging.yml")
class Config:
env_file = Path(__file__).parent.parent.parent / ".env"
settings = Settings() - Using python_dotenv to load secret from .env (it should be git ignored.)
- Run project
linux:windows:1
2
3export PYTHONPATH=./src
uvicorn mypkg1.main:app --reload
python -m mypkg2.main1
2
3$env:PYTHONPATH = ".\src"
uvicorn mypkg1.main:app --reload
python -m mypkg2.main
2. Package and Building
A typical pyproject.toml
1 | [build-system] # PEP 518 —— tell pip how to build |
- VCS driven versioning (uv+hatching.build)
- package version read from “git tab v1.2.3 && git push –tags”
- “uv build” will write version=”1.2.3” into the package level “init.py” automatically.
- dev branch will have special suffix, implemented by hatch-vcs.
- uv build / uv publish to build whl locally or publish to pypi.org( or self host repo)
3. Type Hints and Documentation
1 | def add(x: int, y: int) -> int: |
- Using type hints for all function/class/module/variable, following PEP 484 including:
- function: parameters and return value
- class: all fields
- variables
- generic container: generic type
- 3-rd part module’s function/return
- Using mypy check type hints before integration.
mypy could work at- github action prebuilding
- local terminal
- local prebuilding
- Using standard docstring format (google-style)
- Using Sphinx/MkDocs generate documentation webpage through type hints and docstring automatically.
4. Testing
Construct test pyramid with pytest, based on unit test, supplimented with integration test and contract test.
Force test coverage > 90% with pytest-cov in CI.
Adopting hypothesis(property-based testing) to includ massive random test case input.
1. Testing Pyramid
1 | ▲ UI Test (end to end) (emulate real business process) |
2. Unit Test + Integration Test + Contract Test (Example-Based Test)
pytest
Unit Test
1
2
3
4
5def add(x: int, y: int) -> int:
return x + y
def test_add():
assert add(2, 3) == 5Integration Test
1
2
3def test_user_login_and_access_db():
token = login("alice", "pass")
assert db.get_user_by_token(token).name == "alice"Contract Test
1
2
3
4def test_api_contract(requests_mock):
requests_mock.get("https://api.example.com/user", json={"name": "Elvin"})
resp = fetch_user("https://api.example.com/user")
assert resp["name"] == "Elvin"
3. Force 90% Test Coverage
pytest-cov
1 | pytest --cov=src/ --cov-report=term |
1 | - name: Run tests with coverage |
4. Auto Test (Property-Based Testing)
hypothesis
1 | from hypothesis import given |
5. CI/CD
github action
1 | name: CI/CD Pipeline |
6. Logging, Monitoring and Tracing
- Structured Logging
logging + pythonjsonlogger
1 | import logging |
1 | { |
- Metrics Monitoring
Prometheus
1 | from prometheus_client import Counter, start_http_server |
- Distributed Tracing
opentelemetry
1 | from opentelemetry import trace |
7. Ohter Advance Practices
1. Observability
Purpose: Make runtime behavior visible and measurable for debugging, monitoring, and alerting.
Key Practices:
- Health Checks: Expose
/health,/ready, or/liveendpoints to indicate service status. - Metrics Exposure: Expose Prometheus-compatible
/metricsendpoint. - Tracing and Exception Monitoring: Integrate tools to trace requests and capture errors.
Tools:
FastAPI,Flaskwith custom middleware for health/ready endpointsPrometheus,OpenTelemetry,GrafanaSentryfor exception reporting
Example:
1 |
|
2. Security Baseline
Purpose: Prevent security vulnerabilities during development and deployment.
Key Practices:
- Dependency Vulnerability Scanning
- Static Code Analysis
- Secrets Detection
- Least Privilege Execution
Tools:
pip-audit: detect vulnerable packagesbandit: static security analysisgitleaks: find hardcoded secrets- Docker
USERdirective: run containers as non-root
CI Integration Example:
1 | - name: Security Audit |
3. Performance Strategy
Purpose: Optimize for critical paths, resource efficiency, and responsiveness.
Key Practices:
- Profiling Critical Code Paths
- Accelerate with Native Extensions
- Caching Expensive Computations
- Separate Async vs Parallel Work
Tools:
cProfile,py-spy,line_profilerCython,Rust + PyO3functools.lru_cache,Redis,memcachedasyncio,concurrent.futures,multiprocessing
Example:
1 | from functools import lru_cache |
4. Delivery and Operations
Purpose: Enable containerized deployment, reproducibility, and safe infrastructure automation.
Key Practices:
- Multi-stage Docker Build
- Non-root Containers
- Kubernetes Deployment with Helm
- Infrastructure as Code
- Safe Database Migrations
Tools:
Docker,docker-composeHelm,Terraformalembic,flyway,django-migrations
Example: Minimal Dockerfile with best practices
1 | FROM python:3.11-slim AS base |