|
42 | 42 | and UPPER_SNAKE_CASE for constants. |
43 | 43 | - Use `from __future__ import annotations` in every module. |
44 | 44 | - Type-annotate all public function signatures. |
45 | | -- Docstrings on all public classes and methods (numpy style). |
| 45 | +- Docstrings on all public classes and methods (numpy style). These must |
| 46 | + include sections Parameters, Returns and Raises, where applicable. |
46 | 47 | - Prefer flat over nested, explicit over clever. |
47 | 48 | - Write straightforward code; do not add defensive checks for unlikely |
48 | 49 | edge cases. |
|
59 | 60 | with both getter and setter) or **read-only** (property with getter |
60 | 61 | only). If internal code needs to mutate a read-only property, add a |
61 | 62 | private `_set_<name>` method instead of exposing a public setter. |
| 63 | +- Lint complexity thresholds (`max-args`, `max-branches`, |
| 64 | + `max-statements`, `max-locals`, `max-nested-blocks`, etc. in |
| 65 | + `pyproject.toml`) are intentional code-quality guardrails. They are |
| 66 | + not arbitrary numbers — the project uses ruff's defaults (with |
| 67 | + `max-args` and `max-positional-args` set to 6 instead of 5 to account |
| 68 | + for ruff counting `self`/`cls`). When code violates a threshold, it is |
| 69 | + a signal that the function or class needs refactoring — not that the |
| 70 | + threshold needs raising. Do not raise thresholds, add `# noqa` |
| 71 | + comments, or use any other mechanism to silence complexity violations. |
| 72 | + Instead, refactor the code (extract helpers, introduce parameter |
| 73 | + objects, flatten nesting, etc.). For complex refactors that touch many |
| 74 | + lines or change public API, propose a refactoring plan and wait for |
| 75 | + approval before proceeding. |
62 | 76 |
|
63 | 77 | ## Architecture |
64 | 78 |
|
|
107 | 121 | `*.py` script, then run `pixi run notebook-prepare` to regenerate the |
108 | 122 | notebook. |
109 | 123 |
|
| 124 | +## Testing |
| 125 | + |
| 126 | +- Every new module, class, or bug fix must ship with tests. See |
| 127 | + `docs/architecture/architecture.md` §10 for the full test strategy. |
| 128 | +- **Unit tests mirror the source tree:** |
| 129 | + `src/easydiffraction/<pkg>/<mod>.py` → |
| 130 | + `tests/unit/easydiffraction/<pkg>/test_<mod>.py`. Run |
| 131 | + `pixi run test-structure-check` to verify. |
| 132 | +- Category packages with only `default.py`/`factory.py` may use a single |
| 133 | + parent-level `test_<package>.py` instead of per-file tests. |
| 134 | +- Supplementary test files use the pattern `test_<mod>_coverage.py`. |
| 135 | +- Tests that expect `log.error()` to raise must `monkeypatch` Logger to |
| 136 | + RAISE mode (another test may have leaked WARN mode). |
| 137 | +- `@typechecked` setters raise `typeguard.TypeCheckError`, not |
| 138 | + `TypeError`. |
| 139 | +- No test-ordering dependence, no network, no sleeping, no real |
| 140 | + calculation engines in unit tests. |
| 141 | +- After adding or modifying tests, run `pixi run unit-tests` and confirm |
| 142 | + all tests pass. |
| 143 | + |
110 | 144 | ## Changes |
111 | 145 |
|
112 | 146 | - Before implementing any structural or design change (new categories, |
|
147 | 181 | `docs/architecture/architecture.md`. |
148 | 182 | - After changes, run linting and formatting fixes with `pixi run fix`. |
149 | 183 | Do not check what was auto-fixed, just accept the fixes and move on. |
| 184 | + Then, run linting and formatting checks with `pixi run check` and |
| 185 | + address any remaining issues until the code is clean. |
150 | 186 | - After changes, run unit tests with `pixi run unit-tests`. |
151 | 187 | - After changes, run integration tests with |
152 | 188 | `pixi run integration-tests`. |
|
0 commit comments