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. One Event shape for all update types, one router for handlers; sync and async share the same core (normalize, router, error handling). New Telegram methods work without changing the library.
Features
- Zero hardcoding — All Telegram API methods work without library updates. Call
bot.send_message(...),bot.send_photo(...), or any method; names are converted fromsnake_casetocamelCaseautomatically. - Single Event type — Every update (message, callback, inline, etc.) is normalized to one
Event; the full payload stays inevent.raw. - Full update coverage — Commands, messages, edits, channel posts, inline queries, callbacks, joins, polls, reactions, business, webhooks.
- Sync and async — Use
bot.run()with sync handlers orbot.run_async()with async handlers; same router and Event, shared core. - Long polling — Offset and timeouts handled. Optional
timeout,limit,allowed_updates, andon_erroronrun()/run_async(). Webhook examples with Flask and FastAPI.
Installation
pip install shingram
Documentation
Full documentation is available at: https://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.2.0.tar.gz.
File metadata
- Download URL: shingram-0.2.0.tar.gz
- Upload date:
- Size: 15.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e476e3e9bb4449474da9ef3f284a8aa4baa4ed34c0a3112220e79cb71109745
|
|
| MD5 |
6511f60976da59386fcd128083a88746
|
|
| BLAKE2b-256 |
c7255d210b0a54b9b8d65425767ae8a564f8d7842fe5f31e987aa597f9d0f405
|
File details
Details for the file shingram-0.2.0-py3-none-any.whl.
File metadata
- Download URL: shingram-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.6 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 |
793abf7d71b9b0dc3dbb44ad12840feaced5ff66ae08d412fc3fd174fb5ef136
|
|
| MD5 |
26e0205c06c2022ea59bd088ea688219
|
|
| BLAKE2b-256 |
d35b2eba3b32f2987146fe13945cd764fe8f8e17f10853b7a84ad8ece2e1ef1e
|