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_casefor 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
PascalCasefor class names - Use descriptive, noun-based names
Constants¶
- Use
UPPER_SNAKE_CASEfor constants
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¶
Linting¶
Type Checking¶
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¶
- PEP 8 - Python style guide
- Google Python Style Guide
- Type Hints (PEP 484)