https://github.com/gleb-chipiga/aiotgbot
Asynchronous library for Telegram bot API
https://github.com/gleb-chipiga/aiotgbot
asyncio python telegram
Last synced: 4 months ago
JSON representation
Asynchronous library for Telegram bot API
- Host: GitHub
- URL: https://github.com/gleb-chipiga/aiotgbot
- Owner: gleb-chipiga
- License: mit
- Created: 2020-10-12T14:11:19.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2025-11-30T13:08:32.000Z (7 months ago)
- Last Synced: 2025-12-22T01:44:11.237Z (6 months ago)
- Topics: asyncio, python, telegram
- Language: Python
- Homepage:
- Size: 1.14 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Asynchronous library for Telegram bot API
[](https://pypi.org/project/aiotgbot)
[](https://github.com/gleb-chipiga/aiotgbot/blob/master/LICENSE)
[](https://pypistats.org/packages/aiotgbot)
## Key Features
- Asyncio and [aiohttp](https://github.com/aio-libs/aiohttp) based
- All [Telegram Bot API](https://core.telegram.org/bots/api) types and methods supported
- Tracks Telegram Bot API 7.2 (released March 31, 2024)
- Bot API rate limit support
- Both long polling and webhooks supported
- Fully type annotated ([PEP 484](https://www.python.org/dev/peps/pep-0484/))
## Installation
aiotgbot is available on PyPI. Use pip to install it:
```bash
pip install aiotgbot
```
## Requirements
- Python 3.11–3.14
- [aiohttp](https://github.com/aio-libs/aiohttp)
- [aiojobs](https://github.com/aio-libs/aiojobs)
- [msgspec](https://github.com/jcrist/msgspec)
- [tenacity](https://github.com/jd/tenacity)
- [frozenlist](https://github.com/aio-libs/frozenlist)
- [aiofreqlimit](https://github.com/gleb-chipiga/aiofreqlimit)
- [yarl](https://github.com/aio-libs/yarl)
## Using aiotgbot
```python
from typing import AsyncIterator
from aiotgbot import (
Bot,
BotUpdate,
BotUpdateKey,
HandlerTable,
PollBot,
PrivateChatFilter,
Runner,
)
from aiotgbot.storage_memory import MemoryStorage
handlers = HandlerTable()
@handlers.message(filters=[PrivateChatFilter()])
async def reply_private_message(bot: Bot, update: BotUpdate) -> None:
assert update.message is not None
name = (
f"{update.message.chat.first_name} "
f"{update.message.chat.last_name}"
)
update["greeting_count"] = update.get("greeting_count", 0) + 1
await bot.send_message(update.message.chat.id, f"Hello, {name}!")
async def run_context(runner: Runner) -> AsyncIterator[None]:
storage = MemoryStorage()
await storage.connect()
handlers.freeze()
bot = PollBot(runner["token"], handlers, storage)
await bot.start()
yield
await bot.stop()
await storage.close()
def main() -> None:
runner = Runner(run_context)
runner["token"] = "some:token"
runner.run()
if __name__ == "__main__":
main()
```
## Upgrading to 0.18.0
**New features:**
- **BotUpdateKey** – a dedicated typed key object for items stored on `BotUpdate`.
- `BotUpdate` exposes `get_typed(key)`, `set_typed(key, value)`, and `del_typed(key)` helpers for working with `BotUpdateKey` instances.
- Each `BotUpdateKey` enforces runtime type checking via `isinstance()` so handlers only see the expected payload.
`BotUpdate` remains a regular mutable mapping so filters and handlers can stash arbitrary helper objects between each other. To keep data structured, use `BotUpdateKey` which enforces types per slot:
```python
from dataclasses import dataclass
from aiotgbot import BotUpdateKey
@dataclass
class Session:
trace_id: str
retries: int
session_key = BotUpdateKey("session", Session)
async def my_handler(bot: Bot, update: BotUpdate) -> None:
if session_key.name not in update:
update.set_typed(session_key, Session(trace_id="abc", retries=0))
session = update.get_typed(session_key)
...
```
## Development
We use [Prek](https://github.com/DetachHead/prek) as a drop-in `pre-commit` replacement backed by `uv` so hook environments resolve quickly and reproducibly. Install it once and run the configured Ruff, `mypy --strict`, and Basedpyright checks via:
```bash
uv tool install prek
prek install
prek run --all-files
```
`prek run` reads `.pre-commit-config.yaml`, so you can still target a subset of hooks or files during local development.
`mise.toml` at the repo root mirrors the common workflows, so you can rely on [mise](https://mise.jdx.dev/) instead of remembering the raw commands. Trust the config once via `mise trust mise.toml` and then run, for example:
```bash
mise run lint
mise run mypy
mise run basedpyright
mise run test
```