| name | python-rules |
| description | Comprehensive Python coding rules covering style, patterns, testing, and security |
Python Coding Rules
Coding Style
Immutability (CRITICAL)
ALWAYS create new objects, NEVER mutate existing ones:
// Pseudocode
WRONG: modify(original, field, value) -> changes original in-place
CORRECT: update(original, field, value) -> returns new copy with change
Rationale: Immutable data prevents hidden side effects, makes debugging easier, and enables safe concurrency.
File Organization
MANY SMALL FILES > FEW LARGE FILES:
- High cohesion, low coupling
- 200-400 lines typical, 800 max
- Extract utilities from large modules
- Organize by feature/domain, not by type
Standards
- Follow PEP 8 conventions
- Use type annotations on all function signatures
Immutable Data Structures
Prefer immutable data structures:
from dataclasses import dataclass
@dataclass(frozen=True)
class User:
name: str
email: str
from typing import NamedTuple
class Point(NamedTuple):
x: float
y: float
Formatting
- black for code formatting
- isort for import sorting
- ruff for linting
Error Handling
ALWAYS handle errors comprehensively:
- Handle errors explicitly at every level
- Provide user-friendly error messages in UI-facing code
- Log detailed error context on the server side
- Never silently swallow errors
Input Validation
ALWAYS validate at system boundaries:
- Validate all user input before processing
- Use schema-based validation where available
- Fail fast with clear error messages
- Never trust external data (API responses, user input, file content)
Code Quality Checklist
Before marking work complete:
Patterns
Skeleton Projects
When implementing new functionality:
- Search for battle-tested skeleton projects
- Evaluate options for security, extensibility, relevance
- Clone best match as foundation
- Iterate within proven structure
Repository Pattern
Encapsulate data access behind a consistent interface:
- Define standard operations: findAll, findById, create, update, delete
- Concrete implementations handle storage details (database, API, file, etc.)
- Business logic depends on the abstract interface, not the storage mechanism
- Enables easy swapping of data sources and simplifies testing with mocks
API Response Format
Use a consistent envelope for all API responses:
- Include a success/status indicator
- Include the data payload (nullable on error)
- Include an error message field (nullable on success)
- Include metadata for paginated responses (total, page, limit)
Protocol (Duck Typing)
from typing import Protocol
class Repository(Protocol):
def find_by_id(self, id: str) -> dict | None: ...
def save(self, entity: dict) -> dict: ...
Dataclasses as DTOs
from dataclasses import dataclass
@dataclass
class CreateUserRequest:
name: str
email: str
age: int | None = None
Context Managers & Generators
- Use context managers (
with statement) for resource management
- Use generators for lazy evaluation and memory-efficient iteration
Testing
Minimum Test Coverage: 80%
Test Types (ALL required):
- Unit Tests - Individual functions, utilities, components
- Integration Tests - API endpoints, database operations
- E2E Tests - Critical user flows
Test-Driven Development
MANDATORY workflow:
- Write test first (RED)
- Run test - it should FAIL
- Write minimal implementation (GREEN)
- Run test - it should PASS
- Refactor (IMPROVE)
- Verify coverage (80%+)
Troubleshooting Test Failures
- Check test isolation
- Verify mocks are correct
- Fix implementation, not tests (unless tests are wrong)
Framework
Use pytest as the testing framework.
Coverage
pytest --cov=src --cov-report=term-missing
Test Organization
Use pytest.mark for test categorization:
import pytest
@pytest.mark.unit
def test_calculate_total():
...
@pytest.mark.integration
def test_database_connection():
...
Security
Mandatory Security Checks
Before ANY commit:
Secret Management
- NEVER hardcode secrets in source code
- ALWAYS use environment variables or a secret manager
- Validate that required secrets are present at startup
- Rotate any secrets that may have been exposed
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.environ["OPENAI_API_KEY"]
Security Scanning
- Use bandit for static security analysis:
bandit -r src/
Security Response Protocol
If security issue found:
- STOP immediately
- Fix CRITICAL issues before continuing
- Rotate any exposed secrets
- Review entire codebase for similar issues