Cluster ERP lints Python with Ruff and type-checks it with mypy in strict mode. Both tools are configured in pyproject.toml, pinned to exact versions, and run in two places: the CI lint job and the pytest file tests/test_static_quality.py. This page lists the settings and the commands. The web JavaScript has no lint gate in CI; Not determined from code whether one is run elsewhere.
Scope and source¶
- Defined in:
pyproject.toml(sections[tool.mypy],[[tool.mypy.overrides]],[tool.ruff],[tool.ruff.lint],[tool.ruff.lint.per-file-ignores]). - Run by:
.github/workflows/ci.yml(joblint) andtests/test_static_quality.py. - Count: 9 selected Ruff rule families, 2 ignored rules, and 9 per-file ignore entries, counted from
pyproject.toml:123-149.
Tool versions¶
The dev extra pins both tools. A comment says the zero-finding state is measured against these versions and that raising a pin is a deliberate change with its own re-run (pyproject.toml:75-78).
| Tool | Version | Source |
|---|---|---|
| mypy | 1.20.2 |
pyproject.toml:80 |
| Ruff | 0.15.12 |
pyproject.toml:83 |
| pytest | >=8.0.0 |
pyproject.toml:81 |
| pytest-asyncio | >=0.24.0 |
pyproject.toml:82 |
mypy settings¶
| Name | Value | Meaning | Source |
|---|---|---|---|
strict |
true |
All strict checks are on | pyproject.toml:100 |
plugins |
pydantic.mypy |
Pydantic models are understood by the checker | pyproject.toml:101 |
python_version |
3.12 |
Target language version | pyproject.toml:102 |
override ignore_missing_imports |
true for boto3.*, botocore.*, reportlab.* |
These optional dependencies ship no type stubs; their call sites are typed as Any |
pyproject.toml:104-111 |
Ruff settings¶
| Name | Value | Meaning | Source |
|---|---|---|---|
target-version |
py312 |
Target language version | pyproject.toml:114 |
line-length |
100 |
Maximum line length | pyproject.toml:115 |
select |
E, F, W, I, N, UP, B, A, SIM |
Rule families that run | pyproject.toml:123 |
ignore B008 |
ignored | FastAPI puts Depends(), Query(), and require_permission() in argument defaults |
pyproject.toml:125-127 |
ignore N802 |
ignored | Qt override methods keep their C++ names | pyproject.toml:128-130 |
The TCH family is not selected on purpose. The comment explains that the code base resolves annotations at runtime (Pydantic v2 models, SQLAlchemy Mapped[], FastAPI route signatures), so moving imports into a TYPE_CHECKING block would break resolution (pyproject.toml:117-122).
Per-file ignores¶
| Path | Ignored rule | Reason given | Source |
|---|---|---|---|
migrations/** |
E501 |
Migrations are frozen historical records with long inline SQL | pyproject.toml:134-136 |
src/cluster_erp/ai/intent_engine.py |
N806 |
Upper-case constants at function scope | pyproject.toml:137-141 |
src/cluster_erp/modules/procurement/mrp/services.py |
N806 |
Same reason | pyproject.toml:142 |
src/cluster_erp/server/routes/chat.py |
N806 |
Same reason | pyproject.toml:143 |
src/cluster_erp/desktop/modules/procurement/mrp/stock_requirements.py |
N806 |
Same reason | pyproject.toml:144 |
src/cluster_erp/desktop/modules/procurement/mrp/time_phased.py |
N806 |
Same reason | pyproject.toml:145 |
src/cluster_erp/desktop/widgets/chat/chat_widget.py |
N806 |
Same reason | pyproject.toml:146 |
src/cluster_erp/desktop/widgets/generic/field_factory.py |
N815 |
Qt signal names keep their PySide spelling | pyproject.toml:147-148 |
src/cluster_erp/desktop/core/api_worker.py |
N813 |
Same reason | pyproject.toml:149 |
Where the tools run¶
| Place | Command | Scope | Source |
|---|---|---|---|
CI job lint |
python -m ruff check src tests |
src, tests |
.github/workflows/ci.yml:51 |
CI job lint |
python -m mypy src |
src, including the Qt client |
.github/workflows/ci.yml:52 |
| pytest | ruff check src/ tests/ scripts/ |
src, tests, scripts |
tests/test_static_quality.py:26-35 |
| pytest | mypy src/cluster_erp |
the package | tests/test_static_quality.py:21-23, tests/test_static_quality.py:38-46 |
CI installs the desktop extra with PySide6==6.8.3 before mypy, so the Qt client is type-checked against that release (.github/workflows/ci.yml:48-50).
To run the same checks on a workstation, use the CI commands:
python -m ruff check src tests
python -m mypy src
Constraints and validation¶
- The static quality test fails on any finding, not only on new ones. Its docstring records that the repository reached zero Ruff findings on 2026-08-17 and zero strict mypy findings on 2026-08-18 (
tests/test_static_quality.py:3-10). - The mypy subprocess has a time limit of 600 seconds and the Ruff subprocess 300 seconds (
tests/test_static_quality.py:33,tests/test_static_quality.py:44).
Discrepancies¶
Related pages¶
Verified against commit 92f8051 on 2026-11-13.