Skip to content

TPPT Concept

Why TPPT?

In today's world where generative AI is becoming ubiquitous, many organizations still require reports to be submitted in PowerPoint (pptx) format. (Or is it just us who are being left behind?)

TPPT is a powerful wrapper for python-pptx that brings type safety to slide masters and more.

We've designed it to be both intuitive and easy to use, making your PowerPoint generation process safer and more efficient.

Minimal Imports

Let's revisit the Quick Start example:

import tppt

(
    tppt.Presentation.builder()
    .slide(
        lambda slide: slide.BlankLayout()
        .builder()
        .text(
            "Hello, World!",
            left=(1, "in"),
            top=(1, "in"),
            width=(5, "in"),
            height=(2, "in"),
        )
    )
    .build()
    .save("simple.pptx")
)

Notice how this code only requires a single import of TPPT.

With just this minimal import, you can create complete PowerPoint presentations.

This design choice is intentional - by requiring only the TPPT import, we aim to improve the success rate of AI-generated code.

We achieve this through two key techniques:

Simplified Unit Specification with Literals

Traditionally, specifying shape dimensions in PowerPoint would look like this:

import tppt
from tppt.types import Inches

(
    tppt.Presentation.builder()
    .slide(
        lambda slide: slide.BlankLayout()
        .builder()
        .text(
            "Hello, World!",
            left=Inches(1),
            top=Inches(1),
            width=Inches(5),
            height=Inches(2),
        )
    )
    .build()
    .save("simple.pptx")
)

With TPPT, you can write the same thing more concisely: (1, "in") instead of tppt.types.Inches(1).

This Literal-based approach significantly reduces the number of imports needed.

While writing values is simplified, reading properties still gives you proper Inches objects, allowing you to perform arithmetic operations and comparisons as needed.

Smart Type Extraction

You'll notice places where we use lambda expressions like lambda slide: slide.... This is a form of lazy evaluation - we extract the type at initialization time and then build the element by applying operations to it.

The beauty of this approach is that instead of importing types and passing them as function arguments, we extract and use types directly from within the function.

This not only reduces imports but also brings another advantage: by extracting type operations into functions, you can easily create reusable components.

import tppt


def format_text(
    text_obj: tppt.pptx.Text, text: str, *, bold: bool = False, italic: bool = False
) -> tppt.pptx.Text:
    paragraph = text_obj.text_frame.add_paragraph()
    run = paragraph.add_run()
    run.text = text
    font = run.font
    if bold:
        font.bold = True
    if italic:
        font.italic = True

    return text_obj


(
    tppt.Presentation.builder()
    .slide(
        lambda slide: slide.BlankLayout()
        .builder()
        .text(
            tppt.apply(format_text, "Hello, World!", bold=True, italic=True),
            left=(1, "in"),
            top=(1, "in"),
            width=(5, "in"),
            height=(2, "in"),
        )
    )
    .build()
    .save("simple.pptx")
)

You can create and reuse your own formatting functions like format_text with ease.

Type Safety First

TPPT is designed primarily for users who create new slides based on slide masters.

If you've worked with python-pptx before, you know the struggle of adding type safety to slide masters.

TPPT solves this by allowing you to define types for slide masters using pydantic-like declarative type hints:

import datetime

import tppt


class CustomTitleSlideLayout(tppt.SlideLayout):
    title: tppt.Placeholder[str]
    subtitle: tppt.Placeholder[str | None] = None
    date: tppt.Placeholder[datetime.date | None] = None
    footer: tppt.Placeholder[str | None] = None


class CustomTitleAndContentSlideLayout(tppt.SlideLayout):
    title: tppt.Placeholder[str]
    content: tppt.Placeholder[str]
    date: tppt.Placeholder[datetime.date | None] = None
    footer: tppt.Placeholder[str | None] = None


@tppt.slide_master("custom_slide_master_base.pptx")
class CustomSlideMaster(tppt.SlideMaster):
    TitleLayout: tppt.Layout[CustomTitleSlideLayout]
    TitleAndContentLayout: tppt.Layout[CustomTitleAndContentSlideLayout]


presentation = (
    tppt.Presentation.builder(CustomSlideMaster)
    .slide(
        lambda slide: slide.TitleLayout(
            title="Custom Master Title",
        )
    )
    .slide(
        lambda slide: slide.TitleAndContentLayout(
            title="Custom Title",
            content="Custom Content",
        )
        .builder()
        .text(
            "Custom Text",
            top=(1, "in"),
            left=(2, "in"),
            width=(3, "in"),
            height=(4, "in"),
        )
    )
    .build()
    .save("custom_slide_master.pptx")
)

Don't want to write type definitions manually? We've got you covered with a handy tool:

python -m tppt.tool.ppt2template $YOUR_TEMPLATE.pptx -o $OUTPUT_FILE.py

After setting up placeholders in your slide layout constructor, you can easily add text, pictures, tables, and other elements.

And the best part? All these operations are fully type-safe!