Skip to main content

Declarative, developer-friendly library for building Telegram bots

Project description

TeleKit

PyPi Python PyPi Downloads

Telekit

Telekit is a declarative, developer-friendly library for building Telegram bots. It gives developers a dedicated Sender for composing and sending messages and a Chain for handling dialogue between the user and the bot. The library also handles inline keyboards and callback routing automatically, letting you focus on the bot's behavior instead of repetitive tasks.

import telekit

class MyStartHandler(telekit.Handler):
    @classmethod
    def init_handler(cls):
        cls.on.command('start').invoke(cls.handle_start)

    def handle_start(self):
        self.chain.sender.set_text("Hello!")
        self.chain.sender.set_photo("robot.png")
        self.chain.send()

telekit.Server("BOT_TOKEN").polling()

Send "Hello!" with a photo on /start

Telekit comes with a built-in DSL, allowing developers to create fully interactive bots with minimal code. It also integrates Jinja, giving you loops, conditionals, expressions, and filters to generate dynamic content.

@ main {
    title   = "🎉 Fun Facts Quiz";
    message = "Test your knowledge with 10 fun questions!";

    buttons {
        question_1("Start Quiz");
    }
}

See the full example

Even in its beta stage, Telekit accelerates bot development, offering typed command parameters, text styling via Bold(), Italic(), built-in emoji game results for 🎲 🎯 🏀 ⚽ 🎳 🎰, and much more out of the box. Its declarative design makes bots easier to read, maintain, and extend.

Key features:

  • Declarative bot logic with chains for effortless handling of complex conversations
  • Ready-to-use DSL for FAQs and other interactive scripts
  • Automatic handling of message formatting via Sender and callback routing
  • Deep Linking support with type-checked Command Parameters for flexible user input
  • Built-in Permission and Logging system for user management
  • Seamless integration with pyTelegramBotAPI
  • Fast to develop and easy-to-extend code

GitHub PyPi Telegram Community

Contents

Overview

Telekit is a library for building Telegram bots where dialogs look like normal method calls. No bulky state machines. No scattered handlers.

The idea is simple: you point to the next step — Telekit calls it when the user replies.

Entries

No state machines. Just tell Telekit which method should handle the next user message.

def handle(self):
    self.chain.sender.set_text("👋 Hello! What is your name?")
    self.chain.set_entry_text(self.handle_name)
    self.chain.send()

def handle_name(self, name: str):
    self.chain.sender.set_text(f"Nice to meet you, {name}!")
    self.chain.send()

The handle method sends a message and registers handle_name as the next step using set_entry_text. When the user replies, Telekit automatically calls handle_name and passes the user's message as a plain str argument.

That's it. No enums. No manual state tracking. No boilerplate.

Inline Keyboards

Buttons can either return a value or call a method directly.

Choice keyboard — map button labels to values. The selected value is passed straight into your handler:

self.chain.set_inline_choice(
    self.on_choice,
    choices={
        "Option 1": "Value 1",
        "Option 2": "Value 2",
        "Option 3": [3, "Yes, it's an array"],
    }
)

def on_choice(self, choice: str | list):
    print(f"{choice!r}") # "Value 1", "Value 2" or [3, "Yes, it's an array"]

Inside on_choice, you receive exactly what you defined in choices: a string, list, number, function — anything.

Callback keyboard — each button calls its own method:

self.chain.set_inline_keyboard({
    "« Back": self.display_previous_page,
    "Next »": self.display_next_page,
})

Useful for pagination, navigation, or menus.

Command Parameters

Telekit can parse and validate command parameters for you.

from telekit.parameters import *

class GreetHandler(telekit.Handler):
    @classmethod
    def init_handler(cls) -> None:
        cls.on.command("greet", params=[Int(), Str()]).invoke(cls.handle)

    def handle(self, age: int | None = None, name: str | None = None):
        if age is None or name is None:
            self.chain.sender.set_text("Usage: /greet <age> <name>")
        else:
            self.chain.sender.set_text(f"Hello, {name}! You are {age} years old. Next year you'll turn {age + 1} 😅")
        self.chain.send()

Now /greet 64 "Alice Reingold" or /greet 128 Dracula are parsed automatically.

[!INFO] If arguments are invalid or missing, you simply receive None and decide how to respond.

Dialogue

Dialogs are built as a chain of steps. Each method waits for the user before continuing.

