PyMax

repository·main·Indexed 42 days ago

https://github.com/maxapiteam/pymax

An asynchronous Python library for interacting with the unofficial internal Max API. PyMax version 2.4.1 allows developers to automate accounts, listen to events, and manage chats, users, files, and sessions via TCP (Client) or WebSocket (WebClient). It supports SMS-based and QR-code authorization, providing tools for profile management, chat folder organization, and custom request dispatching via ClientRouter.

Tokens
35.9K
Snippets
105
Records
196
Agent score
53%

What's inside PyMax

  1. Overview of PyMax

    main

    PyMax is an asynchronous Python library designed for interacting with the Max API. It provides tools to:

    • Authenticate with Max accounts.
    • Receive events.
    • Send messages.
    • Manage chats and files.
    • Work with Max domain types.

    Warning: PyMax uses an unofficial internal Max API. The API may change without warning, and use of this library is at your own responsibility.

  2. Understand PyMax data types

    main

    PyMax uses Pydantic models to represent Max data, such as messages, chats, contacts, profiles, folders, attachments, and sync state. In most workflows, you do not instantiate these manually; instead, the client returns these pre-constructed objects.

    Using these types allows for clear, type-hinted code, enabling you to use isinstance checks to handle specific attachment types or data structures.

    from pymax import Client, Message
    from pymax.types.domain import PhotoAttachment
    
    async def handler(message: Message, client: Client) -> None:
        for attach in message.attaches:
            if isinstance(attach, PhotoAttachment):
                print(attach.photo_id, attach.base_url)
  3. Configure Reconnect behavior

    main

    By default, reconnect is enabled. If a network error occurs, the client closes the current runtime, waits for reconnect_delay seconds, recreates the connection/app, and re-runs start/login.

    • Routers: Your root Router is preserved during reconnect; the new App instance receives the same router.
    • Lifecycle: The on_start hook is called after every successful reconnect.
    • Token Revocation: If the server revokes the login token, ExtraConfig(relogin=True) (the default) will automatically trigger a new authorization flow.
    • Disconnect Hook: You can register an on_disconnect handler to react to connection losses.
    @client.on_disconnect()
    async def disconnected(exc: Exception, reconnect: bool, delay: float) -> None:
        print("connection lost:", exc, reconnect, delay)
  4. Handle Noneable fields in PyMax types

    main

    Because the Max API does not always send a complete object (for example, in edit, delete, or service events), many fields in PyMax models are defined as None-able.

    Best Practice: Always check if a field is not None before attempting to use it to avoid errors.

  5. Use the Client for long-running connections and mobile API access

    main

    The Client is a TCP client featuring SMS authorization. It is the primary interface for maintaining long-running connections, handling events, and interacting with the Max mobile API.

    When using Client.authorize_qr_login, you must configure the device_type in ExtraConfig to either ANDROID or IOS. The DESKTOP device type does not support QR code login confirmation.

    from pymax import Client, ExtraConfig
    
    # Example configuration for QR login support
    config = ExtraConfig(device_type="ANDROID")
    client = Client(config=config)
  6. Choose between Client and WebClient

    main

    PyMax provides two primary client types that share a common set of high-level methods but differ in their transport layer and authorization mechanisms:

    Client

    • Transport: TCP
    • Authorization: SMS-based
    • Device Types: Supports ANDROID, IOS, and DESKTOP via the device_type parameter.
    • QR Login: To use Client.authorize_qr_login for confirming QR code logins, you must use ANDROID or IOS. The DESKTOP device type does not support this method.

    WebClient

    • Transport: WebSocket
    • Authorization: QR-based
    • Device Type: Always uses DeviceType.WEB in standard configurations. Note that setting ExtraConfig.device_type does not affect the WebClient behavior.
  7. Use VersionCatalog to map Android client versions to build numbers and fingerprints

    main

    The VersionCatalog class in pymax.versions is used to associate a specific Android client version with its corresponding build number and fingerprint. This mapping is required by the Client to identify and interact with specific client versions correctly.

    If you attempt to look up a version that is not present in the catalog, a VersionNotFoundError will be raised.

  8. Use ClientRouter to organize handlers

    main

    Instead of registering all handlers directly on the client, you can use a ClientRouter to group logic. Handlers in a router always receive the event and the client as arguments: (event, client). You can apply filters to handlers to control when they trigger.

    from pymax import Client, ClientRouter, Message
    
    router = ClientRouter()
    
    # A filter function
    def is_start(message: Message) -> bool:
        return message.text == "/start"
    
    # Registering a handler with a filter
    @router.on_message(is_start)
    async def start(message: Message, client: Client) -> None:
        await message.answer("Готово")
    
    client = Client(phone="+79990000000", work_dir="cache")
    client.include_router(router)
  9. Difference between bound and unbound objects

    main

    PyMax distinguishes between objects that are linked to a client and those that are just raw data.

    • Bound Objects: Messages and chats received via Client or WebClient are automatically bound to the client. This allows you to call action methods directly on the object.
    • Unbound Objects: If you create a Message or Chat manually via Pydantic, it is just a data container. It does not know which client to use for actions, and calling action methods on it will result in an error.

    Recommendation: Do not manually bind objects. Instead, obtain them from handlers, get_chat(), fetch_chats(), or fetch_history().

    # Bound objects (from Client/WebClient) allow direct actions:
    await message.answer("ok")
    await chat.answer("ok")
  10. Understand the difference between Router, ClientRouter, and WebRouter

    main

    There is only one actual class: Router.

    ClientRouter and WebRouter are simply type aliases used for type hinting:

    • ClientRouter is Router[Client]
    • WebRouter is Router[WebClient]

    Router Hierarchy:

    • The root router is located inside the client instance.
    • Use include_router() to add pluggable routers to the root.
    • Use router.include_router(child) to create nested router structures.
  11. Understand ClientRouter and WebRouter type aliases

    main

    PyMax uses a single Router class, but provides two type aliases to improve IDE type hinting for the second argument (client) in your handlers:

    • ClientRouter: An alias for Router[Client]. Use this when working with the standard Client.
    • WebRouter: An alias for Router[WebClient]. Use this when working with WebClient.

    Using these aliases ensures that your IDE correctly identifies the methods available on the client object passed to your handlers.

    from pymax import Client, ClientRouter, Message
    
    router = ClientRouter()
    
    @router.on_message()
    async def handle(message: Message, client: Client) -> None:
        await message.answer("ok")