# Code Quality This guide covers the code quality tools and standards used in the Wizamart 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) - **mypy** - Static type checker - **pytest** - Testing framework with coverage reporting All tools are configured in `pyproject.toml` for consistency and ease of use. ## 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 ``` ## 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 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 + 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) | ## Pre-Commit Workflow Before committing code: ```bash # 1. Format and lint your code make check # 2. Run relevant tests make test-fast # 3. If all passes, commit git add . git commit -m "your message" ``` ## 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/)