textcompose


Nametextcompose JSON
Version 1.2.0 PyPI version JSON
download
home_pageNone
SummaryA Python library for building dynamic, structured text templates using a declarative, compose-based approach
upload_time2025-07-08 15:31:10
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseApache-2.0
keywords compose logic templates structured text template templating text generation
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # TextCompose

[![PyPI version](https://img.shields.io/pypi/v/textcompose?color=blue)](https://pypi.org/project/textcompose)
[![License](https://img.shields.io/github/license/m-xim/textcompose.svg)](/LICENSE)
[![Tests Status](https://github.com/m-xim/textcompose/actions/workflows/tests.yml/badge.svg)](https://github.com/m-xim/textcompose/actions)
[![Release Status](https://github.com/m-xim/textcompose/actions/workflows/release.yml/badge.svg)](https://github.com/m-xim/textcompose/actions)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/m-xim/textcompose)

**TextCompose** is a Python library for creating dynamic, structured text templates with an intuitive, component-based approach. Inspired by [aiogram-dialog](https://github.com/Tishka17/aiogram_dialog).

<br>

## ✨ 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

```bash
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`](#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`](./example) folder.

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

```python
from magic_filter import F

from textcompose import Template
from textcompose.containers import Group, List
from textcompose.elements import Format, Jinja, Text
from textcompose.logics import If

template = Template(
    Format("Hello, {name}!"),
    Format("Status: {status}"),  # or `lambda ctx: f"Status: {ctx['status']}"` with function
    If(
        F["notifications"] > 0,  # `if_`: condition to check if there are notifications
        Format("You have {notifications} new notifications."),  # `then_`: content to render if condition is True
        Format("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 items
            inner_sep="\n",  # `inner_sep`: separator between parts of a single item
            getter=lambda ctx: ctx["messages"],  # `getter`: function or F to extract the list of messages from context
        ),
        sep="\n",  # `sep`: separator between children of Group
        when=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

```python
from textcompose.elements import ProgressBar

bar = ProgressBar(
    current=42,  # `current`: Current progress value
    total=100,  # `total`: Total value for the progress bar
    width=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`](./textcompose/styles/progress_bar.py)). Examples:

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

You can create a custom style using `ProgressBarStyle`:

```python
from textcompose.styles import ProgressBarStyle
from textcompose.elements import ProgressBar


custom_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!<br>
Open an issue or pull request to help TextCompose get even better.

<br>

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

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "textcompose",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "compose, logic templates, structured text, template, templating, text generation",
    "author": null,
    "author_email": "m-xim <i@m-xim.ru>",
    "download_url": "https://files.pythonhosted.org/packages/00/ad/1c57d6f901b9ab1934db3eab591bf93ec7a54a7252ff41ef4a52c9b6b165/textcompose-1.2.0.tar.gz",
    "platform": null,
    "description": "# TextCompose\n\n[![PyPI version](https://img.shields.io/pypi/v/textcompose?color=blue)](https://pypi.org/project/textcompose)\n[![License](https://img.shields.io/github/license/m-xim/textcompose.svg)](/LICENSE)\n[![Tests Status](https://github.com/m-xim/textcompose/actions/workflows/tests.yml/badge.svg)](https://github.com/m-xim/textcompose/actions)\n[![Release Status](https://github.com/m-xim/textcompose/actions/workflows/release.yml/badge.svg)](https://github.com/m-xim/textcompose/actions)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/m-xim/textcompose)\n\n**TextCompose** is a Python library for creating dynamic, structured text templates with an intuitive, component-based approach. Inspired by [aiogram-dialog](https://github.com/Tishka17/aiogram_dialog).\n\n<br>\n\n## \u2728 Features\n\n- \ud83e\uddf1 Flexible text composition from components\n- \ud83d\udd00 Conditional rendering support (`when`)\n- \ud83d\udd01 Grouping and repeating blocks\n- \ud83c\udfa8 Formatting via f-string and Jinja2\n- \ud83d\udd0c Easily extensible with new components\n\n## \ud83d\ude80 Installation\n\n```bash\nuv add textcompose\n# or\npip install textcompose\n```\n\n## \ud83e\udde9 Components Overview\n\n### General\n\n- `Template` \u2014 main class for combining and rendering components\n\n\n### Elements\n`Element` \u2014 abstract base class for all element components\n\n- `Text` \u2014 static text.\n- `Format` \u2014 dynamic python f-string formatting\n- `Jinja` \u2014 Jinja2 template rendering\n- [`ProgressBar`](#progressbar) \u2014 show progress visually\n\n### Containers\n`Container` \u2014 abstract base class for all container components\n\n- `Group` \u2014 group children with custom separators.\n- `List` \u2014 repeat templates for each item in a collection.\n\n### Logic Components\n`Logic` \u2014 abstract base class for all container components\n\n- `If` \u2014 conditionally show different blocks (use `if_`, `then_`, `else_`)\n\n> [!TIP]\n> All components support the `when` parameter for conditional display (value, expression, function, or magic_filter).\n\n## \u26a1\ufe0f How to Use\n\nAll usage examples can be found in the [`example`](./example) folder.\n\n### Quick Start\nSee how easy it is to build structured, interactive text blocks:\n\n```python\nfrom magic_filter import F\n\nfrom textcompose import Template\nfrom textcompose.containers import Group, List\nfrom textcompose.elements import Format, Jinja, Text\nfrom textcompose.logics import If\n\ntemplate = Template(\n    Format(\"Hello, {name}!\"),\n    Format(\"Status: {status}\"),  # or `lambda ctx: f\"Status: {ctx['status']}\"` with function\n    If(\n        F[\"notifications\"] > 0,  # `if_`: condition to check if there are notifications\n        Format(\"You have {notifications} new notifications.\"),  # `then_`: content to render if condition is True\n        Format(\"You not have new notifications.\"),  # `else_`: content to render if condition is False\n    ),\n    Group(\n        Jinja(\"\\nTotal messages {{ messages|length }}:\"),\n        List(\n            Format(\"Time - {item[time]}:\"),\n            Format(\"-  {item[text]}\"),\n            sep=\"\\n\",  # `sep`: separator between list items\n            inner_sep=\"\\n\",  # `inner_sep`: separator between parts of a single item\n            getter=lambda ctx: ctx[\"messages\"],  # `getter`: function or F to extract the list of messages from context\n        ),\n        sep=\"\\n\",  # `sep`: separator between children of Group\n        when=F[\"messages\"].len() > 0,  # `when`: show this block only if there are messages\n    ),\n    Text(\"\\nThank you for using our service!\"),  # or \"Recent messages:\" without class\n)\n\ncontext = {\n    \"name\": \"Alexey\",\n    \"status\": \"Online\",\n    \"notifications\": 2,\n    \"messages\": [\n        {\"text\": \"Your package has been delivered.\", \"time\": \"09:15\"},\n        {\"text\": \"Reminder: meeting tomorrow at 10:00.\", \"time\": \"18:42\"},\n    ],\n}\n\nprint(template.render(context))\n```\n\n**Output:**\n```\nHello, Alexey!\nStatus: Online\nYou have 2 new notifications.\n\nTotal messages 2:\nTime - 09:15:\n-  Your package has been delivered.\nTime - 18:42:\n-  Reminder: meeting tomorrow at 10:00.\n\nThank you for using our service!\n```\n\n### ProgressBar\n\nThe `ProgressBar` component renders a textual progress bar. It supports various styles, customizable width, templates, and dynamic values.\n\n#### Usage\n\n```python\nfrom textcompose.elements import ProgressBar\n\nbar = ProgressBar(\n    current=42,  # `current`: Current progress value\n    total=100,  # `total`: Total value for the progress bar\n    width=20,  # `width`: Number of characters in the bar.\n    style=\"symbol_square\",  # `style`: Style (string \u2014 built-in style name, or `ProgressBarStyle` object).\n)\nprint(bar.render({}))\n```\n\n**Output:**\n```\n[\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0\u25a0        ] 42%\n```\n\n#### Styles\n\nBuilt-in styles are listed in the `PROGRESS_BAR_STYLES` dictionary (see [`textcompose/styles/progress_bar.py`](./textcompose/styles/progress_bar.py)). Examples:\n\n- `\"symbol_square\"`: `[\u25a0\u25a0\u25a0\u25a0\u25a0     ]`\n- `\"symbol_classic\"`: `[#####-----]`\n- `\"emoj_square\"`: `\ud83d\udfe9\ud83d\udfe9\ud83d\udfe9\u2b1c\u2b1c\u2b1c`\n- `\"emoji_circle\"`: `\ud83d\udfe2\ud83d\udfe2\u26aa\u26aa\u26aa`\n\nYou can create a custom style using `ProgressBarStyle`:\n\n```python\nfrom textcompose.styles import ProgressBarStyle\nfrom textcompose.elements import ProgressBar\n\n\ncustom_style = ProgressBarStyle(\n    left=\"<\", fill=\"*\", empty=\"-\", right=\">\", template=\"{percent} {left}{bar}{right}\"\n)\nbar = ProgressBar(current=7, total=10, width=10, style=custom_style)\nprint(bar.render({}))\n```\n\n**Output:**\n```\n70% <*******--->\n```\n\n##### Template\n\nThe `template` parameter in the style allows you to customize the output string. Available placeholders:\n- `{left}` \u2014 left border\n- `{bar}` \u2014 the bar itself (filled + empty part)\n- `{right}` \u2014 right border\n- `{percent}` \u2014 percent complete (e.g., `42%`)\n- `{total}` \u2014 maximum value\n- `{current}` \u2014 current value\n\n## \ud83e\udd1d Contributing\n\n\ud83d\udca1 Ideas? Issues? PRs are welcome!<br>\nOpen an issue or pull request to help TextCompose get even better.\n\n<br>\n\n> **Ready to supercharge your text formatting?<br>**\n> **Try TextCompose today and make your bots, reports, and notifications shine! \u2728**\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "A Python library for building dynamic, structured text templates using a declarative, compose-based approach",
    "version": "1.2.0",
    "project_urls": {
        "Homepage": "https://github.com/m-xim/textcompose",
        "Issues": "https://github.com/m-xim/textcompose/issues",
        "Repository": "https://github.com/m-xim/textcompose"
    },
    "split_keywords": [
        "compose",
        " logic templates",
        " structured text",
        " template",
        " templating",
        " text generation"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f79f16d0b4174cc25c6440ac6273dbd4e6820209822d8023ebe04e33d26c98e9",
                "md5": "c717ca1a75548a0c03451fc0bc8aecdf",
                "sha256": "f479d4ea56e2f9fcc32d1aa07653ea33793fae9d48528b7093308c47fc0f214e"
            },
            "downloads": -1,
            "filename": "textcompose-1.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c717ca1a75548a0c03451fc0bc8aecdf",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 17555,
            "upload_time": "2025-07-08T15:31:08",
            "upload_time_iso_8601": "2025-07-08T15:31:08.718910Z",
            "url": "https://files.pythonhosted.org/packages/f7/9f/16d0b4174cc25c6440ac6273dbd4e6820209822d8023ebe04e33d26c98e9/textcompose-1.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "00ad1c57d6f901b9ab1934db3eab591bf93ec7a54a7252ff41ef4a52c9b6b165",
                "md5": "8886791ffb27ef325e8b0cf1abd5cce6",
                "sha256": "c2fbd8b6a578cee4feb91eb43b1ed045057a4824417ef69bbcc5a173ec72007a"
            },
            "downloads": -1,
            "filename": "textcompose-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "8886791ffb27ef325e8b0cf1abd5cce6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 34245,
            "upload_time": "2025-07-08T15:31:10",
            "upload_time_iso_8601": "2025-07-08T15:31:10.018247Z",
            "url": "https://files.pythonhosted.org/packages/00/ad/1c57d6f901b9ab1934db3eab591bf93ec7a54a7252ff41ef4a52c9b6b165/textcompose-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-08 15:31:10",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "m-xim",
    "github_project": "textcompose",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "textcompose"
}
        
Elapsed time: 0.65824s