class DialogueHandler(telekit.Handler):

    @classmethod
    def init_handler(cls) -> None:
        cls.on.text("hello", "hi", "hey").invoke(cls.handle_hello)

    def handle_hello(self) -> None:
        self.chain.sender.set_text("👋 Hello! What is your name?")
        if self.user.first_name:
            self.chain.set_entry_suggestions([self.user.first_name])
        self.chain.set_entry_text(self.handle_name)
        self.chain.send()

    def handle_name(self, name: str) -> None:
        self.user_name = name
        self.chain.sender.set_text("Nice! How are you feeling today?")
        self.chain.set_entry_text(self.handle_feeling)
        self.chain.send()

    def handle_feeling(self, feeling: str) -> None:
        self.chain.sender.set_text(f"Got it, {self.user_name.title()}! You feel: {feeling}")
        self.chain.set_inline_keyboard({"↺ Restart": self.handle_hello})
        self.chain.send()

How it works:

  • The handler reacts to "hello", "hi", or "hey" (lowercase, UPPERCASE, or mixed).
  • handle_hello asks for the user's name.
  • set_entry_suggestions attaches the user's Telegram first_name as a suggestion button.
  • handle_name stores the name in self.user_name.
  • handle_feeling completes the flow and adds a "↺ Restart" button that routes back to the beginning.

It looks like regular Python. And reads like it too.

Sender

Want to add an image, document or an effect in a single line?

self.chain.sender.set_effect(Effect.HEART) # Add effect to message. Use enum or string
self.chain.sender.set_photo("robot.png") # Attach photo. URL, file_id, or path
self.chain.sender.set_document("README.md") # Attach document. URL, file_id, or path
self.chain.sender.set_text_as_document("Hello, this is a text document!") # Convert string to text document
self.chain.sender.send_chat_action(ChatAction.TYPING) # Send chat action. Use enum or string

[!NOTE] Telekit automatically decides whether to use 'bot.send_message' or 'bot.send_photo' based on the content

Styles

Telekit lets you describe formatting as objects instead of writing raw HTML or Markdown.

from telekit.styles import *

def handle(self) -> None:
    self.chain.sender.set_text(
        Bold("Text style examples:\n"),
        Stack(
            Bold("Bold text"),
            Italic("Italic text"),
            Bold(Italic("Bold + italic")),
            Link("Link", url="https://example.com"),
            BotLink("Deep link", username="MyBot", start="promo_42"),
            start="- {{index}}. ",
            sep=".\n",
        )
    )
    self.chain.send()

You describe structure. Telekit generates HTML or MarkdownV2 automatically:

<b>Text style examples:</b>

- 1. <b>Bold text</b>.
- 2. <i>Italic text</i>.
- 3. <b><i>Bold + italic</i></b>.
- 4. <a href="https://example.com">Link</a>.
- 5. <a href="https://t.me/MyBot?start=promo_42">Deep link</a>

No manual escaping. No broken formatting because of one missing character.

Telekit DSL

If you prefer not to write dialog logic in Python, you can use the built-in DSL with Jinja support.

import telekit

class QuizHandler(telekit.TelekitDSL.Mixin):
    @classmethod
    def init_handler(cls) -> None:
        cls.analyze_string(script)
        cls.on.command("start").invoke(cls.start_script)

script = """
$ timeout {
    time = 20; // 20 sec.
}

@ main {
    title   = "🎉 Fun Facts Quiz";
    message = "Test your knowledge with 10 fun questions!";

    buttons {
        next("Start Quiz");
    }
}

@ question_1 {
    title   = "🐶 Question 1";
    message = "Which animal is the fastest on land?";
    buttons {
        _lose("Elephant");
        next("Cheetah");       // correct answer
        _lose("Horse");
        _lose("Lion");
    }
}

/* ... */
"""

telekit.Server(BOT_TOKEN).polling()

Key features of the Telekit DSL:

  • Scene-based architecture
  • Anonymous scenes
  • Automatic navigation stack management
  • Input handling
  • Images support and link buttons
  • Template variables
  • Custom variables
  • Hooks (Python API integration)
  • Jinja template engine
Click to see what you can do with the DSL
Telekit Example 7 Telekit Example 8

You can find a full quiz example and DSL reference in the repository.

Example Bot

You can launch an example bot by running the following code:

import telekit

telekit.example(YOUR_BOT_TOKEN)

It includes example commands, dialogs, keyboards, and style usage.

Why Telekit

  • No FSM — just chains.
  • Declarative, behavior-focused bot logic with minimal boilerplate.
  • Automatic callback routing and input handling.
  • Styles API for rich text (Bold, Italic, Links) with automatic escaping.
  • Deep linking and typed command parameters.
  • Built-in DSL for menus, FAQs, and simple bots.
  • Zero-code Obsidian Canvas mode.
  • Seamless integration with pyTelegramBotAPI.

