aiotdlib - Python asyncio Telegram client based on TDLib

[!WARNING]
This library is still in development, so any updates before version 1.0.0 may include breaking changes. Please be cautious and pin the library version when using it. If you wish to update, I recommend reviewing the Git commit history.
This wrapper is actual
for TDLib v1.8.46
This package includes prebuilt TDLib binaries for macOS (arm64) and Debian (amd64).
You can use your own binary by passing library_path argument to Client class constructor. Make sure it's built
from this commit. Compatibility with
other versions of library is not guaranteed.
Features
- All types and functions are generated automatically
from tl schema
- All types and functions come with validation and good IDE type hinting (thanks
to Pydantic)
- A set of high-level API methods which makes work with tdlib much simpler
Requirements
- Python 3.9+
- Get your api_id and api_hash. Read more
in Telegram docs
Installation
PyPI
pip install aiotdlib
or if you use Poetry
poetry add aiotdlib
Examples
Base example
import asyncio
import logging
from aiotdlib import Client, ClientSettings
API_ID = 123456
API_HASH = ""
PHONE_NUMBER = ""
async def main():
client = Client(
settings=ClientSettings(
api_id=API_ID,
api_hash=API_HASH,
phone_number=PHONE_NUMBER
)
)
async with client:
me = await client.api.get_me()
logging.info(f"Successfully logged in as {me.model_dump_json()}")
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Any parameter of Client class could be also set via environment variables with prefix AIOTDLIB_*.
import asyncio
import logging
from aiotdlib import Client
async def main():
async with Client() as client:
me = await client.api.get_me()
logging.info(f"Successfully logged in as {me.model_dump_json()}")
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
and run it like this:
export AIOTDLIB_API_ID=123456
export AIOTDLIB_API_HASH=<my_api_hash>
export AIOTDLIB_BOT_TOKEN=<my_bot_token>
python main.py
Events handlers
import asyncio
import logging
from aiotdlib import Client, ClientSettings
from aiotdlib.api import API, BaseObject, UpdateNewMessage
API_ID = 123456
API_HASH = ""
PHONE_NUMBER = ""
async def on_update_new_message(client: Client, update: UpdateNewMessage):
chat_id = update.message.chat_id
chat = await client.api.get_chat(chat_id)
logging.info(f'Message received in chat {chat.title}')
async def any_event_handler(client: Client, update: BaseObject):
logging.info(f'Event of type {update.ID} received')
async def main():
client = Client(
settings=ClientSettings(
api_id=API_ID,
api_hash=API_HASH,
phone_number=PHONE_NUMBER
)
)
client.add_event_handler(on_update_new_message, update_type=API.Types.UPDATE_NEW_MESSAGE)
client.add_event_handler(any_event_handler, update_type=API.Types.ANY)
async with client:
await client.idle()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Bot command handler
import logging
from aiotdlib import Client, ClientSettings
from aiotdlib.api import UpdateNewMessage
API_ID = 123456
API_HASH = ""
BOT_TOKEN = ""
bot = Client(
settings=ClientSettings(
api_id=API_ID,
api_hash=API_HASH,
bot_token=BOT_TOKEN
)
)
@bot.bot_command_handler(command='help')
async def on_help_command(client: Client, update: UpdateNewMessage):
await client.send_text(update.message.chat_id, "I will help you!")
async def on_start_command(client: Client, update: UpdateNewMessage):
print(update.EXTRA)
await client.send_text(update.message.chat_id, "Have a good day! :)")
async def on_custom_command(client: Client, update: UpdateNewMessage):
print(update.EXTRA)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
bot.bot_command_handler(on_start_command, command='start')
bot.bot_command_handler(on_custom_command, command='custom')
bot.run()
Proxy
import asyncio
import logging
from aiotdlib import Client
from aiotdlib import ClientSettings
from aiotdlib import ClientProxySettings
from aiotdlib import ClientProxyType
API_ID = 123456
API_HASH = ""
PHONE_NUMBER = ""
async def main():
client = Client(
settings=ClientSettings(
api_id=API_ID,
api_hash=API_HASH,
phone_number=PHONE_NUMBER,
proxy_settings=ClientProxySettings(
host="10.0.0.1",
port=3333,
type=ClientProxyType.SOCKS5,
username="aiotdlib",
password="somepassword",
)
)
)
async with client:
await client.idle()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
Middlewares
import asyncio
import logging
from aiotdlib import Client, HandlerCallable, ClientSettings
from aiotdlib.api import API, BaseObject, UpdateNewMessage
API_ID = 12345
API_HASH = ""
PHONE_NUMBER = ""
async def some_pre_updates_work(event: BaseObject):
logging.info(f"Before call all update handlers for event {event.ID}")
async def some_post_updates_work(event: BaseObject):
logging.info(f"After call all update handlers for event {event.ID}")
async def my_middleware(client: Client, event: BaseObject, /, *, call_next: HandlerCallable):
await some_pre_updates_work(event)
try:
await call_next(client, event)
finally:
await some_post_updates_work(event)
async def on_update_new_message(client: Client, update: UpdateNewMessage):
logging.info('on_update_new_message handler called')
async def main():
client = Client(
settings=ClientSettings(
api_id=API_ID,
api_hash=API_HASH,
phone_number=PHONE_NUMBER
)
)
client.add_event_handler(on_update_new_message, update_type=API.Types.UPDATE_NEW_MESSAGE)
client.add_middleware(my_middleware)
async with client:
await client.idle()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
LICENSE
This project is licensed under the terms of the MIT license.