Skip to content

Code Standards

Garot Conklin edited this page Dec 8, 2024 · 1 revision

Code Standards

Overview

This document outlines the coding standards and best practices for the fleXRPL Discord Bot project. Following these standards ensures consistency, maintainability, and quality across the codebase.

Python Style Guide

Code Formatting

Black Configuration

# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py311']
include = '\.pyx?$'
extend-exclude = '''
# A regex preceded with ^/ will apply only to files and directories
# in the root of the project.
^/tests/
'''

Isort Configuration

[tool.isort]
profile = "black"
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
line_length = 88

Naming Conventions

Variables and Functions

# Good
user_message = "Hello"
def process_webhook_event(payload: dict) -> None:
    pass

# Bad
userMessage = "Hello"  # Not snake_case
def ProcessWebhookEvent(payload):  # Not snake_case
    pass

Classes

# Good
class WebhookHandler:
    pass

class GitHubEventProcessor:
    pass

# Bad
class webhookHandler:  # Not PascalCase
    pass

Constants

# Good
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
GITHUB_API_URL = "https://api.github.com"

# Bad
maxRetries = 3  # Not uppercase
default_timeout = 30  # Not uppercase

Code Organization

File Structure

src/
├── bot/
│   ├── __init__.py
│   ├── client.py
│   └── cogs/
│       ├── __init__.py
│       └── github.py
├── handlers/
│   ├── __init__.py
│   └── webhook.py
└── utils/
    ├── __init__.py
    └── formatting.py

Module Organization

"""
Module docstring explaining purpose and usage.
"""

# Standard library imports
import asyncio
import json

# Third-party imports
import discord
from fastapi import FastAPI

# Local imports
from bot.client import DiscordBot
from utils.formatting import format_message

# Constants
MAX_RETRIES = 3

# Classes
class WebhookHandler:
    """Class docstring."""
    pass

# Functions
def process_event(payload: dict) -> None:
    """Function docstring."""
    pass

# Main execution (if applicable)
if __name__ == "__main__":
    pass

Documentation Standards

Docstrings

def process_webhook(
    payload: dict,
    retries: int = 3,
    timeout: float = 30.0
) -> bool:
    """
    Process incoming webhook payload with retry mechanism.

    Args:
        payload (dict): The webhook payload to process
        retries (int, optional): Number of retry attempts. Defaults to 3.
        timeout (float, optional): Timeout in seconds. Defaults to 30.0.

    Returns:
        bool: True if processing successful, False otherwise.

    Raises:
        ValueError: If payload is malformed
        TimeoutError: If processing exceeds timeout
    """
    pass

Type Hints

from typing import Optional, List, Dict, Union

def get_repository_events(
    repo_name: str,
    event_types: List[str],
    since: Optional[str] = None
) -> Dict[str, Union[str, List[dict]]]:
    pass

Error Handling

Exception Patterns

class WebhookError(Exception):
    """Base exception for webhook-related errors."""
    pass

class ValidationError(WebhookError):
    """Raised when webhook payload validation fails."""
    pass

def process_webhook(payload: dict) -> None:
    try:
        validate_payload(payload)
    except ValidationError as e:
        logger.error(f"Validation failed: {e}")
        raise
    except Exception as e:
        logger.exception("Unexpected error")
        raise WebhookError(f"Processing failed: {e}") from e

Testing Standards

Test Organization

# test_webhook.py
import pytest
from handlers.webhook import WebhookHandler

class TestWebhookHandler:
    @pytest.fixture
    def handler(self):
        return WebhookHandler()

    def test_valid_payload(self, handler):
        """Test processing of valid webhook payload."""
        payload = {"action": "opened"}
        assert handler.process(payload) is True

    @pytest.mark.asyncio
    async def test_async_processing(self, handler):
        """Test async webhook processing."""
        pass

Logging Standards

Logger Configuration

import logging

logger = logging.getLogger(__name__)

def setup_logging():
    """Configure logging for the application."""
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )

Log Usage

# Good
logger.info("Processing webhook payload")
logger.error("Failed to process webhook: %s", str(error))

# Bad
print("Processing webhook payload")  # Don't use print
logger.error(f"Failed to process webhook: {error}")  # Don't use f-strings in logs

Security Standards

Secret Handling

# Good
from os import environ
token = environ.get("DISCORD_BOT_TOKEN")

# Bad
token = "1234567890"  # Never hardcode secrets

Input Validation

from typing import TypedDict

class WebhookPayload(TypedDict):
    action: str
    repository: dict

def process_webhook(payload: WebhookPayload) -> None:
    """Process webhook with validated payload."""
    if not isinstance(payload.get("action"), str):
        raise ValidationError("Invalid action type")

Performance Guidelines

Async/Await Usage

# Good
async def process_events(events: List[dict]) -> None:
    await asyncio.gather(*[process_event(event) for event in events])

# Bad
def process_events(events: List[dict]) -> None:
    for event in events:  # Should be async
        process_event(event)

Resource Management

# Good
async with aiohttp.ClientSession() as session:
    async with session.get(url) as response:
        data = await response.json()

# Bad
session = aiohttp.ClientSession()
response = await session.get(url)  # Session not properly managed

Git Commit Standards

Commit Messages

# Good
git commit -m "feat: add webhook validation middleware"
git commit -m "fix: handle missing payload attributes"
git commit -m "docs: update webhook configuration guide"

# Bad
git commit -m "updates"  # Not descriptive
git commit -m "fixed bug"  # Not specific

This documentation is maintained by the fleXRP team.