An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# Asynchronous library for Telegram bot API

[![Latest PyPI package version](https://badge.fury.io/py/aiotgbot.svg)](https://pypi.org/project/aiotgbot)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/gleb-chipiga/aiotgbot/blob/master/LICENSE)
[![Downloads](https://img.shields.io/pypi/dm/aiotgbot)](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
```