This project uses automated code quality tools to ensure consistent code style, detect errors early, and maintain high code quality standards.
Tools Used:
- Ruff - Fast Python linter (replaces flake8, isort, etc.)
- Black - Code formatter
- Pylint - Comprehensive linting
- Mypy - Static type checking
- Bandit - Security linting
- pip-audit - Dependency vulnerability scanning
Configuration Files:
.pylintrc- Pylint settingsmypy.ini- Mypy type checking configpyproject.toml- Black formatter config
# Activate virtual environment
source venv/bin/activate
# Install quality tools (already in requirements.txt)
pip install ruff black pylint mypy bandit[toml] pip-audit
# Set Python path
export PYTHONPATH=$(pwd)# Run all checks (same as CI)
ruff check python_app tests/python
black --check python_app tests/python
pylint python_app tests/python
mypy python_app
pip-audit
bandit -r python_appPurpose: Catch common errors quickly before running slower tools.
# Check for issues
ruff check python_app tests/python
# Auto-fix issues (where possible)
ruff check --fix python_app tests/pythonWhat it checks:
- Import sorting
- Unused imports/variables
- Syntax errors
- PEP 8 violations
- Complex code patterns
Purpose: Automatically format code to a consistent style.
# Check formatting (dry-run)
black --check python_app tests/python
# Auto-format code
black python_app tests/python
# Format specific file
black python_app/app.pyConfiguration: pyproject.toml
- Line length: 100 characters
- Target Python: 3.11+
Purpose: Deep code analysis for quality, bugs, and style issues.
# Run pylint (parallel processing)
pylint -j 2 python_app tests/python
# Check specific file
pylint python_app/app.py
# Check specific directory
pylint python_app/routes/Configuration: .pylintrc
- Max line length: 120
- Disabled warnings: Common acceptable patterns (docs, duplicate-code, etc.)
- Good names: Short variables common in tests/benchmarks (i, j, o, v, c, p1, p2, etc.)
Common Disabled Warnings (configured in .pylintrc):
C0114-C0116- Missing docstrings (acceptable in tests/utilities)R0801- Duplicate code (intentional patterns across routes)R0903- Too few public methods (common in test classes)W0511- TODO comments (acceptable)R1710- Inconsistent return statements (common in fixtures)
Purpose: Static type checking to catch type-related errors.
# Type check production code (excludes tests)
mypy python_app
# Type check with verbose output
mypy python_app --verbose
# Type check specific file
mypy python_app/app.pyConfiguration: mypy.ini
- Python version: 3.11
- Ignores missing imports (for external libraries)
- Excludes tests (to avoid duplicate module name errors)
- Special handling for Flask and requests (dynamic attributes)
Why tests are excluded:
- Test files often have duplicate names (
test_localization.pyin both unit/ and integration/) - Tests use more relaxed typing (dynamic fixtures, etc.)
- Focus type checking on production code
Purpose: Find common security issues in Python code.
# Scan production code
bandit -r python_app
# Scan with quiet output (only errors)
bandit -q -r python_app
# Scan specific file
bandit python_app/ocaml_bridge.pyWhat it checks:
- Hardcoded passwords/secrets
- SQL injection risks
- Shell injection risks
- Use of insecure functions
Purpose: Check installed packages for known vulnerabilities.
# Audit dependencies
pip-audit
# Audit with specific output format
pip-audit --format json-
Format code with Black:
black python_app tests/python
-
Fix Ruff issues:
ruff check --fix python_app tests/python
-
Check Pylint (fix critical issues):
pylint python_app tests/python
-
Type check with Mypy:
mypy python_app
-
Run tests:
pytest tests/python/ -v
Create a Makefile for convenience:
.PHONY: quality
quality:
ruff check python_app tests/python
black --check python_app tests/python
pylint python_app tests/python
mypy python_app
bandit -q -r python_app
pip-auditThen run: make quality
Located in project root. Key settings:
max-line-length = 120good-names = i,j,k,...,o,v,c,p1,p2(short names for tests/benches)- Disabled warnings for acceptable patterns
Located in project root. Key settings:
python_version = 3.11ignore_missing_imports = True(for external libs)exclude = tests/.*(avoid duplicate module names)- Special configs for
flask.*andrequests.*
Located in project root. Contains Black configuration:
line-length = 100target-version = ["py311"]- Include/exclude patterns
Issue: Pylint flags similar error handling patterns across routes.
Solution: Already disabled in .pylintrc. This duplication is intentional for clarity.
Issue: test_localization.py exists in both tests/python/unit/ and tests/python/integration/.
Solution: Tests are excluded from mypy. Only python_app/ is type-checked.
Issue: Mypy can't see Flask's dynamic attributes (Blueprint, Response, etc.).
Solution: Special [mypy-flask.*] and [mypy-requests.*] configs in mypy.ini with ignore_missing_imports = True.
Issue: Black suggests wrapping long lines.
Solution: Run black to auto-format, or manually wrap following Black's style guide.
Issue: Ruff flags imports that aren't used.
Solution: Run ruff check --fix to auto-remove, or remove manually.
All quality checks run in CI before tests:
-
Quality Job (Python 3.11 & 3.12):
- Ruff → Black → Pylint → Mypy → Security
- All steps are blocking (must pass)
-
Tests Job (only after quality passes):
- Unit tests
- Integration tests
- Functional tests
- Coverage ≥80%
See: CI Workflow Guide
- CI Workflow Guide - How CI runs quality checks
- README.md - Project overview
- Python Proxy Server - Proxy server docs
Current Status: ✅ All quality tools configured and passing in CI!
Some checks are intentionally suppressed with documented rationale. We prefer narrow, localized suppressions with clear comments rather than broad global ignores.
-
Pylint: too-many-locals (R0914) in benchmarks
- Scope:
python_app/benchmarks/benchmark_runner.py - Rationale: Micro-benchmark harness is a script-style tool. Splitting variables across helpers would add overhead and reduce readability in a timing-sensitive script. The scope is narrow and contained.
- Scope:
-
Pylint: import-outside-toplevel (C0415)
- Resolution: We moved optional platform-specific imports (select/fcntl) to guarded top-level imports. Where a dynamic import is still required, it is explicitly justified to avoid runtime costs/re-entrancy.
-
Mypy: attr-defined for Flask
- Scope: Entire project via
disable_error_code = attr-definedwith[mypy-flask.*]ignore - Rationale: Flask exposes dynamic attributes (Blueprint/Response) that mypy cannot see without additional stubs/plugins. We keep strong typing for our production code and revisit enabling strict Flask typing later.
- Scope: Entire project via
-
Pylint: duplicate-code (R0801) in route error handling
- Scope: Route modules under
python_app/routes/ - Rationale: Repeated error handling patterns are deliberate for clarity and consistent UX. The duplication is shallow and intentional.
- Scope: Route modules under
-
Bandit: nosec on subprocess calls (B404/B603/B607)
- Scope:
python_app/ocaml_bridge.py,python_app/benchmarks/benchmark_runner.py - Rationale: We never use
shell=True. Commands are fixed/validated, ports are int-derived, and OCaml binary paths are absolute. Each call includes an inline# nosecwith justification.
- Scope:
-
TODO comments (W0511)
- Scope: migration hotspots
- Rationale: Mark intentional placeholders for the migration phase; they don't affect behavior.
We will remove suppressions when they stop being necessary (e.g., once Flask typing stubs are introduced, or when benchmarks are refactored into helper modules that don’t distort timings).
You can run all quality checks in an isolated Hatch env (no manual venv):
# Install hatch once
python3 -m pip install --user hatch
# From repo root
hatch run quality # Ruff, Black, Pylint, Mypy, Bandit, pip-audit
hatch run tests # Run Python tests
hatch run ruff # Individual tools are available too
hatch run black
hatch run pylint
hatch run mypy
hatch run bandit
hatch run auditHatch uses the configuration in pyproject.toml to create an isolated environment with all required tools and dependencies.
All code under python_app/ must pass the following checks locally and in CI:
- Format:
black python_app - Lint:
ruff check python_appandpylint python_app - Types:
mypy python_app - Security:
bandit -q -r python_app -lll
Notes:
- Subprocess calls must use
shell=Falseand fixed arg lists. Add# nosec B603/B607with rationale when needed. - Internal HTTP requests to
genewebare permitted with timeouts; tag with# nosec B310and a short reason. - Avoid bare
except/pass; handle or return a safe fallback.