Minimal Python wrapper for the Telegram Bot API; one Event, one router, sync and async.
Project description
Shingram
Minimal Python wrapper for the Telegram Bot API. Future-proof: new API methods work without library updates. Dual mode: same code works sync or async. All updates normalized to a single Event object — no dozens of classes to learn.
Features
- Zero hardcoding — Call any Telegram method; new API features work immediately
- One Event type — Every update (message, callback, inline, etc.) has the same shape
- Sync & Async — Use
bot.run()orbot.run_async()with the same handlers - ~1,200 lines — Lightweight, readable, easy to contribute
Installation
pip install shingram
Documentation
Full documentation: nouzumoto.github.io/shingram
Quick Start
from shingram import Bot
bot = Bot("YOUR_BOT_TOKEN")
@bot.on("command:start")
def handle_start(event):
bot.send_message(chat_id=event.chat_id, text="Hello!")
@bot.on("message")
def handle_message(event):
bot.send_message(chat_id=event.chat_id, text=f"You wrote: {event.text}")
bot.run()
Event types
- Commands:
command:start,command:help, etc. Usecommandto catch all commands - Messages:
messagefor text messages - Edited messages:
edited_messagefor edited text messages - Channel posts:
channel_postandedited_channel_post - Inline queries:
inline_queryfor inline search queries - Callback queries:
callbackfor inline button clicks - Join/Leave events:
joinandleavefor group membership changes - Poll updates:
pollandpoll_answerfor poll-related events - Chat member updates:
chat_memberandmy_chat_member - Chat join requests:
chat_join_request - Business messages:
business_message,edited_business_message,business_connection - Message reactions:
message_reactionandmessage_reaction_count - Chat boosts:
chat_boostandremoved_chat_boost - Shipping and payment:
shipping_query,pre_checkout_query - Chosen inline results:
chosen_inline_result
Handlers always get the same Event; the field that varies is type (and name for commands/callbacks).
Event fields
@dataclass
class Event:
type: str # Event type: "command", "message", "callback", etc.
name: str # Event name: "start" for commands, "" for others
chat_id: int # Chat ID (0 if not applicable)
user_id: int # User ID (0 if not applicable)
text: str # Message text or callback data
raw: dict # Complete raw data from Telegram API
reply_to: Optional[int] # ID of replied message (if present)
chat_type: Optional[str] # "private", "group", "supergroup", "channel"
inline_query_id: Optional[str] # For inline_query events
callback_query_id: Optional[str] # For callback_query events
message_id: Optional[int] # Message ID (if available)
username: Optional[str] # User username (if available)
first_name: Optional[str] # User first name (if available)
chat_title: Optional[str] # Chat title (for groups/channels)
last_name: Optional[str] # User last name (if available)
language_code: Optional[str] # User language code (if available)
content_type: Optional[str] # "text", "photo", "document", etc. (for messages)
Async
Use async def handlers and start the bot with bot.run_async(). For API calls use await bot.async_client.send_message(...) (and the other methods on bot.async_client).
from shingram import Bot
bot = Bot("YOUR_BOT_TOKEN")
@bot.on("command:start")
async def handle_start(event):
await bot.async_client.send_message(chat_id=event.chat_id, text="Hello!")
@bot.on("message")
async def handle_message(event):
if event.text:
await bot.async_client.send_message(chat_id=event.chat_id, text=f"You said: {event.text}")
bot.run_async()
You can pass optional polling options to run() and run_async(): timeout (default 30), limit (default 100), allowed_updates (list of update types, or None for all), and on_error (callback for polling-loop errors, e.g. bot.run(on_error=logger.exception)).
Error Handling
from shingram import Bot, TelegramAPIError
try:
bot.send_message(chat_id=123, text="Test")
except TelegramAPIError as e:
print(f"Telegram API error: {e}")
print(f"Error code: {e.error_code}")
print(f"Description: {e.description}")
Examples
See the examples/ directory in the repo. You can find plenty of examples there: sync (e.g. echo_bot.py, inline_bot.py, keyboard_bot.py, webhook_flask.py, webhook_fastapi.py) and async (e.g. echo_bot_async.py, inline_bot_async.py, keyboard_bot_async.py). Set your bot token in the file and run it.
License
MIT License - see LICENSE for details.
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 shingram-0.3.0.tar.gz.
File metadata
- Download URL: shingram-0.3.0.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5cab873871fb88bf1cda53900a3389db74f4554dfac5dc235e57f7059d2811b
|
|
| MD5 |
5c97aab8632a01fd326f9c46831c1955
|
|
| BLAKE2b-256 |
2f1c42e9e465990e1e4c234f0976ce2aab3f61f2f98652934b22e821c79971c3
|
File details
Details for the file shingram-0.3.0-py3-none-any.whl.
File metadata
- Download URL: shingram-0.3.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
571326c0c4d7772ac48f54a159c0a67d14de619a20b54e01349b2d5cf0f8d8a0
|
|
| MD5 |
0cd3faa727a67c88755e9698179be17e
|
|
| BLAKE2b-256 |
f7f11671420598e59b9fbc4f8eec8b40acff2d38e48a81341116b03e644e3235
|