Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart with Orion/orion/ORION across 184 files. This includes database identifiers, email addresses, domain references, R2 bucket names, DNS prefixes, encryption salt, Celery app name, config defaults, Docker configs, CI configs, documentation, seed data, and templates. Renames homepage-wizamart.html template to homepage-orion.html. Fixes duplicate file_pattern key in api.yaml architecture rule. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
438 lines
11 KiB
Markdown
438 lines
11 KiB
Markdown
# Code Quality
|
|
|
|
This guide covers the code quality tools and standards used in the Orion platform.
|
|
|
|
## Overview
|
|
|
|
The project uses modern Python tooling to maintain high code quality:
|
|
|
|
- **Ruff** - All-in-one linter and formatter (replaces black, isort, flake8, and more)
|
|
- **pre-commit** - Git hooks that auto-fix lint issues before each commit
|
|
- **mypy** - Static type checker
|
|
- **pytest** - Testing framework with coverage reporting
|
|
|
|
All tools are configured in `pyproject.toml` for consistency and ease of use.
|
|
|
|
## Setup (after cloning)
|
|
|
|
```bash
|
|
# Install dev dependencies (includes ruff, pre-commit, mypy)
|
|
pip install -r requirements-dev.txt
|
|
|
|
# Install pre-commit git hooks (required once per clone)
|
|
pre-commit install
|
|
```
|
|
|
|
The pre-commit hook runs automatically on every `git commit` and will:
|
|
|
|
- Validate architecture patterns
|
|
- Fix trailing whitespace and missing end-of-file newlines
|
|
- Auto-fix ruff lint issues (import sorting, unused imports, etc.)
|
|
|
|
If a hook modifies files (e.g. fixes imports), the commit is aborted. Simply `git add` the fixed files and commit again.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Format code
|
|
make format
|
|
|
|
# Lint and auto-fix issues
|
|
make lint
|
|
|
|
# Run both formatting and linting
|
|
make check
|
|
|
|
# Strict linting (no auto-fix) - for CI/CD
|
|
make lint-strict
|
|
|
|
# Run pre-commit hooks manually on all files
|
|
pre-commit run --all-files
|
|
```
|
|
|
|
## Ruff - Modern Linting and Formatting
|
|
|
|
Ruff is a blazingly fast Python linter and formatter written in Rust. It replaces multiple tools with a single, comprehensive solution.
|
|
|
|
### What Ruff Does
|
|
|
|
**Formatting** (replaces black):
|
|
- Consistent code style
|
|
- Automatic quote normalization
|
|
- Line length enforcement (88 characters)
|
|
|
|
**Linting** (replaces flake8, isort, pyupgrade, and more):
|
|
- Import sorting and organization
|
|
- Code style checks (PEP 8)
|
|
- Bug detection (flake8-bugbear)
|
|
- Modern Python syntax suggestions (pyupgrade)
|
|
- Code simplification suggestions
|
|
|
|
### Enabled Rule Sets
|
|
|
|
| Code | Description | Purpose |
|
|
|------|-------------|---------|
|
|
| E, W | pycodestyle | PEP 8 style enforcement |
|
|
| F | pyflakes | Basic error detection |
|
|
| I | isort | Import sorting |
|
|
| N | pep8-naming | Naming conventions |
|
|
| UP | pyupgrade | Modern Python syntax |
|
|
| B | flake8-bugbear | Common bug patterns |
|
|
| C4 | flake8-comprehensions | Better comprehensions |
|
|
| SIM | flake8-simplify | Code simplification |
|
|
| PIE | flake8-pie | Misc. lints |
|
|
| RET | flake8-return | Return statement improvements |
|
|
| Q | flake8-quotes | Quote consistency |
|
|
|
|
### Usage
|
|
|
|
```bash
|
|
# Format all code
|
|
make format
|
|
# or directly:
|
|
python -m ruff format .
|
|
|
|
# Lint and auto-fix issues
|
|
make lint
|
|
# or directly:
|
|
python -m ruff check . --fix
|
|
|
|
# Check without fixing (CI/CD)
|
|
make lint-strict
|
|
# or directly:
|
|
python -m ruff check .
|
|
```
|
|
|
|
### Configuration
|
|
|
|
Ruff is configured in `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.ruff]
|
|
line-length = 88
|
|
target-version = "py311"
|
|
exclude = [".git", ".venv", "venv", "__pycache__", "alembic/versions"]
|
|
|
|
[tool.ruff.lint]
|
|
select = ["E", "W", "F", "I", "N", "UP", "B", "C4", "SIM", "PIE", "RET", "Q"]
|
|
ignore = ["E501", "B008", "RET504", "SIM102"]
|
|
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
```
|
|
|
|
## mypy - Type Checking
|
|
|
|
mypy performs static type analysis to catch type-related errors before runtime.
|
|
|
|
### Usage
|
|
|
|
```bash
|
|
# Run type checking
|
|
python -m mypy .
|
|
|
|
# Or as part of lint
|
|
make lint
|
|
```
|
|
|
|
### Configuration
|
|
|
|
mypy is configured in `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.mypy]
|
|
python_version = "3.11"
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
ignore_missing_imports = true
|
|
exclude = ["^\\.venv/", "^venv/", "^alembic/versions/"]
|
|
```
|
|
|
|
## Testing with pytest
|
|
|
|
Run tests with coverage reporting:
|
|
|
|
```bash
|
|
# Run all tests
|
|
make test
|
|
|
|
# Run with coverage
|
|
make test-coverage
|
|
|
|
# Run only unit tests
|
|
make test-unit
|
|
|
|
# Run only integration tests
|
|
make test-integration
|
|
|
|
# Run fast tests (skip slow ones)
|
|
make test-fast
|
|
```
|
|
|
|
### Coverage Configuration
|
|
|
|
Coverage settings are in `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.coverage.run]
|
|
source = ["app", "models", "middleware", "tasks", "storage"]
|
|
omit = ["*/tests/*", "*/venv/*", "*/alembic/*"]
|
|
|
|
[tool.coverage.report]
|
|
precision = 2
|
|
show_missing = true
|
|
```
|
|
|
|
## Makefile Commands
|
|
|
|
### Code Quality Commands
|
|
|
|
| Command | Description | When to Use |
|
|
|---------|-------------|-------------|
|
|
| `make format` | Format code with Ruff | Before committing |
|
|
| `make lint` | Lint and auto-fix with Ruff + mypy | Before committing |
|
|
| `make lint-strict` | Lint without auto-fix + mypy | In CI/CD pipelines |
|
|
| `make arch-check` | Validate architecture patterns | Before committing |
|
|
| `make arch-check-file file="path"` | Check a single file | Quick validation |
|
|
| `make arch-check-object name="merchant"` | Check all files for an entity | Entity-wide validation |
|
|
| `make check` | Run format + lint | Quick pre-commit check |
|
|
| `make ci` | Full CI pipeline (strict lint + coverage) | CI/CD workflows |
|
|
| `make qa` | Quality assurance (format + lint + arch-check + coverage + docs) | Before releases |
|
|
|
|
### Testing Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `make test` | Run all tests |
|
|
| `make test-unit` | Run unit tests only |
|
|
| `make test-integration` | Run integration tests only |
|
|
| `make test-coverage` | Run tests with coverage report |
|
|
| `make test-fast` | Run fast tests (skip slow ones) |
|
|
|
|
## Architecture Validation
|
|
|
|
The architecture validator ensures code follows established patterns and best practices.
|
|
|
|
### Quick Start
|
|
|
|
```bash
|
|
# Check all files
|
|
make arch-check
|
|
|
|
# Check a single file
|
|
make arch-check-file file="app/api/v1/admin/stores.py"
|
|
|
|
# Check all files related to an entity
|
|
make arch-check-object name="merchant"
|
|
make arch-check-object name="store"
|
|
```
|
|
|
|
### What It Checks
|
|
|
|
| Category | Examples |
|
|
|----------|----------|
|
|
| **API Endpoints** | Pydantic models, no business logic, exception handling, auth |
|
|
| **Service Layer** | No HTTPException, proper exceptions, DB session as param |
|
|
| **Models** | SQLAlchemy/Pydantic separation |
|
|
| **JavaScript** | Centralized logger, apiClient usage |
|
|
| **Templates** | Base template inheritance |
|
|
|
|
### Output
|
|
|
|
The validator provides a summary table showing pass/fail status per file:
|
|
|
|
```
|
|
📋 FILE SUMMARY:
|
|
--------------------------------------------------------------------------------
|
|
File Status Errors Warnings
|
|
----------------------------- -------- ------- --------
|
|
app/api/v1/admin/merchants.py ❌ FAILED 6 9
|
|
app/services/merchant_service.py ✅ PASSED 0 0
|
|
--------------------------------------------------------------------------------
|
|
Total: 2 files | ✅ 1 passed | ❌ 1 failed | 6 errors | 9 warnings
|
|
```
|
|
|
|
See [Architecture Rules Reference](architecture-rules.md) for detailed rule documentation.
|
|
|
|
## Pre-Commit Workflow
|
|
|
|
Before committing code:
|
|
|
|
```bash
|
|
# 1. Format, lint, and verify critical imports
|
|
make check
|
|
|
|
# 2. Validate architecture patterns
|
|
make arch-check
|
|
|
|
# 3. Run relevant tests
|
|
make test-fast
|
|
|
|
# 4. If all passes, commit
|
|
git add .
|
|
git commit -m "your message"
|
|
```
|
|
|
|
### Critical Import Verification
|
|
|
|
The `make check` command includes a critical import verification step that ensures re-export imports haven't been removed by linters.
|
|
|
|
**What it checks:**
|
|
- `models/database/base.py` - Re-exports Base from app.core.database
|
|
- `models/__init__.py` - Exports Base for Alembic
|
|
- `models/database/__init__.py` - Exports Base from database package
|
|
|
|
**Why it matters:**
|
|
Linters like Ruff may see these imports as "unused" (F401) because they're re-exported, not directly used. Removing them breaks the application.
|
|
|
|
**Manual verification:**
|
|
```bash
|
|
make verify-imports
|
|
```
|
|
|
|
If this fails, imports have been removed and must be restored.
|
|
|
|
## CI/CD Integration
|
|
|
|
For continuous integration:
|
|
|
|
```bash
|
|
# Use strict mode (no auto-fixes)
|
|
make ci
|
|
```
|
|
|
|
This will:
|
|
1. Run strict linting (fails on any issues)
|
|
2. Run type checking with mypy
|
|
3. Run full test suite with coverage
|
|
|
|
## IDE Integration
|
|
|
|
### VSCode
|
|
|
|
Install these extensions:
|
|
- Ruff (charliermarsh.ruff)
|
|
- Python (ms-python.python)
|
|
|
|
Add to `.vscode/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"[python]": {
|
|
"editor.formatOnSave": true,
|
|
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
"editor.codeActionsOnSave": {
|
|
"source.fixAll": true,
|
|
"source.organizeImports": true
|
|
}
|
|
},
|
|
"ruff.enable": true,
|
|
"ruff.lint.enable": true
|
|
}
|
|
```
|
|
|
|
### PyCharm
|
|
|
|
1. Go to Settings → Tools → External Tools
|
|
2. Add Ruff:
|
|
- Program: `python`
|
|
- Arguments: `-m ruff check $FilePath$ --fix`
|
|
- Working directory: `$ProjectFileDir$`
|
|
|
|
## Common Issues
|
|
|
|
### Import Order
|
|
|
|
Ruff automatically organizes imports into sections:
|
|
1. Future imports
|
|
2. Standard library
|
|
3. Third-party packages
|
|
4. First-party packages (app, models, middleware, tasks, storage, scripts)
|
|
5. Local folder imports
|
|
|
|
### Line Length
|
|
|
|
Default line length is 88 characters (black's default). Long lines are automatically wrapped.
|
|
|
|
### Type Hints
|
|
|
|
While not strictly enforced, adding type hints improves code quality:
|
|
|
|
```python
|
|
# Good
|
|
def get_user(user_id: int) -> User:
|
|
return db.query(User).get(user_id)
|
|
|
|
# Better with Optional
|
|
from typing import Optional
|
|
|
|
def get_user(user_id: int) -> Optional[User]:
|
|
return db.query(User).get(user_id)
|
|
```
|
|
|
|
## Ignoring Rules
|
|
|
|
### Per-File Ignores
|
|
|
|
Configure in `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"__init__.py" = ["F401"] # Allow unused imports
|
|
"tests/**/*.py" = ["S101"] # Allow assert statements
|
|
```
|
|
|
|
### Inline Ignores
|
|
|
|
Use `# noqa` comments sparingly:
|
|
|
|
```python
|
|
# Ignore specific rule
|
|
example = lambda x: x + 1 # noqa: E731
|
|
|
|
# Ignore all rules for line
|
|
long_url = "https://..." # noqa
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Run `make check` before every commit**
|
|
2. **Let Ruff auto-fix issues** - don't fight the formatter
|
|
3. **Add type hints** for better code quality
|
|
4. **Keep test coverage above 80%**
|
|
5. **Use meaningful variable names** that pass naming checks
|
|
6. **Avoid broad exception catches** - be specific
|
|
7. **Use pathlib** instead of os.path when possible
|
|
8. **Keep functions focused** - if it's complex, break it down
|
|
|
|
## Migration from Old Tools
|
|
|
|
If you were using black, isort, or flake8 before:
|
|
|
|
| Old Tool | New Tool | Notes |
|
|
|----------|----------|-------|
|
|
| black | ruff format | 100% compatible |
|
|
| isort | ruff check --select I | Built into Ruff linting |
|
|
| flake8 | ruff check | Faster, more comprehensive |
|
|
| pyupgrade | ruff check --select UP | Built into Ruff |
|
|
|
|
All configurations have been migrated to `pyproject.toml`.
|
|
|
|
## Performance
|
|
|
|
Ruff is **10-100x faster** than the tools it replaces:
|
|
|
|
- **black**: ~2s → ruff: ~0.1s
|
|
- **isort**: ~3s → ruff: ~0.1s
|
|
- **flake8**: ~10s → ruff: ~0.2s
|
|
|
|
This means faster CI/CD pipelines and better developer experience.
|
|
|
|
## Resources
|
|
|
|
- [Ruff Documentation](https://docs.astral.sh/ruff/)
|
|
- [Ruff Rules](https://docs.astral.sh/ruff/rules/)
|
|
- [mypy Documentation](https://mypy.readthedocs.io/)
|
|
- [pytest Documentation](https://docs.pytest.org/)
|