A powerful builder library for creating recursive inline keyboard menus in python-telegram-bot
Project description
Telegram Menu Builder
A powerful, type-safe Python library for creating recursive inline keyboard menus in python-telegram-bot v20+.
โจ Features
- ๐๏ธ Builder Pattern API - Intuitive, fluent interface for menu construction
- ๐ Type-Safe - Full type hints with Python 3.12+, validated with Pyright
- ๐ฆ Smart Callback Encoding - Automatically handles Telegram's 64-byte limit
- ๐พ Hybrid Storage - Inline, temporary (Redis), and persistent (SQL) strategies
- ๐ Unlimited Nesting - Create complex multi-level menus with breadcrumb support
- โก Async-First - Built for modern async/await patterns
- ๐งฉ Pluggable Storage - Bring your own storage backend
- ๐จ Flexible Layouts - Grid layouts, custom columns, navigation buttons
- ๐งช Well Tested - Comprehensive test suite with 90%+ coverage
๐ Quick Start
Installation
pip install telegram-menu-builder
Basic Usage
from telegram import Update
from telegram.ext import Application, CallbackQueryHandler, ContextTypes
from telegram_menu_builder import MenuBuilder, MenuRouter
# Create a menu
async def show_settings(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
menu = (MenuBuilder()
.add_item("๐ Language", handler="set_language")
.add_item("๐ค Profile", handler="edit_profile")
.add_item("๐ Notifications", handler="notifications")
.columns(2)
.add_back_button()
.build())
await update.message.reply_text("โ๏ธ Settings", reply_markup=menu)
# Route callbacks
router = MenuRouter()
@router.handler("set_language")
async def handle_language(update: Update, context: ContextTypes.DEFAULT_TYPE, data: dict) -> None:
# Handle language selection
pass
# Register with application
app = Application.builder().token("YOUR_TOKEN").build()
app.add_handler(CallbackQueryHandler(router.route))
๐ Advanced Examples
Multi-Level Menus with Parameters
menu = (MenuBuilder()
.add_item(
"๐ Edit User",
handler="edit_user",
user_id=123,
field="email",
breadcrumb=["settings", "users"],
validation_required=True
)
.add_item(
"๐๏ธ Delete User",
handler="delete_user",
user_id=123,
confirm=True
)
.columns(1)
.add_back_button(handler="user_list", page=2)
.build())
Submenu Navigation
# Main menu
main_menu = MenuBuilder()
# Create submenu
user_submenu = (MenuBuilder()
.add_item("Add User", handler="add_user")
.add_item("List Users", handler="list_users")
.add_back_button())
# Add submenu to main menu
main_menu.add_submenu("๐ฅ Users", user_submenu)
Custom Storage Backend
from telegram_menu_builder import StorageBackend, MenuBuilder
from redis.asyncio import Redis
class RedisStorage(StorageBackend):
def __init__(self, redis_client: Redis) -> None:
self.redis = redis_client
async def set(self, key: str, data: dict, ttl: int) -> None:
await self.redis.setex(key, ttl, json.dumps(data))
async def get(self, key: str) -> dict | None:
value = await self.redis.get(key)
return json.loads(value) if value else None
# Use custom storage
storage = RedisStorage(redis_client)
builder = MenuBuilder(storage_manager=storage)
๐๏ธ Architecture
The library follows a clean architecture with separation of concerns:
MenuBuilder (API Layer)
โ
MenuAction (Data encoding/decoding)
โ
StorageManager (Strategy selection)
โ
StorageBackend (Interface)
โโโ MemoryStorage
โโโ RedisStorage
โโโ SQLStorage
Callback Data Encoding
The library intelligently encodes callback data based on size:
- Inline (< 60 bytes): Encoded directly in callback_data
- Short-term (60-500 bytes): Stored in Redis/Memory with TTL
- Persistent (> 500 bytes): Stored in database
# Automatic strategy selection
action = MenuAction(
handler="complex_handler",
params={
"user_id": 123,
"filters": {"active": True, "role": "admin"},
"breadcrumb": ["main", "users", "edit"],
"metadata": {...}
}
)
# Library automatically chooses best storage strategy
๐งช Development
Setup Development Environment
# Clone repository
git clone https://github.com/smoxy/telegram-menu-builder.git
cd telegram-menu-builder
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit install
Run Tests
# Run all tests
pytest
# Run with coverage
pytest --cov
# Run specific test file
pytest tests/test_builder.py
# Run type checking
mypy src
pyright
Code Quality
# Format code
black src tests
# Lint code
ruff check src tests
# Run all pre-commit hooks
pre-commit run --all-files
๐ Documentation
Full documentation is available at: https://telegram-menu-builder.readthedocs.io
๐ค Contributing
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐๏ธ Architecture Highlights
Intelligent Callback Data Management
- Automatic Strategy Selection: Chooses between inline, short-term, and persistent storage
- Compression: Zlib compression for inline data
- Deduplication: Same data = same storage key
- 64-byte Limit: Automatically handles Telegram's callback_data constraint
Type Safety
- Pydantic v2: Runtime validation with static type support
- Pyright Strict: 100% type coverage with strict checking
- MyPy Compatible: Dual type checker validation
- Python 3.12+: Modern type hints (generics, Self, Protocol)
Storage Architecture
CallbackData โ Encoder โ Strategy Selector
โโ Inline (< 60 bytes)
โโ Short-term Storage (60-500 bytes, TTL)
โโ Persistent Storage (> 500 bytes)
๐ Acknowledgments
- Built for python-telegram-bot v20+
- Inspired by real-world Telegram bot development challenges
- Type checking powered by Pyright
- Validation powered by Pydantic v2
๐ Project Status
This project is currently in alpha stage. APIs may change before 1.0.0 release.
- โ Core builder API
- โ Callback encoding/decoding
- โ Memory storage backend
- ๐ง Redis storage backend (in progress)
- ๐ง SQL storage backend (in progress)
- ๐ Pagination support (planned)
- ๐ Template system (planned)
- ๐ Form wizard support (planned)
๏ฟฝ Publishing to PyPI
If you want to contribute or publish your own fork:
Build the Package
# Install build tools
pip install build twine
# Build distribution files
python -m build
# Verify the build
twine check dist/*
Upload to PyPI
See PYPI_CONFIG.md for detailed instructions on configuring your PyPI token.
# Using the provided script
python upload_to_pypi.py
# Or manually
twine upload dist/*
๏ฟฝ๐ฌ Support
- ๐ซ Report bugs: GitHub Issues
- ๐ก Request features: GitHub Discussions
- ๐ง Email: info@sf-paris.dev
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
Why MIT License?
The MIT License is chosen to maximize accessibility and enable diverse use cases:
- โ Free to use - Commercial, private, or personal projects
- โ Free to modify - Adapt the code to your needs
- โ Free to distribute - Share with others or on package managers
- โ Training AI Models - Explicitly permitted - this code can be used for training machine learning models and AI systems
- โ Minimal requirements - Only requires attribution and license inclusion
IMPORTANT: This project can be used for training AI models. If you use this code to train language models, code-generation models, or any other AI systems, you are explicitly permitted to do so under the MIT License.
Attribution
If you use this project, we appreciate (but don't require) attribution:
Telegram Menu Builder - MIT License
Copyright (c) 2025 Simone Flavio Paris
https://github.com/smoxy/telegram-menu-builder
Made with โค๏ธ for the Telegram Bot community
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
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