Skip to content

Repository files navigation

TextCompose

PyPI versionLicenseTests StatusRelease StatusAsk DeepWiki

TextCompose is a Python library for creating dynamic, structured text templates with an intuitive, component-based approach. Inspired by aiogram-dialog.


✨ Features

  • 🧱 Flexible text composition from components
  • 🔀 Conditional rendering support (when)
  • 🔁 Grouping and repeating blocks
  • 🎨 Formatting via f-string and Jinja2
  • 🔌 Easily extensible with new components

🚀 Installation

uv add textcompose
# or
pip install textcompose

🧩 Components Overview

General

  • Template — main class for combining and rendering components

Elements

Element — abstract base class for all element components

  • Text — static text.
  • Format — dynamic python f-string formatting
  • Jinja — Jinja2 template rendering
  • ProgressBar — show progress visually

Containers

Container — abstract base class for all container components

  • Group — group children with custom separators.
  • List — repeat templates for each item in a collection.

Logic Components

Logic — abstract base class for all container components

  • If — conditionally show different blocks (use if_, then_, else_)

Tip

All components support the when parameter for conditional display (value, expression, function, or magic_filter).

⚡️ How to Use

All usage examples can be found in the example folder.

Quick Start

See how easy it is to build structured, interactive text blocks:

frommagic_filterimportFfromtextcomposeimportTemplatefromtextcompose.containersimportGroup, Listfromtextcompose.elementsimportFormat, Jinja, Textfromtextcompose.logicsimportIftemplate=Template(
Format("Hello, {name}!"),
Format("Status: {status}"), # or `lambda ctx: f"Status: {ctx['status']}"` with functionIf(
F["notifications"] >0, # `if_`: condition to check if there are notificationsFormat("You have {notifications} new notifications."), # `then_`: content to render if condition is TrueFormat("You not have new notifications."), # `else_`: content to render if condition is False
),
Group(
Jinja("\nTotal messages {{ messages|length }}:"),
List(
Format("Time - {item[time]}:"),
Format("- {item[text]}"),
sep="\n", # `sep`: separator between list itemsinner_sep="\n", # `inner_sep`: separator between parts of a single itemgetter=lambdactx: ctx["messages"], # `getter`: function or F to extract the list of messages from context
),
sep="\n", # `sep`: separator between children of Groupwhen=F["messages"].len() >0, # `when`: show this block only if there are messages
),
Text("\nThank you for using our service!"), # or "Recent messages:" without class
)
context= {
"name": "Alexey",
"status": "Online",
"notifications": 2,
"messages": [
{"text": "Your package has been delivered.", "time": "09:15"},
{"text": "Reminder: meeting tomorrow at 10:00.", "time": "18:42"},
],
}
print(template.render(context))

Output:

Hello, Alexey!
Status: Online
You have 2 new notifications.
Total messages 2:
Time - 09:15:
- Your package has been delivered.
Time - 18:42:
- Reminder: meeting tomorrow at 10:00.
Thank you for using our service!

ProgressBar

The ProgressBar component renders a textual progress bar. It supports various styles, customizable width, templates, and dynamic values.

Usage

fromtextcompose.elementsimportProgressBarbar=ProgressBar(
current=42, # `current`: Current progress valuetotal=100, # `total`: Total value for the progress barwidth=20, # `width`: Number of characters in the bar.style="symbol_square", # `style`: Style (string — built-in style name, or `ProgressBarStyle` object).
)
print(bar.render({}))

Output:

[■■■■■■■■ ] 42%

Styles

Built-in styles are listed in the PROGRESS_BAR_STYLES dictionary (see textcompose/styles/progress_bar.py). Examples:

  • "symbol_square": [■■■■■ ]
  • "symbol_classic": [#####-----]
  • "emoj_square": 🟩🟩🟩⬜⬜⬜
  • "emoji_circle": 🟢🟢⚪⚪⚪

You can create a custom style using ProgressBarStyle:

fromtextcompose.stylesimportProgressBarStylefromtextcompose.elementsimportProgressBarcustom_style=ProgressBarStyle(
left="<", fill="*", empty="-", right=">", template="{percent} {left}{bar}{right}"
)
bar=ProgressBar(current=7, total=10, width=10, style=custom_style)
print(bar.render({}))

Output:

70% <*******--->
Template

The template parameter in the style allows you to customize the output string. Available placeholders:

  • {left} — left border
  • {bar} — the bar itself (filled + empty part)
  • {right} — right border
  • {percent} — percent complete (e.g., 42%)
  • {total} — maximum value
  • {current} — current value

🤝 Contributing

💡 Ideas? Issues? PRs are welcome!
Open an issue or pull request to help TextCompose get even better.


Ready to supercharge your text formatting?
Try TextCompose today and make your bots, reports, and notifications shine! ✨

About

Python library for building dynamic, structured text templates using a declarative, compose-based approach

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages