Code Style¶
Carbon Connect enforces consistent code style across Python and TypeScript codebases through automated tooling.
Python Style Guide¶
Formatters and Linters¶
| Tool | Purpose | Configuration |
|---|---|---|
| Black | Code formatting | 100-char line limit |
| Ruff | Linting (replaces flake8, isort, pyflakes) | pyproject.toml |
| isort | Import sorting | Integrated with Ruff |
| mypy | Static type checking | Strict mode |
| Bandit | Security linting | Excludes test files |
Rules¶
- Python 3.11+ with type hints mandatory on all function signatures
- 4-space indentation (no tabs)
- 100-character line limit (enforced by Black)
- Double quotes for strings (Black default)
- Trailing commas in multi-line collections
Naming Conventions¶
| Element | Convention | Example |
|---|---|---|
| Modules | snake_case | matching_engine.py |
| Classes | PascalCase | MatchingEngine |
| Functions | snake_case | calculate_rule_score() |
| Constants | UPPER_SNAKE_CASE | SEMANTIC_WEIGHT = 0.25 |
| Variables | snake_case | grant_score |
| Type aliases | PascalCase | GrantList = list[Grant] |
| Pydantic schemas | PascalCase | GrantResponse |
| SQLAlchemy models | PascalCase | Company |
| Test functions | test_<feature>_should_<behavior> | test_matching_should_disqualify_country_mismatch |
Import Order¶
Enforced by Ruff (isort-compatible):
# 1. Standard library
from datetime import UTC, datetime
from uuid import UUID
# 2. Third-party
import httpx
import structlog
from fastapi import APIRouter, Depends
from sqlalchemy.ext.asyncio import AsyncSession
# 3. Local application
from backend.app.core.config import get_settings
from backend.app.models.database.grant import Grant
from backend.app.services.matching_engine import MatchingEngine
Type Hints¶
Type hints are mandatory:
# CORRECT: Full type annotations
async def calculate_matches(
company_id: UUID,
db: AsyncSession,
min_score: float = 0.5,
limit: int = 50,
) -> list[MatchResult]:
...
# WRONG: Missing type annotations
async def calculate_matches(company_id, db, min_score=0.5, limit=50):
...
Use modern Python 3.11+ syntax:
# CORRECT: Python 3.11+ syntax
def get_name(value: str | None) -> str:
...
items: list[str] = []
mapping: dict[str, int] = {}
# WRONG: Legacy syntax
from typing import Optional, List, Dict
def get_name(value: Optional[str]) -> str:
...
Docstrings¶
Use Google-style docstrings for public APIs:
def calculate_rule_score(company: Company, grant: Grant) -> float:
"""
Calculate rule-based matching score.
Components:
- Country match (40% of rule score) - disqualifying if no match
- NACE code match (35% of rule score)
- Company size match (25% of rule score)
Args:
company: The company profile to evaluate.
grant: The grant opportunity to match against.
Returns:
Float between 0.0 and 1.0 representing the rule-based score.
Raises:
ValueError: If company or grant data is invalid.
"""
TypeScript Style Guide¶
Formatters and Linters¶
| Tool | Purpose | Configuration |
|---|---|---|
| ESLint | Linting and code quality | .eslintrc.json |
| Prettier | Code formatting | .prettierrc |
| TypeScript | Type checking | tsconfig.json (strict mode) |
Rules¶
- ES2022+ target with strict mode enabled
- 2-space indentation (Prettier default)
- Double quotes for strings
- Semicolons required
- Trailing commas in multi-line
Naming Conventions¶
| Element | Convention | Example |
|---|---|---|
| Files (components) | PascalCase.tsx | GrantCard.tsx |
| Files (utilities) | camelCase.ts | apiClient.ts |
| Components | PascalCase | DashboardStats |
| Functions/hooks | camelCase | useGrants() |
| Constants | UPPER_SNAKE_CASE | API_BASE_URL |
| Types/interfaces | PascalCase | GrantSearchParams |
| CSS classes | kebab-case via Tailwind | text-sm font-medium |
Component Style¶
Prefer functional components with hooks:
// CORRECT: Functional component with TypeScript
interface GrantCardProps {
grant: Grant;
onSave: (id: string) => void;
}
export function GrantCard({ grant, onSave }: GrantCardProps) {
const [isSaved, setIsSaved] = useState(false);
return (
<div className="rounded-lg border p-4">
<h3 className="text-lg font-semibold">{grant.title}</h3>
{/* ... */}
</div>
);
}
Running Style Checks¶
Python¶
# Format code
poetry run black backend/ tests/
poetry run ruff check --fix backend/ tests/
# Check without modifying
poetry run black --check backend/ tests/
poetry run ruff check backend/ tests/
# Type checking
poetry run mypy backend/
# Security linting
poetry run bandit -r backend/ -ll
TypeScript¶
cd frontend
# Lint
npx eslint src/ --ext .ts,.tsx
# Format
npx prettier --check "src/**/*.{ts,tsx}"
# Type check
npx tsc --noEmit
Editor Configuration¶
VS Code¶
Recommended extensions:
- Python (ms-python)
- Ruff (charliermarsh.ruff)
- Prettier (esbenp.prettier-vscode)
- ESLint (dbaeumer.vscode-eslint)
- Tailwind CSS IntelliSense (bradlc.vscode-tailwindcss)