Skip to content

Latest commit

 

History

History
284 lines (212 loc) · 6.03 KB

File metadata and controls

284 lines (212 loc) · 6.03 KB

Development Guide

English | 中文

Coding standards, workflow, and best practices for this template.

!!! note "Source of truth for Claude Code" The root CLAUDE.md is the authoritative coding standards and skill index for this project — start there. The top-level memory-bank/ drives a plan → architect → progress loop: read it before you start, and update it when you finish so the context stays current for the next session.

Code Style

Python style

  • Follow [PEP 8]; auto-format with Black (88 cols)
  • Meaningful names; add type hints
  • Google-style docstrings

Example:

def calculate_total(items: list[dict[str, float]], tax_rate: float = 0.1) -> float:
    """
    Calculate the total price including tax.

    Args:
        items: List of items with 'price'
        tax_rate: Tax rate as decimal

    Returns:
        Total price including tax

    Raises:
        ValueError: If any item is negative
    """
    if not items:
        return 0.0
    subtotal = sum(item["price"] for item in items)
    if subtotal < 0:
        raise ValueError("Total cannot be negative")
    return subtotal * (1 + tax_rate)

Naming

  • Files/dirs: lowercase, underscores (my_module.py); tests test_module.py
  • Vars/functions: snake_case
  • Classes: PascalCase
  • Constants: UPPER_SNAKE
  • Private: _internal, __for_mangling

Docstrings

Use Google style for functions and classes (see examples above and below).

Type Hints

Basic types and containers:

name: str = "John"
age: int = 30
items: list[str] = ["apple", "banana"]

Optional and unions:

from typing import Optional, Union

def find_user(user_id: str) -> Optional[dict]:
    """Find user by ID."""
    ...

def process_value(value: Union[int, str]) -> str:
    """Process integer or string value."""
    return str(value)

Generics:

from typing import TypeVar, List

T = TypeVar("T")

def reverse(items: List[T]) -> List[T]:
    """Reverse a list."""
    return items[::-1]

Git Workflow

Branch naming

feature/add-user-authentication
bugfix/fix-login-error
hotfix/critical-security-patch
refactor/improve-api-structure
docs/update-readme
test/add-integration-tests

Conventional Commits

Format:

<type>(<scope>): <subject>

Types: feat, fix, docs, style, refactor, test, chore.

Example:

git commit -m "feat: add user authentication"
git commit -m "feat(auth): add OAuth2 login support

- Implement OAuth2 flow
- Add token refresh
- Update session management

Closes #123"

Pre-commit checks

Automatically run before commit:

  1. black
  2. ruff
  3. flake8
  4. mypy
  5. interrogate
  6. isort

Skip (not recommended):

git commit --no-verify -m "emergency fix"

Testing Standards

Layout

tests/
├── __init__.py
├── conftest.py
├── test_core.py
├── test_api.py
└── integration/
    └── test_integration.py

Writing tests

import pytest
from src.core.example import Example


class TestExample:
    """Test suite for Example."""

    def test_init(self):
        example = Example(42)
        assert example.value == 42

    def test_method_with_valid_input(self):
        example = Example(10)
        assert example.calculate(2) == 20

    def test_method_with_invalid_input(self):
        example = Example(10)
        with pytest.raises(ValueError):
            example.calculate(-1)

    @pytest.mark.parametrize("input_value,expected", [(0, 0), (5, 25), (10, 100)])
    def test_calculate_multiple(self, input_value, expected):
        example = Example(input_value)
        assert example.calculate(input_value) == expected

Coverage targets

  • Minimum: 80%
  • Core logic: 100%
  • Check doc coverage with interrogate

Code Review Checklist

  • Functionality: meets requirements; no regressions; error handling present
  • Quality: follows style; lint passes; formatted; no type errors
  • Tests: unit tests added; passing; coverage ok; integration tests as needed
  • Docs: docstrings added; README/CHANGELOG updated if needed
  • Other: no secrets; no temp files; CI green

Performance

  • Prefer generators; cache results; choose right data structures; async I/O when helpful
def process_large_dataset(data):
    """Use generator for large data."""
    for item in data:
        yield process_item(item)

Profile with snakeviz:

import cProfile

def profile_code(func):
    """Profile a function."""
    profiler = cProfile.Profile()
    profiler.enable()
    result = func()
    profiler.disable()
    profiler.dump_stats("profile.stats")
    return result

Best Practices

Error handling

import logging

logger = logging.getLogger(__name__)

def process_user_data(user_id: str) -> dict:
    """Process user data with proper error handling."""
    try:
        user = get_user(user_id)
        return process(user)
    except UserNotFoundError:
        logger.error("User %s not found", user_id)
        raise
    except Exception as exc:
        logger.error("Unexpected error processing user %s: %s", user_id, exc)
        raise ProcessingError(f"Failed to process user: {exc}") from exc

Logging

import logging

logger = logging.getLogger(__name__)

def important_operation(value: str) -> None:
    """Perform important operation with logging."""
    logger.info("Starting important operation with value: %s", value)
    try:
        result = do_something(value)
        logger.info("Operation completed successfully")
    except Exception as exc:
        logger.error("Operation failed: %s", exc, exc_info=True)
        raise

Resource management

from contextlib import contextmanager

@contextmanager
def managed_resource(resource):
    """Context manager for resource management."""
    try:
        resource.open()
        yield resource
    finally:
        resource.close()

Next Steps