7.5 KiB
Python Development Guidelines
Document Version: v10
Note on Versioning:
- This document version is independent — reused across projects
- Project version source of truth:
pyproject.toml- Version propagates:
pyproject.toml→constants.py→ codeCHANGELOG.mduses project version frompyproject.toml
Related Documents
- README.md — Project overview, tool descriptions, build instructions
- AGENTS.md — Rules for AI assistants
- PROJECT.md — Project goals and current state
- CHANGELOG.md — Version history
Documentation Organization
All detailed documentation of features and systems belongs in the docs/ folder, not in the project root.
The root directory contains only the core documents: README.md, CLAUDE.md, AGENTS.md, DESIGN_DOCUMENT.md, PROJECT.md, CHANGELOG.md.
1. Code Style
- PEP8 with 120-character lines (Ruff)
- 4 spaces indentation
- snake_case functions/variables, PascalCase classes, SCREAMING_SNAKE_CASE constants
- Type hints required on all functions
- Import order: stdlib → third-party → local
2. SOLID Principles
- SRP — One class = one responsibility
- OCP — Open for extension, closed for modification
- LSP — Subclasses substitutable for parents
- ISP — Small interfaces over large ones
- DIP — Depend on abstractions
3. Dependency Injection
Pass dependencies via constructor. Never instantiate dependencies inside a class.
4. Protocols Over Inheritance
Prefer typing.Protocol and composition over class inheritance.
5. Data Classes
Use @dataclass for internal data structures, pydantic.BaseModel for data that requires validation.
6. Logging and Console Output
Logging — loguru
Use loguru for all internal logging. Never log secrets, passwords, tokens, or API keys.
Log sinks
| Sink | Level | Format |
|---|---|---|
File logs/{AppName}_{time}.log |
DEBUG |
full (timestamp + level + message) |
| stdout | INFO |
full |
File sink retains max 10 log files (retention=10). No rotation by size — each run creates a new file via {time} in the filename.
The DEBUG sink is only active when constants.DEFAULT_DEBUG is True (controlled by ENV_DEBUG=true in .env).
Additional sinks (e.g. GUI log panels) may be added per project as needed.
Log levels
| Level | When to use |
|---|---|
DEBUG |
Per-item detail: individual file reads/writes, cache hits, per-row operations |
INFO |
User-visible milestones: file loaded, process started/finished, file saved |
WARNING |
Recoverable issues: fallback used, unexpected but non-fatal state |
ERROR |
Failures the user must know about: missing file, failed save, missing config — operation cannot continue |
Console output — print()
print() is allowed for direct user-facing console communication: input prompts, progress lines, and result summaries. This applies to console tools that interact with the user through stdin/stdout.
print() is not a substitute for loguru. It must not be used for debugging or internal event tracking.
7. Environment and Secrets
- Secrets in
.envfile; controlled byENV_DEBUG=true/false - Load via
python-dotenvandos.getenv() - Never commit
.env
8. Error Handling
Define specific exception types. Use a fail-fast approach — surface errors early rather than silently continuing.
9. Testing
- pytest only — no
unittest, noTestCaseclasses, noself.assert* - Arrange-Act-Assert pattern
- Test naming:
test_<action>_<context>
10. Tooling
| Tool | Purpose |
|---|---|
| Ruff | Formatting and linting |
| mypy | Static type checking |
| pytest | Testing |
Run before every commit:
poetry run ruff check
poetry run mypy
poetry run pytest
11. Poetry
poetry install # Install all dependencies
poetry add <pkg> # Add runtime dependency
poetry add --group dev <pkg> # Add dev dependency
poetry remove <pkg> # Remove dependency
poetry run <cmd> # Run command in virtualenv
Never edit pyproject.toml directly to add or remove dependencies.
poetry.lock
poetry.lock is committed for applications — it pins the exact dependency graph and keeps builds reproducible.
12. Project Structure
project/
├── entry_point.py # Entry point(s) — named by purpose or tool name
├── src/ # All application modules
├── tests/ # Tests
├── docs/ # Detailed documentation
├── .venv/ # Virtual environment (managed by Poetry)
└── pyproject.toml # Project config and dependencies
A project may have multiple entry points (e.g. cli.py, gui.py, or per-tool scripts).
13. Distribution and Deployment
When a project is distributed as a standalone executable (no Python required on target machine):
- Use PyInstaller to compile each entry point into a single
.exe - Each tool has its own
.specfile in the project root - Console tools use
console=Truein the.spec— they rely oninput()andprint()for user interaction. GUI applications turn the console off withENV_BUILD_CONSOLE=false; that flag is independent ofENV_DEBUG - Compiled executables are stored in
dist/and committed to the repository — the repository serves as the distribution channel for internal teams .gitignoremust not excludedist/in projects that use this deployment model
prebuild.py
prebuild.py runs before PyInstaller. It verifies that the active interpreter is the project .venv, prints the resolved version, and rewrites the console= line in the .spec to match .env.
| Variable | Default | Effect |
|---|---|---|
ENV_BUILD_CONSOLE |
true |
Value written into console= in the .spec |
ENV_BUILD_SPEC |
<project folder>.spec |
Which .spec file to update |
prebuild.py touches one .spec per run — with several entry points, set ENV_BUILD_SPEC for each build.
Build commands:
poetry run python prebuild.py
poetry run pyinstaller ToolName.spec
This section applies only to projects that produce standalone executables. Skip for libraries or web services.
14. Versioning
- Follow semantic versioning:
MAJOR.MINOR.PATCH - Version is defined in
pyproject.tomlunder[project] - Always ask before bumping the version — never increment automatically
- Update
CHANGELOG.mdbefore bumping the version
15. Documentation and Task Management
- Keep
PROJECT.mdandCHANGELOG.mdup to date when making changes - Document architectural changes in this file or in
docs/
Task notation
Tasks are written as single-line comments directly in code, using the Todo Tree tags defined in AGENTS.md (TODO, FIXME, BUG, HACK, NOTE). PROJECT.md carries only cross-cutting tasks that have no single place in the code.
# TODO: extract this into a separate loader
# FIXME: crashes on an empty file
# BUG: rounding is off by one cent on negative amounts
# HACK: temporary workaround until the API adds paging
# NOTE: order matters here, the parser is stateful
No other task format is used — no checkboxes, no numbered lists in documentation.
If a tag already exists at a specific location in code, do not repeat it in PROJECT.md.