diff --git a/docs/source/pyrogram/index.rst b/docs/source/pyrogram/index.rst index d1084a29..6b2bc5dd 100644 --- a/docs/source/pyrogram/index.rst +++ b/docs/source/pyrogram/index.rst @@ -1,11 +1,10 @@ Pyrogram ======== -In this section you can find a detailed description of the Pyrogram API. +In this section you can find a detailed description of the Pyrogram package and its high-level API. -:class:`Client ` is the main class you have to deal with. -You will notice that methods are named after the well established `Telegram Bot API`_ and that most of them accept -the same parameters as well, thus offering a familiar look to Bot developers. +:class:`Client ` is the main class. It exposes easy-to-use methods that are named +after the `Telegram Bot API`_ methods, thus offering a familiar look to Bot developers. .. toctree:: Client diff --git a/docs/source/resources/TextFormatting.rst b/docs/source/resources/TextFormatting.rst index ffec21b9..b822dd5f 100644 --- a/docs/source/resources/TextFormatting.rst +++ b/docs/source/resources/TextFormatting.rst @@ -9,7 +9,7 @@ Markdown Style -------------- To use this mode, pass :obj:`MARKDOWN ` or "markdown" in the *parse_mode* field when using -:obj:`send_message `. Use the following syntax in your message: +:obj:`send_message() `. Use the following syntax in your message: .. code:: @@ -31,7 +31,7 @@ HTML Style ---------- To use this mode, pass :obj:`HTML ` or "html" in the *parse_mode* field when using -:obj:`send_message `. The following tags are currently supported: +:obj:`send_message() `. The following tags are currently supported: .. code:: diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst index c13202c3..4ce86656 100644 --- a/docs/source/resources/UpdateHandling.rst +++ b/docs/source/resources/UpdateHandling.rst @@ -1,41 +1,118 @@ Update Handling =============== -Updates are events that happen in your Telegram account (incoming messages, new channel posts, user name changes, ...) -and can be handled by using a callback function, that is, a function called every time an ``Update`` is received from -Telegram. +Updates are handled by registering one or more callback functions with an Handler. +There are multiple Handlers to choose from, one for each kind of update. -To set an update handler simply call :meth:`set_update_handler ` -by passing the name of your defined callback function as argument *before* you start the Client. +Registering an Handler +---------------------- -Here's a complete example on how to set it up: +We shall examine the :obj:`MessageHandler `, which will be in charge for handling +:obj:`Message ` objects. + +The easiest and nicest way to register a MessageHandler is by decorating your function with the +:meth:`on_message() ` decorator. Here's a full example that prints out the content +of a message as soon as it arrives. .. code-block:: python from pyrogram import Client + app = Client("my_account") - def update_handler(client, update, users, chats): - print(update) - def main(): - client = Client(session_name="example") - client.set_update_handler(update_handler) + @app.on_message() + def my_handler(client, message): + print(message) - client.start() - client.idle() - if __name__ == "__main__": - main() + app.start() + app.idle() -The last line of the main function, :meth:`client.idle() `, is not strictly necessary but highly -recommended when using the update handler; it will block your script execution until you press ``CTRL+C`` and -automatically call the :meth:`stop ` method which stops the Client and gently close the underlying -connection. +Alternatively, if you prefer not to use decorators, there is an alternative way for registering Handlers. +This is useful, for example, if you want to keep your callback functions in a separate file. -Examples --------- +.. code-block:: python -- `Simple Echo `_ -- `Advanced Echo `_ -- `Advanced Echo 2 `_ + from pyrogram import Client, MessageHandler + + def my_handler(client, message): + print(message) + + app = Client("my_account") + + app.add_handler(MessageHandler(my_handler)) + + app.start() + app.idle() + +Using Filters +------------- + +For a finer grained control over what kind of messages will be allowed or not, you can use +:class:`Filters `. The next example will show you how to handler only messages +containing an :obj:`Audio ` object: + +.. code-block:: python + + from pyrogram import Filters + + @app.on_message(Filters.audio) + def my_handler(client, message): + print(message) + +or, without decorators: + +.. code-block:: python + + from pyrogram import Filters, Messagehandler + + def my_handler(client, message): + print(message) + + app.add_handler(MessageHandler(my_handler, Filters.audio)) + +Advanced Filters +---------------- + +Filters can also be used in a more advanced way by combining more filters together using bitwise operators: + +- Use ``~`` to invert a filter (behaves like the ``not`` operator). +- Use ``&`` and ``|`` to merge two filters (``and``, ``or`` operators respectively). + +Here are some examples: + +- Message is a **text** message **and** is **not edited**. + + .. code-block:: python + + @app.on_message(Filters.text & ~Filters.edited) + def my_handler(client, message): + print(message) + +- Message is a **sticker** **and** was sent in a **channel** or in a **private** chat. + + .. code-block:: python + + @app.on_message(Filters.sticker & (Filters.channel | Filters.private)) + def my_handler(client, message): + print(message) + +Some filters can also accept parameters, like :obj:`command ` or +:obj:`regex `: + +- Message is either a /start or /help **command**. + + .. code-block:: python + + @app.on_message(Filters.command(["start", "help"])) + def my_handler(client, message): + print(message) + +- Message is a **text** message matching the given regex pattern. + + .. code-block:: python + + @app.on_message(Filters.regex("pyrogram")) + def my_handler(client, message): + print(message) \ No newline at end of file diff --git a/docs/source/start/BasicUsage.rst b/docs/source/start/BasicUsage.rst index 3e04dee0..ea2f7005 100644 --- a/docs/source/start/BasicUsage.rst +++ b/docs/source/start/BasicUsage.rst @@ -9,9 +9,9 @@ Basic Usage Simple API Access ----------------- -The easiest way to interact with the API is via the :class:`Client ` class which exposes bot-like_ -methods. The purpose of this Client class is to make it even simpler to work with Telegram's API by abstracting the -raw functions listed in the API scheme. +The easiest way to interact with the Telegram API is via the :class:`Client ` class, +which exposes bot-like_ methods. The purpose of this Client class is to make it even simpler to work with the +API by abstracting the raw functions listed in the scheme. The result is a much cleaner interface that allows you to: @@ -25,10 +25,13 @@ The result is a much cleaner interface that allows you to: .. code-block:: python - client.send_message( - chat_id="me", - text="Hi there! I'm using Pyrogram" - ) + client.send_message("me", "Hi there! I'm using Pyrogram") + +- Upload a photo (with caption): + + .. code-block:: python + + client.send_photo("me", "/home/dan/perla.jpg", "Cute!") .. seealso:: For a complete list of the available methods have a look at the :class:`Client ` class. @@ -39,7 +42,7 @@ Using Raw Functions If you want **complete**, low-level access to the Telegram API you have to use the raw :mod:`functions ` and :mod:`types ` exposed by the ``pyrogram.api`` -package and call any Telegram API method you wish using the :meth:`send ` method provided by +package and call any Telegram API method you wish using the :meth:`send() ` method provided by the Client class. Here some examples: diff --git a/docs/source/start/ProjectSetup.rst b/docs/source/start/ProjectSetup.rst index 323e6a0c..ca6f388e 100644 --- a/docs/source/start/ProjectSetup.rst +++ b/docs/source/start/ProjectSetup.rst @@ -8,7 +8,7 @@ API Keys -------- The very first step requires you to obtain a valid Telegram API key. -If you already have one you can skip this, otherwise: +If you already have one you can skip this step, otherwise: #. Visit https://my.telegram.org/apps and log in with your Telegram Account. #. Fill out the form to register a new Telegram application. @@ -31,8 +31,8 @@ There are two ways to configure a Pyrogram application project, and you can choo api_id = 12345 api_hash = 0123456789abcdef0123456789abcdef -- Alternatively, you can pass your API key to Pyrogram by simply using the *api_key* parameter of the Client class. - This way you can have full control on how to store and load your credentials: +- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* + parameters of the Client class. This way you can have full control on how to store and load your credentials: .. code-block:: python @@ -40,25 +40,26 @@ There are two ways to configure a Pyrogram application project, and you can choo client = Client( session_name="example", - api_key=(12345, "0123456789abcdef0123456789abcdef") + api_id=12345 + api_hash="0123456789abcdef0123456789abcdef" ) -.. note:: The examples below will assume you have created a *config.ini* file, thus they won't show the *api_key* - parameter usage in the :class:`Client ` class. +.. note:: The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id* + and *api_hash* parameters usage. -Authorization -------------- +User Authorization +------------------ -Telegram requires that users be authorized in order to use the API. +In order to use the API, Telegram requires that Users be authorized via their phone numbers. Pyrogram automatically manages this access, all you need to do is create an instance of the :class:`Client ` class by passing to it a ```` of your choice -and call the :meth:`start ` method: +(e.g.: "my_account") and call the :meth:`start ` method: .. code-block:: python from pyrogram import Client - client = Client(session_name="example") + client = Client("my_account") client.start() This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_) @@ -70,15 +71,26 @@ and the **phone code** you will receive: Is "+39**********" correct? (y/n): y Enter phone code: 32768 -After successfully authorizing yourself, a new file called ``example.session`` will be created allowing -Pyrogram executing API calls with your identity. +After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing +Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app, +and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number. .. important:: Your *.session file(s) must be kept secret. -.. note:: +Bot Authorization +----------------- - The authorization process is executed only once. - However, the code above is always required; as long as a valid session file exists, - Pyrogram will use that and won't ask you to enter your phone number again when you restart your script. +Being written entirely from the ground up, Pyrogram is also able to authorize Bots. +This means that you can use Pyrogram to execute API calls with a Bot identity. +Instead of phone numbers, Bots are authorized via their tokens which are created by BotFather_: -.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes \ No newline at end of file +.. code-block:: python + + from pyrogram import Client + + client = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") + client.start() + + +.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes +.. _BotFather: https://t.me/botfather \ No newline at end of file diff --git a/docs/source/start/QuickInstallation.rst b/docs/source/start/QuickInstallation.rst index f3f568e7..4969fe24 100644 --- a/docs/source/start/QuickInstallation.rst +++ b/docs/source/start/QuickInstallation.rst @@ -7,6 +7,12 @@ The most straightforward and recommended way to install or upgrade Pyrogram is b $ pip3 install --upgrade pyrogram +or, with TgCrypto_ (recommended): + +.. code-block:: bash + + $ pip3 install --upgrade pyrogram[tgcrypto] + Bleeding Edge ------------- diff --git a/pyrogram/client/chat_action.py b/pyrogram/client/chat_action.py index d2a8c35a..95bffb8e 100644 --- a/pyrogram/client/chat_action.py +++ b/pyrogram/client/chat_action.py @@ -21,7 +21,7 @@ from pyrogram.api import types class ChatAction: """This class provides a convenient access to all Chat Actions available. - It is intended to be used with :obj:`pyrogram.Client.send_chat_action`. + Chat Actions are intended to be used with :meth:`send_chat_action() `. """ CANCEL = types.SendMessageCancelAction diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index ac2ecf67..9f6966ec 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -29,8 +29,8 @@ def build(name: str, func: callable, **kwargs) -> type: class Filters: - """This class provides access to all the Filters available in Pyrogram. - It is intended to be used when adding an handler.""" + """This class provides access to all Filters available in Pyrogram. + Filters are intended to be used with the :obj:`MessageHandler `.""" text = build("Text", lambda _, m: bool(m.text and not m.text.startswith("/"))) """Filter text messages.""" @@ -48,34 +48,34 @@ class Filters: """Filter edited messages.""" audio = build("Audio", lambda _, m: bool(m.audio)) - """Filter messages that contain an :obj:`Audio `.""" + """Filter messages that contain :obj:`Audio ` objects.""" document = build("Document", lambda _, m: bool(m.document)) - """Filter messages that contain a :obj:`Document `.""" + """Filter messages that contain :obj:`Document ` objects.""" photo = build("Photo", lambda _, m: bool(m.photo)) - """Filter messages that contain a :obj:`Photo `.""" + """Filter messages that contain :obj:`Photo ` objects.""" sticker = build("Sticker", lambda _, m: bool(m.sticker)) - """Filter messages that contain a :obj:`Sticker `.""" + """Filter messages that contain :obj:`Sticker ` objects.""" video = build("Video", lambda _, m: bool(m.video)) - """Filter messages that contain a :obj:`Video `.""" + """Filter messages that contain :obj:`Video ` objects.""" voice = build("Voice", lambda _, m: bool(m.voice)) - """Filter messages that contain a :obj:`Voice ` note.""" + """Filter messages that contain :obj:`Voice ` note objects.""" video_note = build("Voice", lambda _, m: bool(m.video_note)) - """Filter messages that contain a :obj:`VideoNote `.""" + """Filter messages that contain :obj:`VideoNote ` objects.""" contact = build("Contact", lambda _, m: bool(m.contact)) - """Filter messages that contain a :obj:`Contact `.""" + """Filter messages that contain :obj:`Contact ` objects.""" location = build("Location", lambda _, m: bool(m.location)) - """Filter messages that contain a :obj:`Location `.""" + """Filter messages that contain :obj:`Location ` objects.""" venue = build("Venue", lambda _, m: bool(m.venue)) - """Filter messages that contain a :obj:`Venue `.""" + """Filter messages that contain :obj:`Venue ` objects.""" private = build("Private", lambda _, m: bool(m.chat.type == "private")) """Filter messages sent in private chats.""" @@ -166,6 +166,24 @@ class Filters: ) ) + service = build( + "Service", + lambda _, m: bool( + _.new_chat_members(m) + or _.left_chat_member(m) + or _.new_chat_title(m) + or _.new_chat_photo(m) + or _.delete_chat_photo(m) + or _.group_chat_created(m) + or _.supergroup_chat_created(m) + or _.channel_chat_created(m) + or _.migrate_to_chat_id(m) + or _.migrate_from_chat_id(m) + or _.pinned_m(m) + ) + ) + """Filter all service messages""" + new_chat_members = build("NewChatMembers", lambda _, m: bool(m.new_chat_members)) """Filter service messages for new chat members.""" @@ -198,21 +216,3 @@ class Filters: pinned_message = build("PinnedMessage", lambda _, m: bool(m.pinned_message)) """Filter service messages for pinned messages.""" - - service = build( - "Service", - lambda _, m: bool( - _.new_chat_members(m) - or _.left_chat_member(m) - or _.new_chat_title(m) - or _.new_chat_photo(m) - or _.delete_chat_photo(m) - or _.group_chat_created(m) - or _.supergroup_chat_created(m) - or _.channel_chat_created(m) - or _.migrate_to_chat_id(m) - or _.migrate_from_chat_id(m) - or _.pinned_m(m) - ) - ) - """Filter all service messages""" diff --git a/pyrogram/client/input_phone_contact.py b/pyrogram/client/input_phone_contact.py index 5d5f9f96..1ca8bf4c 100644 --- a/pyrogram/client/input_phone_contact.py +++ b/pyrogram/client/input_phone_contact.py @@ -22,16 +22,16 @@ from pyrogram.session.internals import MsgId class InputPhoneContact: """This object represents a Phone Contact to be added in your Telegram address book. - It is intended to be used with :meth:`pyrogram.Client.add_contacts` + It is intended to be used with :meth:`add_contacts() ` Args: - phone (:obj:`str`): + phone (``str``): Contact's phone number - first_name (:obj:`str`): + first_name (``str``): Contact's first name - last_name (:obj:`str`, optional): + last_name (``str``, optional): Contact's last name """ diff --git a/pyrogram/client/parse_mode.py b/pyrogram/client/parse_mode.py index 668bb9c8..817bccb0 100644 --- a/pyrogram/client/parse_mode.py +++ b/pyrogram/client/parse_mode.py @@ -18,8 +18,8 @@ class ParseMode: - """This class provides a convenient access to parse modes. - It is intended to be used with any method that accepts the optional argument **parse_mode** + """This class provides a convenient access to Parse Modes. + Parse Modes are intended to be used with any method that accepts the optional argument **parse_mode**. """ HTML = "html"