Skip to content

Style Guide

This guide documents both automated formatting rules (enforced by linters) and manual style preferences for the Render Engine project.

Automated Formatting

Ruff (Python)

Render Engine uses Ruff for Python linting and formatting with the following configuration:

  • Line length: 120 characters
  • Indent width: 4 spaces
  • Target version: Python 3.10+
  • Rules enabled: E (pycodestyle errors), F (Pyflakes), I (isort), UP (pyupgrade)

Ruff automatically formats imports, fixes common errors, and enforces PEP 8 style guidelines.

Markdown

Markdown files are linted using markdownlint with configuration in .markdownlint.json.

  • Line length: 120 characters maximum

Python Style Preferences

Function and Method Signatures

When a function or method has multiple parameters, prefer placing each parameter on its own line for better readability:

# Preferred ✓
def create_entry(
    self,
    filepath: Path = None,
    editor: str = None,
    content: str = None,
    metadata: dict = None,
) -> str:
    """Create a new entry for the Collection."""
    pass

# Avoid ✗
def create_entry(self, filepath: Path = None, editor: str = None, content: str = None, metadata: dict = None) -> str:
    """Create a new entry for the Collection."""
    pass

For simple functions with one or two parameters, single-line signatures are acceptable:

# Acceptable for simple signatures
def get_title(self) -> str:
    """Return the title."""
    return self._title

def process(self, value: str) -> None:
    """Process the given value."""
    pass

Type Hint Ordering

Use modern Python union syntax (|) instead of Union from typing. Order types with specific types first, and None last:

# Preferred ✓
def get_page(
    self,
    content_path: str | Path | None = None,
) -> Page:
    pass

# Also acceptable
template: str | None
routes: list[str | Path]

# Avoid ✗ - Old Union syntax
from typing import Union, Optional

def get_page(
    self,
    content_path: Union[str, Path, None] = None,
) -> Page:
    pass

# Avoid ✗ - None in the middle
content_path: str | None | Path

Type Annotations

Always include type hints for function parameters and return values:

# Preferred ✓
def process_content(
    self,
    content: str,
    max_length: int = 100,
    strict: bool = False,
) -> str:
    """Process content with type hints for all parameters."""
    pass

def get_pages(self, count: int) -> list[Page]:
    """Return pages with typed parameters."""
    return self._pages[:count]

# Avoid ✗ - Missing type hints
def process_content(self, content, max_length=100, strict=False):
    """Process content without type hints."""
    pass

Justfile Style

Just is a command-shortcutting tool used to simplify calling commands.

Comment and Indentation

Justfile commands should have a #-led comment that explains the command above the command definition.

The command body must be indented 4 spaces:

# Preferred ✓
# Sync dependencies using uv
sync:
    uv sync --dev

# Run tests with coverage report (defaults to XML)
test-cov-report REPORT='xml':
    uv run --dev pytest --cov-report={{ REPORT }}

Parameter Naming

Parameters should be in UPPER casing. When used in the command, wrap the parameter in double braces with a space between the inner braces and the parameter name:

# Preferred ✓
# Run ruff linter without fixing
lint DIRECTORY='.':
    uvx ruff check {{ DIRECTORY }}

# Avoid ✗ - lowercase parameters or no spaces in braces
lint directory='.':
    uvx ruff check {{directory}}

Command Organization

Group related commands together and use consistent naming patterns:

# Preferred ✓
# Run ruff linter without fixing
lint DIRECTORY='.':
    uvx ruff check {{ DIRECTORY }}

# Run ruff linter with auto-fix
lint-fix DIRECTORY='.':
    uvx ruff check --fix {{ DIRECTORY }}

# Run ruff formatter as check
format DIRECTORY='.':
    uvx ruff format --check {{ DIRECTORY }}

# Run ruff formatter and fix issues
format-fix DIRECTORY='.':
    uvx ruff format {{ DIRECTORY }}