# Python Development Guidelines **Document Version:** v8 > **Note on Versioning:** > - This document version is independent — reused across projects > - **Project version** source of truth: `pyproject.toml` > - Version propagates: `pyproject.toml` → `constants.py` → code > - `CHANGELOG.md` uses project version from `pyproject.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: `DESIGN_DOCUMENT.md`, `AGENTS.md`, `PROJECT.md`, `CHANGELOG.md`. --- ## 1. Code Style - **PEP8** with 150-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.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 `.env` file; controlled by `ENV_DEBUG=true/false` - Load via `python-dotenv` and `os.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`, no `TestCase` classes, no `self.assert*` - Arrange-Act-Assert pattern - Test naming: `test__` --- ## 10. Tooling | Tool | Purpose | |------|---------| | **Ruff** | Formatting and linting | | **mypy** | Static type checking | | **pytest** | Testing | Run before every commit: ```bash poetry run ruff check poetry run mypy ``` --- ## 11. Poetry ```bash poetry install # Install all dependencies poetry add # Add runtime dependency poetry add --group dev # Add dev dependency poetry remove # Remove dependency poetry run # Run command in virtualenv ``` Never edit `pyproject.toml` directly to add or remove dependencies. --- ## 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 `.spec` file in the project root - All console tools must use `console=True` in the `.spec` — tools rely on `input()` and `print()` for user interaction - Compiled executables are stored in `dist/` and **committed to the repository** — the repository serves as the distribution channel for internal teams - `.gitignore` must **not** exclude `dist/` in projects that use this deployment model Build command: ```bash 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.toml` under `[project]` - Always ask before bumping the version — never increment automatically - Update `CHANGELOG.md` before bumping the version --- ## 15. Documentation and Task Management - Keep `PROJECT.md` and `CHANGELOG.md` up 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, or in `PROJECT.md` for cross-cutting concerns: ```python # TODO: one-liner description of a task to be done # FIXME: one-liner description of a known bug to be fixed ``` No other task format is used — no checkboxes, no numbered lists in documentation. If a `# TODO:` comment already exists at a specific location in code, do not repeat it in `PROJECT.md`.