Telekit doesn't try to be everything.
It tries to make Telegram bot development easier.

[!TIP] If you're interested and want to learn more, check out the Tutorial


Changes in version 2.0.1

Obsidian Canvas Mode (Beta)

Build bots visually — no DSL required. Design your dialog flow as a flowchart in Obsidian and connect it to Telekit with a single method call.

  • Added analyze_canvas() to DSLHandler — loads a .canvas file as an executable model

Styles Improvements

The style system has been rewritten from the ground up. Previously, automatic escaping was quite unpredictable — users couldn't always tell when a string would be escaped or not. That's over.

  • Migrated markdown rendering to MarkdownV2
  • Added Stack style for structured list rendering
  • Added Mention style
  • Renamed Sanitize to Escape
  • Renamed NoSanitize to Raw
  • Added utils.sanitize_markdown() — escapes all MarkdownV2 special characters outside valid entities
  • Added utils.adapt_markdown() — converts **bold** / *italic* to Telegram-compatible format
  • Added utils.telegramify_markdown() — convenience pipeline: adapt + sanitize
  • StyleFormatter renamed to TextEntity

Inline Keyboards

Inline keyboards got a proper type system. Previously, any string value in the keyboard dict was treated as a link. Now every button type is explicit.

  • Introduced InlineButton base class with subclasses: LinkButton, WebAppButton, SuggestButton, CopyTextButton, CallbackButton
  • CallbackButton — pass arguments to callbacks and set visual style
  • Added ButtonStyle enum — style your inline buttons (Bot API 9.4)
  • Added inline_choice / set_inline_choice methods
  • set_entry_suggestions now warns when Telegram Bot API limits are exceeded
  • It's no longer pass Message object to callbacks
  • Reduced closure size and improved callback performance

Chain Improvements

  • Added set_break_only_on_match() — control whether chain interrupts only on valid handler match, not random input
  • Added set_break_on_commands() — control whether commands take priority over entry handlers
  • Improved file extension validation via pathlib
  • entry_* handlers no longer pass Message by default — use include_message=True to restore

CallbackQueryHandler

  • Callbacks now invoked directly — no virtual message conversion, faster response times
  • Native alert support for expired or inactive buttons
  • Added set_invalid_data_answer() and set_button_is_no_active_answer() for global customization

DSL Improvements

  • jinja_env is now private — use get_jinja_env() instead
  • TelekitDSL class:
    • All from_* factory methods now use type() for class creation

Fixes

  • Fixed one-time trigger bug — triggers like on.text now fire reliably across multiple messages while a chain timeout is active

Other

  • Added utils.read_token() and utils.read_canvas_path() — clean helpers for reading credentials from files
  • Added utils.format_file_size()
  • Added set_license_text to senders
  • Added format_size to TextDocument
  • Added TelekitState class
  • Bumped pyTelegramBotAPI to v4.31.0
  • Added GPL v3 License

🚀 Upcoming

  • New triggers: document, text_document
  • Telekit DSL: shorter notation and button attributes with style, alert, ... support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

telekit-2.0.1.tar.gz (108.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

telekit-2.0.1-py3-none-any.whl (130.2 kB view details)

Uploaded Python 3

File details

Details for the file telekit-2.0.1.tar.gz.

File metadata

  • Download URL: telekit-2.0.1.tar.gz
  • Upload date:
  • Size: 108.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for telekit-2.0.1.tar.gz
Algorithm Hash digest
SHA256 3962a69be94a857fcac4d33044fc3b977658eb2ec4030eb30ec7dffbfb7cff00
MD5 870b1737f7f01aad7040a8c1dfbddcd0
BLAKE2b-256 5332567cd05132f4df05383271d5790c1b96ab023fc99693cd2191641372006e

See more details on using hashes here.

File details

Details for the file telekit-2.0.1-py3-none-any.whl.

File metadata

  • Download URL: telekit-2.0.1-py3-none-any.whl
  • Upload date:
  • Size: 130.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.11

File hashes

Hashes for telekit-2.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 17692aedd74950a5e1b5ef70269016ee6364af35d0283458ef188ffd8e59478e
MD5 e83ed5580e1b1f4a6a39113bf8a3d2d5
BLAKE2b-256 305906a01781e0b81c99d7c0c391ce48dc1f1f63b6605ebc83a060c31e30aaca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page