A lightweight DSL on top of python-telegram-bot for writing Telegram bots with decorators and explicit outputs.
Project description
telegram-dsl
Lightweight DSL on top of python-telegram-bot (PTB) that lets you build bots by registering handlers with simple decorators and returning explicit outputs.
Quick start
import os
from telegram_dsl.app import build_app
from telegram_dsl.framework.handlers import command_handler
from telegram_dsl.framework import outputs
# When a user sends /start, the bot replies with a welcome message.
@command_handler(add_to_commands=True)
async def start(args, user):
return outputs.text("Hello! Try /help.")
if __name__ == "__main__":
app = build_app(token=os.getenv("TELEGRAM_TOKEN"), debug=True)
app.run_polling()
build_app auto-loads the caller package (and subpackages) so handlers,
middleware, lifecycle hooks, and error handlers are discovered.
How it works
- You decorate async functions with handlers like
@command_handler,@text_handler,@buttons_handler, etc. - Importing those modules triggers the decorators, which register the handlers in the framework registry.
build_app(...)is your entrypoint: it builds a PTBApplication, auto-imports (autoloads) your package so all decorators run, then adds the registered handlers to the app.- When you run the app (e.g.
app.run_polling()), PTB routes incoming updates (messages, button clicks, …) to the first matching registered handler. - During startup, the framework validates that registered handlers don’t overlap in ambiguous ways (e.g. two handlers that would both match the same update). If a conflict is found, startup fails with a clear error so you can tighten your rules.
Decorators overview
Decorators fall into a few categories. In general, you:
- import a decorator
- apply it to an
async deffunction - return an
outputs.*result from that function
Outputs define what the bot sends back to the user. Common outputs include:
outputs.text(...)for a text messageoutputs.buttons(...)for a text message with inline buttonsoutputs.photo(...),outputs.video(...),outputs.audio(...),outputs.document(...)for mediaoutputs.location(...),outputs.venue(...),outputs.contact(...)for structured messagesoutputs.answer_inline_query(...),outputs.answer_callback_query(...)for Telegram “answer” flowsoutputs.none()to send nothing
| Category | What it’s for | Decorators (examples) | How to use (in general) | Example file |
|---|---|---|---|---|
| Command handlers | Handle /commands (Telegram messages starting with /). |
@command_handler, @unknown_command_handler, @any_command, @prefix_handler, @string_command_handler, @string_regex_handler |
Decorate an async function; validate args if required; return outputs.text(...) (or other outputs). |
examples/weather_cookbook/recipes/00_basics.py |
| Text/media handlers | Handle non-command messages (text and media). | @text_handler, @photo_handler, @video_handler, @audio_handler, @document_handler, @location_handler, @animation_handler, @sticker_handler, @customfilter_text_handler |
Pick the handler that matches the input type; use payload when you need file IDs/metadata; return an outputs.* response. |
examples/weather_cookbook/recipes/01_messages.py |
| Buttons (callback queries) | Handle inline button presses from outputs.buttons(...). |
@buttons_handler |
Use pattern=... to match specific buttons; handler receives callback data in args/payload; return an output; buttons can auto-hide. |
examples/weather_cookbook/recipes/02_buttons.py |
| Conversations (stateful flows) | Build multi-step flows with state. | @conversation_handler, @register_entry_point, @register_state, @register_fallback |
Define an entry point and states; each state is a handler; return outputs.conversation(message, next_state) to move through the flow. |
examples/weather_cookbook/recipes/04_conversations.py |
| Inline mode | Support Telegram inline mode “result lists”. | @inline_query_handler, @chosen_inline_result_handler |
Answer inline queries via outputs.answer_inline_query(...); handle chosen results if needed. |
examples/weather_cookbook/recipes/03_inline_queries.py |
| Update-type handlers | React to specific update types (edits, polls, members, etc.). | @edited_message_handler, @poll_handler, @chat_member_handler, @pre_checkout_query_handler, … |
Use when you need a specific Telegram event; access the raw update when required; return outputs or outputs.none(). |
examples/weather_cookbook/recipes/09_update_types.py |
| Middleware | Run code before/around handlers. | @register_global_middleware, @register_middleware |
Middleware gets (update, context, next); call await next(...) to continue; can modify/replace the handler’s output. |
examples/weather_cookbook/recipes/05_middleware.py |
| Lifecycle hooks | Run code at startup/shutdown. | @register_lifecycle |
Register functions to run when the app starts/stops (e.g. scheduling, setup/teardown). | examples/weather_cookbook/recipes/06_lifecycle.py |
| Error handling | Catch and respond to exceptions. | @register_error_handler |
Register an async function to handle errors; can log and reply with a user-friendly message. | examples/weather_cookbook/recipes/07_errors.py |
Make commands
This repo is set up to run everything via Docker using make:
Release notes:
- Releases are triggered locally via
make release VERSION=X.Y.Zand must be run from themainbranch with a clean working tree. VERSIONmust be newer than the latest existingv*tag (tags are the source of truth for the package version viasetuptools-scm).
| Command | What it does |
|---|---|
make docker-build |
Build the Docker image. |
make cookbook-up |
Run the weather cookbook bot (builds if needed). |
make docker-down |
Stop and remove containers. |
make docker-test |
Run the test suite inside Docker. |
make pkg |
Clean (optional), build, and validate package artifacts into dist/ (make pkg CLEAN=0 skips cleaning). |
make release VERSION=0.1.0 |
Create and push annotated tag v0.1.0; GitHub Actions runs tests, builds artifacts, creates a GitHub Release, and publishes to PyPI. |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file telegram_dsl-0.1.0.tar.gz.
File metadata
- Download URL: telegram_dsl-0.1.0.tar.gz
- Upload date:
- Size: 55.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3a35852711d0070bad97fbd8143a4b13c21a34d0aa52366cb1675cd4784b7ba
|
|
| MD5 |
5602e29fa5916624f8c3098c1a93be52
|
|
| BLAKE2b-256 |
ece976dbc4dfdc74118b628398b972586cebb2aceaf2bf235dc73740112968a5
|
Provenance
The following attestation bundles were made for telegram_dsl-0.1.0.tar.gz:
Publisher:
release.yml on ciurlaro/telegram-dsl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
telegram_dsl-0.1.0.tar.gz -
Subject digest:
d3a35852711d0070bad97fbd8143a4b13c21a34d0aa52366cb1675cd4784b7ba - Sigstore transparency entry: 775096996
- Sigstore integration time:
-
Permalink:
ciurlaro/telegram-dsl@3a9337ac17479f6a250f1fbd543694d995952393 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ciurlaro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3a9337ac17479f6a250f1fbd543694d995952393 -
Trigger Event:
push
-
Statement type:
File details
Details for the file telegram_dsl-0.1.0-py3-none-any.whl.
File metadata
- Download URL: telegram_dsl-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76fa4354e1361181f700ec8bc612239cbeb412c6a17a8e7587436da5c211c27c
|
|
| MD5 |
d6ba00f84a00770e97f388b31d1a76f8
|
|
| BLAKE2b-256 |
337478def2e89f802d01c4a1b76b57702ac24c4f5e86c7d8a4b1cae33b7d5cb0
|
Provenance
The following attestation bundles were made for telegram_dsl-0.1.0-py3-none-any.whl:
Publisher:
release.yml on ciurlaro/telegram-dsl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
telegram_dsl-0.1.0-py3-none-any.whl -
Subject digest:
76fa4354e1361181f700ec8bc612239cbeb412c6a17a8e7587436da5c211c27c - Sigstore transparency entry: 775097003
- Sigstore integration time:
-
Permalink:
ciurlaro/telegram-dsl@3a9337ac17479f6a250f1fbd543694d995952393 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/ciurlaro
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3a9337ac17479f6a250f1fbd543694d995952393 -
Trigger Event:
push
-
Statement type: