Skip to content

Code Style Guide

Coding standards and best practices for SlideGen development.

Overview

SlideGen follows Python best practices and PEP 8 style guidelines, with some project-specific conventions.

General Principles

  • Readability: Code should be easy to read and understand
  • Consistency: Follow existing code patterns
  • Simplicity: Prefer simple, clear solutions
  • Documentation: Document public APIs and complex logic

Code Formatting

Line Length

  • Maximum line length: 100 characters
  • Break long lines appropriately

Indentation

  • Use 4 spaces (no tabs)
  • Align continuation lines properly

Imports

Order imports as follows:

# Standard library
import json
from pathlib import Path
from typing import Dict, Optional

# Third-party
import click
import yaml
from pptx import Presentation

# Local
from slidegen.core.registry import LayoutRegistry
from slidegen.theming import Theme

Blank Lines

  • Two blank lines between top-level definitions
  • One blank line between methods
  • No blank lines at end of file

Naming Conventions

Variables and Functions

  • Use snake_case for variables and functions
  • Use descriptive names
# Good
def render_slide(slide, data):
    title_text = data.get("title", "")

# Avoid
def rs(s, d):
    t = d.get("title", "")

Classes

  • Use PascalCase for class names
  • Use descriptive, noun-based names
# Good
class SlideGenerator:
    pass

class LayoutRenderer:
    pass

# Avoid
class Gen:
    pass

Constants

  • Use UPPER_SNAKE_CASE for constants
TITLE_TOP = Inches(0.5)
MAX_BULLETS = 10

Type Hints

Always use type hints for function signatures:

def from_schema(self, schema_path: str) -> None:
    """Load schema from file."""
    pass

def get_renderer(self, layout_type: str) -> Optional[LayoutRenderer]:
    """Get layout renderer."""
    pass

Common Types

from typing import Dict, List, Optional, Any, Union

# Dictionaries
data: Dict[str, Any]

# Lists
items: List[str]

# Optional values
theme: Optional[Theme]

# Union types
value: Union[str, int]

Docstrings

Use Google-style docstrings for all public functions and classes:

def render_slide(
    self,
    slide: Slide,
    data: Dict[str, Any],
    theme: Theme
) -> None:
    """
    Render content to a slide.

    Args:
        slide: PowerPoint slide object
        data: Slide data dictionary
        theme: Theme object for styling

    Raises:
        ValueError: If required data is missing
    """
    pass

Class Docstrings

class SlideGenerator:
    """
    Main class for generating PowerPoint presentations.

    Usage:
        gen = SlideGenerator()
        gen.from_schema("deck.yaml")
        gen.build("output.pptx")
    """
    pass

Error Handling

Use Specific Exceptions

# Good
if not path.exists():
    raise FileNotFoundError(f"Schema file not found: {schema_path}")

# Avoid
if not path.exists():
    raise Exception("File not found")

Error Messages

  • Be descriptive and actionable
  • Include relevant context
# Good
raise ValueError(
    f"Invalid layout type '{layout_type}'. "
    f"Use one of: {', '.join(valid_layouts)}"
)

# Avoid
raise ValueError("Invalid layout")

Testing

Test Naming

  • Test functions: test_<feature>_<scenario>
  • Test classes: Test<Feature>
def test_from_schema_loads_yaml_file():
    """Test that from_schema loads YAML files correctly."""
    pass

def test_from_schema_raises_on_missing_file():
    """Test that from_schema raises FileNotFoundError for missing files."""
    pass

Test Structure

Follow Arrange-Act-Assert pattern:

def test_build_creates_pptx_file(tmp_path):
    """Test that build creates a PowerPoint file."""
    # Arrange
    gen = SlideGenerator()
    gen.from_schema("deck.yaml")
    output_path = tmp_path / "output.pptx"

    # Act
    gen.build(str(output_path))

    # Assert
    assert output_path.exists()
    assert output_path.suffix == ".pptx"

Comments

When to Comment

  • Explain "why", not "what"
  • Document complex algorithms
  • Note non-obvious behavior
# Good: Explains why
# Use blank layout to avoid default placeholder shapes
slide = presentation.slides.add_slide(
    presentation.slide_layouts[6]
)

# Avoid: States the obvious
# Create a new slide
slide = presentation.slides.add_slide(...)

Inline Comments

# Good
# Calculate font size based on content length to prevent overflow
font_size = max(18, min(72, 100 - len(text) // 10))

# Avoid
# Set font size
font_size = 24

File Organization

Module Structure

"""Module docstring describing the module's purpose."""

# Imports (standard, third-party, local)
import ...

# Constants
DEFAULT_FONT_SIZE = 24

# Classes
class MyClass:
    pass

# Functions
def helper_function():
    pass

Best Practices

Keep Functions Focused

# Good: Single responsibility
def validate_schema(schema: Dict[str, Any]) -> ValidationResult:
    """Validate schema structure."""
    pass

def render_slide(slide: Slide, data: Dict[str, Any]) -> None:
    """Render slide content."""
    pass

# Avoid: Multiple responsibilities
def process_and_render(schema, slide):
    """Validate, process, and render."""
    pass

Avoid Deep Nesting

# Good
if not condition:
    return

# Process...

# Avoid
if condition:
    if another_condition:
        if yet_another:
            # Deep nesting
            pass

Use Early Returns

# Good
def process_data(data: Dict[str, Any]) -> Optional[Result]:
    if not data:
        return None

    if "error" in data:
        return None

    # Process...
    return result

Tools

Automatic Formatting

# Format code
ruff format slidegen/

# Check formatting
ruff format --check slidegen/

Linting

# Check for issues
ruff check slidegen/

# Auto-fix issues
ruff check --fix slidegen/

Type Checking

# Check types
mypy slidegen/

# Check specific file
mypy slidegen/core/generator.py

Examples

Good Example

"""Layout renderer for title slides."""

from typing import Dict, Any
from pptx.slide import Slide
from pptx.presentation import Presentation

from slidegen.layouts.base import LayoutRenderer
from slidegen.theming import Theme


class TitleLayoutRenderer(LayoutRenderer):
    """Renders title slides with title and optional subtitle."""

    def render(
        self,
        slide: Slide,
        data: Dict[str, Any],
        presentation: Presentation
    ) -> None:
        """
        Render title slide.

        Args:
            slide: PowerPoint slide object
            data: Slide data with 'title' and optional 'subtitle'
            presentation: Presentation object for context
        """
        title_text = data.get("title", "")
        subtitle_text = data.get("subtitle")

        if not title_text:
            raise ValueError("Title layout requires 'title' field")

        # Render title
        # ... implementation ...

        # Render subtitle if provided
        if subtitle_text:
            # ... implementation ...

Resources