Reusable Telegram bot framework with Clean Architecture
Project description
Bot Framework
Reusable Python library for building Telegram bots with Clean Architecture principles.
Installation
# Basic installation
pip install bot-framework
# With Telegram support
pip install bot-framework[telegram]
# With all optional dependencies
pip install bot-framework[all]
Features
- Clean Architecture - Layered architecture with import-linter enforcement
- Telegram Integration - Ready-to-use services for pyTelegramBotAPI
- Flow Management - Dialog flow stack management with Redis storage
- Role Management - User roles and permissions
- Language Management - Multilingual phrase support
- Request Role Flow - Pre-built flow for role requests
Quick Start
from bot_framework import Button, Keyboard
from bot_framework.app import BotApplication
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
)
# Use unified message service
message_service = app.message_service
keyboard = Keyboard(rows=[
[Button(text="Option 1", callback_data="opt1")],
[Button(text="Option 2", callback_data="opt2")],
])
# Send new message
message_service.send(chat_id=123, text="Choose an option:", keyboard=keyboard)
# Replace existing message
message_service.replace(chat_id=123, message_id=456, text="Updated text")
# Delete message
message_service.delete(chat_id=123, message_id=456)
Message Services
Bot Framework provides a unified TelegramMessageService that combines all message operations:
| Method | Description |
|---|---|
send() |
Send a new message |
send_markdown_as_html() |
Send markdown converted to HTML |
send_document() |
Send a file |
replace() |
Edit existing message |
delete() |
Delete message |
notify_replace() |
Delete old message and send new one |
Using in your handlers
Use IMessageService protocol for dependency injection:
from bot_framework.protocols.i_message_service import IMessageService
class MyHandler:
def __init__(self, message_service: IMessageService) -> None:
self.message_service = message_service
def handle(self, chat_id: int, message_id: int) -> None:
# Switch between send/replace by changing method name only
self.message_service.replace(
chat_id=chat_id,
message_id=message_id,
text="Updated!",
)
Legacy services (still available)
Individual services are still available for backwards compatibility:
message_sender = app.message_sender # IMessageSender
message_replacer = app.message_replacer # IMessageReplacer
message_deleter = app.message_deleter # IMessageDeleter
Bot Commands
Set up bot commands in BotFather using /setcommands. Copy and paste the following:
start - Start the bot
request_role - Request a role
language - Change language
This enables command autocompletion in Telegram when users type /.
Database Migrations
Bot Framework includes built-in database migrations using yoyo-migrations. Migrations are applied automatically when creating a BotApplication instance.
Automatic migrations (default)
from bot_framework.app import BotApplication
# Migrations are applied automatically
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
)
Disable automatic migrations
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
auto_migrate=False, # Disable automatic migrations
)
Manual migration
from bot_framework.migrations import apply_migrations
# Returns number of applied migrations
applied_count = apply_migrations("postgres://user:pass@localhost/dbname")
Created tables
languages- Supported languages (en, ru by default)roles- User roles (user, supervisors by default)users- Bot usersphrases- Multilingual phrasesuser_roles- User-role associations
Configuration
Bot Framework uses JSON files to configure roles, phrases, and languages. The library provides default values, and you can extend them with your own configuration files.
Roles
Roles define user permissions in your bot. The library includes two base roles: user (default for all users) and supervisors (role approvers).
Add custom roles by creating data/roles.json in your project:
{
"roles": [
{"name": "admin", "description": "Administrator with full access"},
{"name": "moderator", "description": "Content moderator"}
]
}
Pass the path to BotApplication:
from pathlib import Path
from bot_framework.app import BotApplication
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
roles_json_path=Path("data/roles.json"),
)
Roles are synced to the database on startup using INSERT ... ON CONFLICT DO NOTHING, so it's safe to run multiple times.
Using roles in handlers:
class AdminOnlyHandler:
def __init__(self):
self.allowed_roles: set[str] | None = {"admin"}
Phrases
Phrases provide multilingual text for your bot. Each phrase has a hierarchical key and translations for each supported language.
Add custom phrases by creating data/phrases.json:
{
"mybot.greeting": {
"ru": "Привет! Я ваш помощник.",
"en": "Hello! I'm your assistant."
},
"mybot.help.title": {
"ru": "Справка",
"en": "Help"
},
"mybot.errors.not_found": {
"ru": "Не найдено",
"en": "Not found"
}
}
Pass the path to BotApplication:
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
phrases_json_path=Path("data/phrases.json"),
)
Using phrases:
# Get phrase for user's language
text = app.phrase_provider.get("mybot.greeting", language_code="ru")
Key naming convention: Use dot-separated hierarchical keys like module.context.action (e.g., orders.validation.empty_cart).
Languages
Languages define which translations are available. The library includes English and Russian by default.
Add custom languages by creating data/languages.json:
{
"languages": [
{"code": "ru", "name": "Russian", "native_name": "Русский"},
{"code": "en", "name": "English", "native_name": "English"},
{"code": "es", "name": "Spanish", "native_name": "Español"}
],
"default_language": "en"
}
Pass the path to BotApplication:
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
languages_json_path=Path("data/languages.json"),
)
Full configuration example
from pathlib import Path
from bot_framework.app import BotApplication
app = BotApplication(
bot_token="YOUR_BOT_TOKEN",
database_url="postgres://user:pass@localhost/dbname",
redis_url="redis://localhost:6379/0",
roles_json_path=Path("data/roles.json"),
phrases_json_path=Path("data/phrases.json"),
languages_json_path=Path("data/languages.json"),
)
app.run()
Project structure:
my_bot/
├── data/
│ ├── roles.json
│ ├── phrases.json
│ └── languages.json
├── handlers/
│ └── ...
└── main.py
Optional Dependencies
telegram- pyTelegramBotAPI for Telegram bot integrationpostgres- psycopg and yoyo-migrations for PostgreSQL database supportredis- Redis for caching and flow state managementall- All optional dependencies
License
MIT
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 bot_framework-0.1.6.tar.gz.
File metadata
- Download URL: bot_framework-0.1.6.tar.gz
- Upload date:
- Size: 71.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0eca0a2521db8b42b2a90ab1c5b369383e66aef8230a1546192c14757b371d75
|
|
| MD5 |
2702b186d44a3cc7c75dc04ddc4a186b
|
|
| BLAKE2b-256 |
1b23f40b455ffbccf005ad01d8e03e9d655b15820fc4355d27677aef23e82d60
|
File details
Details for the file bot_framework-0.1.6-py3-none-any.whl.
File metadata
- Download URL: bot_framework-0.1.6-py3-none-any.whl
- Upload date:
- Size: 93.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
190552a70901cf7842ec9f79813d7a9ed81b2381c905333d389ef9405a588c73
|
|
| MD5 |
de6ce858e214cffd90e057598932b3d6
|
|
| BLAKE2b-256 |
9e14e50003de1a1295f385872dfc53942af5114398a38d8015a0db8f0df33436
|