python-telegram

repository·main·Indexed 20 days ago

https://github.com/alexander-akhmetov/python-telegram

A Python API for the Telegram Database Library (tdlib) that enables developers to build custom Telegram clients using the MTProto protocol. It supports both user accounts via phone number and bot accounts via bot token. The library provides a high-level interface for common tasks, a non-blocking login flow for web applications, proxy support, and the ability to call arbitrary tdlib methods via call_method. It requires Python 3.10 or higher and is supported on Linux and macOS.

Tokens
5.1K
Snippets
21
Records
22
Agent score
72%

What's inside python-telegram

  1. Manage client lifecycle with idle and stop

    main

    tg.idle()

    Blocks the script and waits for an exit signal. By default, it listens for SIGINT, SIGTERM, and SIGABRT. You can customize these via the stop_signals parameter. When a signal is received, idle() automatically calls stop() for you.

    tg.stop()

    You must call stop() to shut down python-telegram and tdlib cleanly. It invokes the close method of tdlib and waits for it to finish. If you are using idle(), you can trigger a shutdown by calling stop() from a different thread.

  2. How to use the Telegram client

    main

    To use the library, you must first register an application at my.telegram.org to obtain an api_id and api_hash.

    Key Concepts:

    • Authentication: Sign in using a phone number or a bot_token (to act as a bot).
    • Database: You must provide a database_encryption_key and a files_directory.
    • Chat Availability: A chat must exist in the tdlib database before you can interact with it (e.g., sending messages). Use get_chats(limit=...) to load chats into the local database.
    • Asynchronicity: All library calls return an AsyncResult object. You must call the .wait() method on this object to retrieve the actual result.
    • Lifecycle: Always call tg.stop() at the end of your script to clean up.
    from telegram.client import Telegram
    from telegram.text import Spoiler
    
    tg = Telegram(
        api_id=123456,
        api_hash="api_hash",
        phone="+31611111111",  # or use 'bot_token'
        database_encryption_key="changekey123",
        files_directory="/tmp/.tdlib_files/",
    )
    tg.login()
    
    # Load chats into the database first
    result = tg.get_chats(limit=100)
    result.wait()
    
    # Send a message
    chat_id = 123456789
    result = tg.send_message(chat_id, Spoiler("Hello world!"))
    result.wait()
    print(result.update)
    
    tg.stop()
  3. Configure a proxy with the Telegram class

    main

    To use a proxy with tdlib via the python-telegram library, you must define a proxy type dictionary and pass the server, port, and type parameters to the Telegram class constructor.

    Supported proxy types (via the @type key) are:

    • proxyTypeMtproto
    • proxyTypeSocks5
    • proxyTypeHttp
    from telegram.client import Telegram
    
    proxy_type = {
        '@type': 'proxyTypeMtproto',  # or 'proxyTypeSocks5', or 'proxyTypeHttp'
    }
    proxy_port = 1234
    proxy_server = 'localhost'
    
    tg = Telegram(
        api_id=123456,
        api_hash='api_hash',
        phone='+31611111111',
        database_encryption_key='changeme1234',
        proxy_server=proxy_server,
        proxy_port=proxy_port,
        proxy_type=proxy_type,
    )
  4. Perform non-blocking login

    main

    By default, python-telegram uses a blocking login method that prompts for credentials in the terminal. For environments without a terminal (like web applications), use login(blocking=False).

    This method returns the current AuthorizationState instead of prompting. You must inspect the returned state, provide the required credentials using the appropriate method, and then call login(blocking=False) again to continue the process. The process is complete when login returns AuthorizationState.READY or when tg.authorization_state equals AuthorizationState.READY.

    from telegram.client import Telegram, AuthorizationState
    
    tg = Telegram(
        api_id=123456,
        api_hash='api_hash',
        phone='+31611111111',
        database_encryption_key='changeme1234',
    )
    
    # Start non-blocking login
    state = tg.login(blocking=False)
    
    if state == AuthorizationState.WAIT_CODE:
        tg.send_code('some-code')
        state = tg.login(blocking=False)  # Continue process
    
    if state == AuthorizationState.WAIT_PASSWORD:
        tg.send_password('secret-password')
        state = tg.login(blocking=False)  # Continue process
    
    # When state is AuthorizationState.READY, you are logged in.
  5. Initialize a Telegram client

    main

    To use the library, you need an api_id and an api_hash from my.telegram.org.

    Initialize the Telegram client using one of two methods:

    • User Account: Pass phone and database_encryption_key.
    • Bot Account: Pass bot_token instead of phone.

    By default, tdlib stores the message database and downloaded files in a temporary directory: /tmp/.tdlib_files/<md5 of your phone number or bot token>/. To persist the database between runs, provide a custom path using the files_directory parameter.

    from telegram.client import Telegram
    
    tg = Telegram(
        api_id=123456,
        api_hash='api_hash',
        phone='+31611111111',
        database_encryption_key='changeme1234',
        # files_directory='/path/to/persistent/storage' # Optional
    )
  6. Configure the tdlib library path

    main

    While python-telegram includes a precompiled tdlib binary for Linux and macOS, it may not work on all systems due to dynamic linking requirements. For better reliability, you can build tdlib from source and install it system-wide using make install.

    If tdlib is not installed system-wide, you must provide the path to the compiled library file (libtdjson.so on Linux or libtdjson.dylib on macOS) when initializing the Telegram client via the library_path parameter.

    from telegram.client import Telegram
    
    tg = Telegram(
        # ...
        library_path='/usr/local/lib/libtdjson.so',
    )
  7. Authenticate with the Telegram client

    main

    The login() method initiates the authentication process. It is a prerequisite for all other API calls.

    Depending on the blocking argument, login() behaves differently:

    • blocking=True (default): The method will attempt to handle the entire login flow, including prompting for codes/passwords via standard input (stdin).
    • blocking=False: The method returns the current AuthorizationState. You must then call specific methods (like send_code, send_password, etc.) to progress the state and call login(blocking=False) again until the state reaches AuthorizationState.READY.

    Common AuthorizationState values returned:

    • WAIT_CODE: Requires a Telegram code.
    • WAIT_PASSWORD: Requires a 2FA password.
    • WAIT_EMAIL_CODE: Requires an email verification code.
    • READY: Authentication successful.
    # Blocking login (easiest for CLI scripts)
    state = client.login(blocking=True)
    if state == AuthorizationState.READY:
        print("Logged in!")
    
    # Non-blocking login (for integration into GUIs or web apps)
    state = client.login(blocking=False)
    if state == AuthorizationState.WAIT_CODE:
        # ... get code from user ...
        client.send_code(user_provided_code)
        # then call login again
        client.login(blocking=False)
  8. Build a simple echo-bot

    main

    To create a bot, register a message handler using add_message_handler(callback). The callback function receives an update dictionary.

    To process text messages, navigate the update dictionary structure: update['message']['content'].get('text', {}).

    Use tg.send_message(chat_id=..., text=...) to reply to users.

    from telegram.client import Telegram
    
    tg = Telegram(
        api_id=123456,
        api_hash='api_hash',
        phone='+31611111111',
        database_encryption_key='changeme1234',
    )
    tg.login()
    
    def new_message_handler(update):
        # Extract text content safely
        message_content = update['message']['content'].get('text', {})
        message_text = message_content.get('text', '').lower()
        is_outgoing = update['message']['is_outgoing']
    
        # Logic: if incoming message is 'ping', reply 'pong'
        if not is_outgoing and message_text == 'ping':
            chat_id = update['message']['chat_id']
            print(f'Ping has been received from {chat_id}')
            tg.send_message(
                chat_id=chat_id,
                text='pong',
            )
    
    tg.add_message_handler(new_message_handler)
    tg.idle()
  9. Run python-telegram using Docker

    main

    A Docker image is available for running the library. You can use it to run examples or scripts by mounting a local directory and passing the required Telegram credentials as command-line arguments.

    docker run -i -t --rm \
                -v /tmp/docker-python-telegram/:/tmp/ \
                akhmetov/python-telegram \
                python3 /app/examples/send_message.py $API_ID $API_HASH $PHONE $CHAT_ID $TEXT