telegram-bot-lite-py
Lightweight Telegram Bot API client — send messages, build keyboards, handle webhooks, all async with zero dependencies.
Pure Python ≥ 3.9. No httpx, no aiohttp, no requests. Just the stdlib.
pip install telegram-bot-lite-py
Features
- Async-first — built on
asyncio+ stdlib SSL - Full Bot API coverage: messages, media, keyboards, commands, callbacks
- Composable update filters (
&,|,~) - Long-polling and webhook modes
- Fluent keyboard builders
- Typed dataclasses for every API object
- Zero third-party dependencies
Quick Start
Echo bot (long polling)
import asyncio
from telegram_bot_lite_py import TelegramBot, Dispatcher
from telegram_bot_lite_py.filters import Filters
bot = TelegramBot("YOUR_BOT_TOKEN")
dp = Dispatcher(bot)
@dp.on_command("start")
async def on_start(bot, update):
await bot.reply(update.message, "Hello! I'm alive 🤖")
@dp.on_message(Filters.text)
async def on_text(bot, update):
await bot.reply(update.message, f"You said: {update.message.text}")
dp.run_polling()
One-shot notification (no dispatcher needed)
import asyncio
from telegram_bot_lite_py import TelegramBot
async def notify():
bot = TelegramBot("YOUR_BOT_TOKEN")
await bot.send_message(CHAT_ID, "<b>Deploy complete!</b>", parse_mode="HTML")
asyncio.run(notify())
Installation
pip install telegram-bot-lite-py
Requires Python 3.9+. No other packages needed.
API Reference
TelegramBot
from telegram_bot_lite_py import TelegramBot
bot = TelegramBot(
token="YOUR_BOT_TOKEN",
timeout=30.0, # per-request timeout in seconds
parse_mode="HTML", # default parse mode: "HTML", "Markdown", "MarkdownV2", or None
)
Sending messages
| Method | Description |
|---|---|
await bot.send_message(chat_id, text, *, parse_mode, reply_markup, ...) |
Send a text message |
await bot.reply(message, text, *, parse_mode, reply_markup) |
Reply to a specific message |
await bot.notify(chat_id, text) |
Shorthand alias for send_message |
await bot.send_photo(chat_id, photo, *, caption, ...) |
Send photo by file_id, URL, or bytes |
await bot.send_document(chat_id, document, *, caption, ...) |
Send document |
await bot.send_audio(chat_id, audio, *, caption, performer, title, ...) |
Send audio |
await bot.send_video(chat_id, video, *, caption, duration, ...) |
Send video |
await bot.send_location(chat_id, lat, lon, ...) |
Send a map pin |
await bot.send_contact(chat_id, phone, first_name, ...) |
Send a contact |
await bot.send_chat_action(chat_id, action) |
Show "typing…" or other indicators |
await bot.forward_message(chat_id, from_chat_id, message_id) |
Forward a message |
await bot.copy_message(chat_id, from_chat_id, message_id) |
Copy (without forward tag) |
Editing & deleting
| Method | Description |
|---|---|
await bot.edit_message_text(text, *, chat_id, message_id, ...) |
Edit message text |
await bot.edit_message_reply_markup(*, chat_id, message_id, reply_markup) |
Update keyboard only |
await bot.delete_message(chat_id, message_id) |
Delete a message |
Callback queries
| Method | Description |
|---|---|
await bot.answer_callback_query(callback_query_id, *, text, show_alert, url) |
Answer an inline button press |
Chat management
| Method | Description |
|---|---|
await bot.get_chat(chat_id) |
Fetch Chat info |
await bot.leave_chat(chat_id) |
Leave a group/channel |
await bot.ban_chat_member(chat_id, user_id, ...) |
Ban a user |
await bot.unban_chat_member(chat_id, user_id) |
Unban a user |
await bot.get_chat_member_count(chat_id) |
Member count |
Bot setup
| Method | Description |
|---|---|
await bot.get_me() |
Fetch the bot's User object |
await bot.set_my_commands(commands) |
Set the command list shown in clients |
await bot.get_my_commands() |
Get current commands |
await bot.delete_my_commands() |
Remove all commands |
Webhook
| Method | Description |
|---|---|
await bot.set_webhook(url, *, secret_token, max_connections, ...) |
Register a webhook |
await bot.delete_webhook(*, drop_pending_updates) |
Remove the webhook |
await bot.get_webhook_info() |
Fetch current webhook status |
Files
| Method | Description |
|---|---|
await bot.get_file(file_id) |
Fetch File metadata |
bot.get_file_url(file_path) |
Build the download URL for a File |
Dispatcher
from telegram_bot_lite_py import Dispatcher
dp = Dispatcher(bot, workers=4)
Decorators
@dp.on_command("start", "help")
async def cmd_handler(bot, update): ...
@dp.on_message(Filters.text & ~Filters.command("start"))
async def text_handler(bot, update): ...
@dp.on_callback("confirm", "cancel")
async def callback_handler(bot, update): ...
@dp.on_callback(prefix="page:")
async def paginate(bot, update): ...
@dp.on_error()
async def error_handler(bot, update, exc): ...
Low-level registration
from telegram_bot_lite_py.filters import Filters
dp.add_handler(my_fn, Filters.photo, priority=10)
Running
# Blocking (runs asyncio event loop internally)
dp.run_polling(timeout=30, drop_pending=True)
# Inside an existing event loop
await dp.start_polling(timeout=30)
Filters
from telegram_bot_lite_py.filters import Filters
Filters.message # any message update
Filters.edited_message # edited message
Filters.callback_query # callback query
Filters.channel_post # channel post
Filters.text # message has text
Filters.photo # message has photo
Filters.document # message has document
Filters.audio
Filters.video
Filters.location
Filters.contact
Filters.sticker
Filters.private # private chat
Filters.group # group or supergroup
Filters.channel # channel
Filters.command("start", "help")
Filters.regex(r"order #\d+")
Filters.text_equals("yes", "no")
Filters.text_contains("hello")
Filters.user(123456, 789012) # whitelist by user_id
Filters.chat(-100123456789) # whitelist by chat_id
Filters.callback_data("ok", "cancel")
Filters.callback_prefix("page:")
Filters.custom_filter(lambda u: u.effective_user.is_premium)
Combine with &, |, ~:
private_text = Filters.text & Filters.private
not_bot = ~Filters.user(bot_id)
media = Filters.photo | Filters.video | Filters.document
Keyboard builders
Inline keyboards
from telegram_bot_lite_py.keyboards import InlineKeyboard, inline_keyboard
# Fluent builder
kb = (
InlineKeyboard()
.button("Yes", callback_data="yes")
.button("No", callback_data="no")
.row()
.button("Visit", url="https://sarmkadan.com")
.build()
)
# Compact factory
kb = inline_keyboard(
[("Option A", "a"), ("Option B", "b")],
[("Cancel", "cancel")],
)
await bot.send_message(chat_id, "Choose:", reply_markup=kb)
Reply keyboards
from telegram_bot_lite_py.keyboards import ReplyKeyboard, reply_keyboard
# Fluent builder
kb = (
ReplyKeyboard(resize=True, one_time=True)
.button("Share Location", request_location=True)
.row()
.button("Share Contact", request_contact=True)
.build()
)
# Compact factory
kb = reply_keyboard(["Yes", "No"], ["Maybe", "Cancel"], resize=True)
await bot.send_message(chat_id, "Choose:", reply_markup=kb)
Remove / force reply
from telegram_bot_lite_py.keyboards import remove_keyboard, force_reply
await bot.send_message(chat_id, "Keyboard removed", reply_markup=remove_keyboard())
await bot.send_message(chat_id, "Enter your name:", reply_markup=force_reply(placeholder="Your name"))
Webhook server
import ssl
from telegram_bot_lite_py import TelegramBot, Dispatcher, WebhookServer
bot = TelegramBot("YOUR_BOT_TOKEN")
dp = Dispatcher(bot)
@dp.on_command("start")
async def start(bot, update):
await bot.reply(update.message, "Hello from webhook!")
# Optional TLS termination
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("cert.pem", "key.pem")
server = WebhookServer(
dp,
host="0.0.0.0",
port=8443,
path="/webhook",
secret_token="my-secret",
ssl_context=ctx,
)
# Register webhook then start
import asyncio
async def main():
await bot.set_webhook(
"https://your-domain.com/webhook",
secret_token="my-secret",
max_connections=40,
)
await server.start()
# keep running
await asyncio.Event().wait()
asyncio.run(main())
Types
All Telegram API objects are plain Python dataclasses.
from telegram_bot_lite_py import Update, Message, User, Chat, CallbackQuery
update: Update
update.update_id
update.message # Message | None
update.edited_message # Message | None
update.callback_query # CallbackQuery | None
update.effective_message # first non-None of message / edited_message / channel_post
update.effective_chat # Chat | None
update.effective_user # User | None
message: Message
message.message_id
message.chat # Chat
message.from_user # User | None
message.text # str | None
message.content_type # "text" | "photo" | "document" | ...
message.get_command() # "/start" | None
message.get_args() # "arg1 arg2" – everything after the command
user: User
user.id
user.full_name # "First Last"
user.mention # "@username" or full name
chat: Chat
chat.id
chat.type # "private" | "group" | "supergroup" | "channel"
chat.is_private # bool
chat.is_group # bool
chat.display_name # title or first_name
Error handling
from telegram_bot_lite_py.exceptions import (
TelegramAPIError,
RetryAfterError,
ForbiddenError,
NetworkError,
)
@dp.on_error()
async def handle_error(bot, update, exc):
if isinstance(exc, RetryAfterError):
print(f"Flood limit. Retry after {exc.retry_after}s")
elif isinstance(exc, ForbiddenError):
print("Bot was blocked by user")
elif isinstance(exc, NetworkError):
print(f"Network problem: {exc}")
else:
print(f"Unhandled error: {exc}")
Examples
Notification bot
import asyncio
from telegram_bot_lite_py import TelegramBot
async def alert(chat_id: int, message: str):
bot = TelegramBot("YOUR_TOKEN")
await bot.send_message(chat_id, f"<b>Alert</b>\n{message}", parse_mode="HTML")
asyncio.run(alert(-100123456789, "Server CPU above 90%"))
Paginated inline buttons
@dp.on_command("list")
async def cmd_list(bot, update):
kb = inline_keyboard(
[("Item 1", "item:1"), ("Item 2", "item:2")],
[("< Prev", "page:0"), ("Next >", "page:2")],
)
await bot.reply(update.message, "Choose an item:", reply_markup=kb)
@dp.on_callback(prefix="item:")
async def on_item(bot, update):
item_id = update.callback_query.data.split(":")[1]
await bot.answer_callback_query(update.callback_query.id, text=f"Selected item {item_id}")
@dp.on_callback(prefix="page:")
async def on_page(bot, update):
page = int(update.callback_query.data.split(":")[1])
await bot.answer_callback_query(update.callback_query.id, text=f"Page {page}")
Admin-only commands
ADMIN_IDS = [123456789]
@dp.on_command("ban", priority=100)
async def cmd_ban(bot, update):
if update.effective_user.id not in ADMIN_IDS:
await bot.reply(update.message, "Access denied.")
return
# ... ban logic
License
MIT — see LICENSE.
© 2024 Vladyslav Zaiets — sarmkadan.com
Metadata
Release files for telegram-bot-lite-py 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| telegram_bot_lite_py-1.0.0.tar.gz | 21.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| telegram_bot_lite_py-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 48.6 kB
Release files / telegram_bot_lite_py-1.0.0.tar.gz
| Download URL | telegram_bot_lite_py-1.0.0.tar.gz |
|---|---|
| Size | 21.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b400fb1c6691aa237beca3e9bfa7367779786f59f76949e3375c0f0acfaaa2f
|
|
BLAKE2b-256 checksum How to use checksums |
2b7523478ed4b371a0ad7d6e16c0ebb60d421c4e9db8d08366eb3d73ab29c24e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / telegram_bot_lite_py-1.0.0-py3-none-any.whl
| Download URL | telegram_bot_lite_py-1.0.0-py3-none-any.whl |
|---|---|
| Size | 26.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a21fb98e03c329b79bc7e9f1ea4d917939b0a003540213331e6352e89531c28d
|
|
BLAKE2b-256 checksum How to use checksums |
82a09587feec6002becec1ce54b068be82697f0426bcb47fb151b7caeee1fd56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|