Clean up documentation pages

This commit is contained in:
Dan 2019-04-12 15:52:06 +02:00
parent 3ac62ba941
commit 05aed5e0e1
18 changed files with 263 additions and 246 deletions

View File

@ -25,6 +25,10 @@ sys.path.insert(0, os.path.abspath('../..'))
# Import after sys.path.insert() to avoid issues
from pyrogram import __version__
from pygments.styles.friendly import FriendlyStyle
FriendlyStyle.background_color = "#f3f2f1"
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@ -60,7 +64,7 @@ master_doc = 'index'
# General information about the project.
project = 'Pyrogram'
copyright = '2017-2018, Dan Tès'
copyright = '2017-2019, Dan Tès'
author = 'Dan Tès'
# The version info for the project you're documenting, acts as replacement for
@ -85,7 +89,7 @@ language = None
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'tango'
pygments_style = 'friendly'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False

View File

@ -9,6 +9,7 @@ Handlers
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
InlineQueryHandler
UserStatusHandler
DisconnectHandler
RawUpdateHandler
@ -22,6 +23,9 @@ Handlers
.. autoclass:: CallbackQueryHandler
:members:
.. autoclass:: InlineQueryHandler
:members:
.. autoclass:: UserStatusHandler
:members:

View File

@ -1,40 +1,102 @@
Advanced Usage
==============
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main Telegram
API with its raw functions and types.
Pyrogram's API, which consists of well documented convenience methods_ and facade types_, exists to provide a much
easier interface to the undocumented and often confusing Telegram API.
In this section, you'll be shown the alternative way of communicating with Telegram using Pyrogram: the main "raw"
Telegram API with its functions and types.
Telegram Raw API
----------------
If you can't find a high-level method for your needs or if you want complete, low-level access to the whole
Telegram API, you have to use the raw :mod:`functions <pyrogram.api.functions>` and :mod:`types <pyrogram.api.types>`
exposed by the ``pyrogram.api`` package and call any Telegram API method you wish using the
:meth:`send() <pyrogram.Client.send>` method provided by the Client class.
Telegram API, you have to use the raw :mod:`functions <pyrogram.api.functions>` and :mod:`types <pyrogram.api.types>`.
As already hinted, raw functions and types can be really confusing, mainly because people don't realize soon enough they
accept *only* the right types and that all required parameters must be filled in. This section will therefore explain
some pitfalls to take into consideration when working with the raw API.
.. hint::
Every available high-level method mentioned in the previous page is built on top of these raw functions.
Every available high-level methods in Pyrogram is built on top of these raw functions.
Nothing stops you from using the raw functions only, but they are rather complex and `plenty of them`_ are already
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API.
re-implemented by providing a much simpler and cleaner interface which is very similar to the Bot API (yet much more
powerful).
If you think a raw function should be wrapped and added as a high-level method, feel free to ask in our Community_!
Caveats
-------
Invoking Functions
^^^^^^^^^^^^^^^^^^
As hinted before, raw functions and types can be confusing, mainly because people don't realize they must accept
*exactly* the right values, but also because most of them don't have enough Python experience to fully grasp how things
work.
Unlike the methods_ found in Pyrogram's API, which can be called in the usual simple way, functions to be invoked from
the raw Telegram API have a different way of usage and are more complex.
This section will therefore explain some pitfalls to take into consideration when working with the raw API.
First of all, both `raw functions`_ and `raw types`_ live in their respective packages (and sub-packages):
``pyrogram.api.functions``, ``pyrogram.api.types``. They all exist as Python classes, meaning you need to create an
instance of each every time you need them and fill them in with the correct values using named arguments.
Next, to actually invoke the raw function you have to use the :meth:`send() <pyrogram.Client.send>` method provided by
the Client class and pass the function object you created.
Here's some examples:
- Update first name, last name and bio:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions
with Client("my_account") as app:
app.send(
functions.account.UpdateProfile(
first_name="Dan", last_name="Tès",
about="Bio written from Pyrogram"
)
)
- Disable links to your account when someone forwards your messages:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions, types
with Client("my_account") as app:
app.send(
functions.account.SetPrivacy(
key=types.PrivacyKeyForwards(),
rules=[types.InputPrivacyValueDisallowAll()]
)
)
- Invite users to your channel/supergroup:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions, types
with Client("my_account") as app:
app.send(
functions.channels.InviteToChannel(
channel=app.resolve_peer(123456789), # ID or Username
users=[ # The users you want to invite
app.resolve_peer(23456789), # By ID
app.resolve_peer("username"), # By username
app.resolve_peer("+393281234567"), # By phone number
]
)
)
Chat IDs
^^^^^^^^
The way Telegram works makes it impossible to directly send a message to a user or a chat by using their IDs only.
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed.
Instead, a pair of ``id`` and ``access_hash`` wrapped in a so called ``InputPeer`` is always needed. Pyrogram allows
sending messages with IDs only thanks to cached access hashes.
There are three different InputPeer types, one for each kind of Telegram entity.
Whenever an InputPeer is needed you must pass one of these:
@ -56,66 +118,19 @@ kind of ID.
For example, given the ID *123456789*, here's how Pyrogram can tell entities apart:
- ``+ID`` - User: *123456789*
- ``-ID`` - Chat: *-123456789*
- ``-100ID`` - Channel (and Supergroup): *-100123456789*
- ``+ID`` User: *123456789*
- ``-ID`` Chat: *-123456789*
- ``-100ID`` Channel (and Supergroup): *-100123456789*
So, every time you take a raw ID, make sure to translate it into the correct ID when you want to use it with an
high-level method.
Examples
--------
- Update first name, last name and bio:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions
with Client("my_account") as app:
app.send(
functions.account.UpdateProfile(
first_name="Dan", last_name="Tès",
about="Bio written from Pyrogram"
)
)
- Share your Last Seen time only with your contacts:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions, types
with Client("my_account") as app:
app.send(
functions.account.SetPrivacy(
key=types.InputPrivacyKeyStatusTimestamp(),
rules=[types.InputPrivacyValueAllowContacts()]
)
)
- Invite users to your channel/supergroup:
.. code-block:: python
from pyrogram import Client
from pyrogram.api import functions, types
with Client("my_account") as app:
app.send(
functions.channels.InviteToChannel(
channel=app.resolve_peer(123456789), # ID or Username
users=[ # The users you want to invite
app.resolve_peer(23456789), # By ID
app.resolve_peer("username"), # By username
app.resolve_peer("393281234567"), # By phone number
]
)
)
.. _methods: ../pyrogram/Client.html#messages
.. _types: ../pyrogram/Types.html
.. _plenty of them: ../pyrogram/Client.html#messages
.. _Raw Functions: Usage.html#using-raw-functions
.. _raw functions: ../pyrogram/functions
.. _raw types: ../pyrogram/types
.. _Community: https://t.me/PyrogramChat

View File

@ -1,13 +1,13 @@
Configuration File
==================
As already mentioned in previous sections, Pyrogram can also be configured by the use of an INI file.
As already mentioned in previous sections, Pyrogram can be configured by the use of an INI file.
This page explains how this file is structured in Pyrogram, how to use it and why.
Introduction
------------
The idea behind using a configuration file is to help keeping your code free of settings (private) information such as
The idea behind using a configuration file is to help keeping your code free of private settings information such as
the API Key and Proxy without having you to even deal with how to load such settings. The configuration file, usually
referred as ``config.ini`` file, is automatically loaded from the root of your working directory; all you need to do is
fill in the necessary parts.
@ -46,7 +46,7 @@ These are all the sections Pyrogram uses in its configuration file:
Pyrogram
^^^^^^^^
The ``[pyrogram]`` section contains your Telegram API credentials *api_id* and *api_hash*.
The ``[pyrogram]`` section contains your Telegram API credentials: *api_id* and *api_hash*.
.. code-block:: ini

View File

@ -1,19 +1,19 @@
Customize Sessions
==================
As you may probably know, Telegram allows Users (and Bots) having more than one session (authorizations) registered
As you may probably know, Telegram allows users (and bots) having more than one session (authorizations) registered
in the system at the same time.
Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official
app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram) and store some useful
information about the client who generated them.
app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram). They store some
useful information such as the client who's using them and from which country and IP address.
.. figure:: https://i.imgur.com/lzGPCdZ.png
:width: 70%
:align: center
A Pyrogram session running on Linux, Python 3.6.
**A Pyrogram session running on Linux, Python 3.6.**
That's how a session looks like on the Android app, showing the three main pieces of information.

View File

@ -4,7 +4,7 @@ Error Handling
Errors are inevitable when working with the API, and they must be correctly handled with ``try..except`` blocks.
There are many errors that Telegram could return, but they all fall in one of these categories
(which are in turn children of the :obj:`RPCError <pyrogram.RPCError>` superclass)
(which are in turn children of the :obj:`RPCError <pyrogram.RPCError>` superclass):
- :obj:`303 - See Other <pyrogram.errors.SeeOther>`
- :obj:`400 - Bad Request <pyrogram.errors.BadRequest>`

View File

@ -1,24 +1,22 @@
More on Updates
===============
Here we'll show some advanced usages when working with updates.
.. note::
This page makes use of Handlers and Filters to show you how to handle updates.
Learn more at `Update Handling <UpdateHandling.html>`_ and `Using Filters <UsingFilters.html>`_.
Here we'll show some advanced usages when working with `update handlers`_ and `filters`_.
Handler Groups
--------------
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
If you register handlers with overlapping (conflicting) filters, only the first one is executed and any other handler
will be ignored. This is intended by design.
In order to process the same update more than once, you can register your handler in a different group.
Groups are identified by a number (number 0 being the default) and are sorted, that is, a lower group number has a
higher priority.
In order to handle the very same update more than once, you have to register your handler in a different dispatching
group. Dispatching groups hold one or more handlers and are processed sequentially, they are identified by a number
(number 0 being the default) and sorted, that is, a lower group number has a higher priority:
For example, in:
For example, take these two handlers:
.. code-block:: python
:emphasize-lines: 1, 6
@app.on_message(Filters.text | Filters.sticker)
def text_or_sticker(client, message):
@ -29,8 +27,8 @@ For example, in:
def just_text(client, message):
print("Just Text")
``just_text`` is never executed because ``text_or_sticker`` already handles texts. To enable it, simply register the
function using a different group:
Here, ``just_text`` is never executed because ``text_or_sticker``, which has been registered first, already handles
texts (``Filters.text`` is shared and conflicting). To enable it, register the function using a different group:
.. code-block:: python
@ -69,7 +67,7 @@ continue to propagate the same update to the next groups until all the handlers
@app.on_message(Filters.private, group=1)
def _(client, message):
print(1 / 0) # Unhandled exception: ZeroDivisionError
raise Exception("Unhandled exception!") # Simulate an unhandled exception
@app.on_message(Filters.private, group=2)
@ -82,7 +80,7 @@ The output for each incoming update will therefore be:
.. code-block:: text
0
ZeroDivisionError: division by zero
Exception: Unhandled exception!
2
Stop Propagation
@ -153,9 +151,9 @@ Continue Propagation
As opposed to `stopping the update propagation <#stop-propagation>`_ and also as an alternative to the
`handler groups <#handler-groups>`_, you can signal the internal dispatcher to continue the update propagation within
the group regardless of the next handler's filters. This allows you to register multiple handlers with overlapping
filters in the same group; to let the dispatcher process the next handler you can do *one* of the following in each
handler you want to grant permission to continue:
**the same group** regardless of the next handler's filters. This allows you to register multiple handlers with
overlapping filters in the same group; to let the dispatcher process the next handler you can do *one* of the following
in each handler you want to grant permission to continue:
- Call the update's bound-method ``.continue_propagation()`` (preferred way).
- Manually ``raise ContinuePropagation`` exception (more suitable for raw updates only).
@ -219,3 +217,6 @@ The output of both (equivalent) examples will be:
0
1
2
.. _`update handlers`: UpdateHandling.html
.. _`filters`: UsingFilters.html

View File

@ -13,8 +13,8 @@ Introduction
------------
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
your applications, you had to put your function definitions in separate files and register them inside your main script,
like this:
your applications, you had to put your function definitions in separate files and register them inside your main script
after importing your modules, like this:
.. note::
@ -72,7 +72,7 @@ functions. So, what if you could? Smart Plugins solve this issue by taking care
Using Smart Plugins
-------------------
Setting up your Pyrogram project to accommodate Smart Plugins is straightforward:
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
#. Create a new folder to store all the plugins (e.g.: "plugins", "handlers", ...).
#. Put your python files full of plugins inside. Organize them as you wish.
@ -129,18 +129,17 @@ Setting up your Pyrogram project to accommodate Smart Plugins is straightforward
from pyrogram import Client
plugins = dict(
root="plugins"
)
plugins = dict(root="plugins")
Client("my_account", plugins=plugins).run()
The first important thing to note is the new ``plugins`` folder. You can put *any python file* in *any subfolder* and
each file can contain *any decorated function* (handlers) with one limitation: within a single module (file) you must
use different names for each decorated function.
The second thing is telling Pyrogram where to look for your plugins: you can either use the *config.ini* file or
the Client parameter "plugins"; the *root* value must match the name of your plugins folder. Your Pyrogram Client
the Client parameter "plugins"; the *root* value must match the name of your plugins root folder. Your Pyrogram Client
instance will **automatically** scan the folder upon starting to search for valid handlers and register them for you.
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
@ -161,7 +160,7 @@ found inside each module will be, instead, loaded in the order they are defined,
This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or
exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude``
keys, either in the *config.ini* file or in the dictionary passed as Client argument. Here's how they work:
directives, either in the *config.ini* file or in the dictionary passed as Client argument. Here's how they work:
- If both ``include`` and ``exclude`` are omitted, all plugins are loaded as described above.
- If ``include`` is given, only the specified plugins will be loaded, in the order they are passed.
@ -214,9 +213,7 @@ also organized in subfolders:
.. code-block:: python
plugins = dict(
root="plugins"
)
plugins = dict(root="plugins")
Client("my_account", plugins=plugins).run()
@ -293,7 +290,7 @@ Load/Unload Plugins at Runtime
In the `previous section <#specifying-the-plugins-to-include>`_ we've explained how to specify which plugins to load and
which to ignore before your Client starts. Here we'll show, instead, how to unload and load again a previously
registered plugins at runtime.
registered plugin at runtime.
Each function decorated with the usual ``on_message`` decorator (or any other decorator that deals with Telegram updates
) will be modified in such a way that, when you reference them later on, they will be actually pointing to a tuple of
@ -314,14 +311,14 @@ attribute. Here's an example:
- Printing ``echo`` will show something like ``(<MessageHandler object at 0x10e3abc50>, 0)``.
- Printing ``echo[0].callback``, that is, the *callback* attribute of the first eleent of the tuple, which is an
- Printing ``echo[0].callback``, that is, the *callback* attribute of the first element of the tuple, which is an
Handler, will reveal the actual callback ``<function echo at 0x10e3b6598>``.
Unloading
^^^^^^^^^
In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it (by importing the
relevant module) and call :meth:`remove_handler <pyrogram.Client.remove_handler>` Client's method with your function
In order to unload a plugin, or any other handler, all you need to do is obtain a reference to it by importing the
relevant module and call :meth:`remove_handler() <pyrogram.Client.remove_handler>` Client's method with your function
name preceded by the star ``*`` operator as argument. Example:
- ``main.py``
@ -346,7 +343,7 @@ Loading
^^^^^^^
Similarly to the unloading process, in order to load again a previously unloaded plugin you do the same, but this time
using :meth:`add_handler <pyrogram.Client.add_handler>` instead. Example:
using :meth:`add_handler() <pyrogram.Client.add_handler>` instead. Example:
- ``main.py``

View File

@ -1,11 +1,13 @@
Update Handling
===============
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
and can be handled by registering one or more callback functions in your app by using `Handlers <../pyrogram/Handlers.html>`_.
Let's now dive right into the core of the framework.
To put it simply, whenever an update is received from Telegram it will be dispatched and your previously defined callback
function(s) matching it will be called back with the update itself as argument.
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
and are handled by registering one or more callback functions in your app using `Handlers <../pyrogram/Handlers.html>`_.
Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback
function will be called.
Registering an Handler
----------------------
@ -15,13 +17,34 @@ To explain how handlers work let's have a look at the most used one, the
updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles
settings them up once you learn from this section.
Using add_handler()
-------------------
The :meth:`add_handler() <pyrogram.Client.add_handler>` method takes any handler instance that wraps around your defined
callback function and registers it in your Client. 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, MessageHandler
def my_function(client, message):
print(message)
app = Client("my_account")
my_handler = MessageHandler(my_function)
app.add_handler(my_handler)
app.run()
Using Decorators
----------------
The easiest and nicest way to register a MessageHandler is by decorating your function with the
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
of a message as soon as it arrives.
A much nicer way to register a MessageHandler is by decorating your callback function with the
:meth:`on_message() <pyrogram.Client.on_message>` decorator, which will still make use of add_handler() under the hood.
.. code-block:: python
@ -37,23 +60,13 @@ of a message as soon as it arrives.
app.run()
Using add_handler()
-------------------
If you prefer not to use decorators for any reason, there is an alternative way for registering Handlers.
This is useful, for example, when you want to keep your callback functions in separate files.
.. note::
.. code-block:: python
Due to how these decorators work in Pyrogram, they will wrap your defined callback function in a tuple consisting of
``(handler, group)``; this will be the value held by your function identifier (e.g.: *my_function* from the example
above).
from pyrogram import Client, MessageHandler
def my_handler(client, message):
print(message)
app = Client("my_account")
app.add_handler(MessageHandler(my_handler))
app.run()
In case, for some reason, you want to get your own function back after it has been decorated, you need to access
``my_function[0].callback``, that is, the *callback* field of the *handler* object which is the first element in the
tuple.

View File

@ -1,17 +1,19 @@
Using Filters
=============
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
:class:`Filters <pyrogram.Filters>`.
So far we've seen how to register a callback function that executes every time a specific update comes from the server,
but there's much more than that to come.
.. note::
This page makes use of Handlers to show you how to handle updates.
Learn more at `Update Handling <UpdateHandling.html>`_.
Here we'll discuss about :class:`Filters <pyrogram.Filters>`. Filters enable a fine-grain control over what kind of
updates are allowed or not to be passed in your callback functions, based on their inner details.
Let's start right away with a simple example:
- This example will show you how to **only** handle messages containing an :obj:`Audio <pyrogram.Audio>` object and
ignore any other message:
ignore any other message. Filters are passed as the first argument of the decorator:
.. code-block:: python
:emphasize-lines: 4
from pyrogram import Filters
@ -20,9 +22,10 @@ For a finer grained control over what kind of messages will be allowed or not in
def my_handler(client, message):
print(message)
- or, without decorators:
- or, without decorators. Here filters are passed as the second argument of the handler constructor:
.. code-block:: python
:emphasize-lines: 8
from pyrogram import Filters, MessageHandler
@ -37,7 +40,7 @@ Combining Filters
-----------------
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
operators:
operators ``~``, ``&`` and ``|``:
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
@ -74,7 +77,7 @@ can also accept arguments:
def my_handler(client, message):
print(message)
- Message is a **text** message matching the given **regex** pattern.
- Message is a **text** message or a media **caption** matching the given **regex** pattern.
.. code-block:: python
@ -104,17 +107,17 @@ Custom Filters
--------------
Pyrogram already provides lots of built-in :class:`Filters <pyrogram.Filters>` to work with, but in case you can't find
a specific one for your needs or want to build a custom filter by yourself (to be used in a different handler, for
example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
a specific one for your needs or want to build a custom filter by yourself (to be used in a different kind of handler,
for example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
.. note::
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`
only.
An example to demonstrate how custom filters work is to show how to create and use one for the
:obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by Bots;
create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline keyboard to
yourself. This allows you to test your filter by pressing the inline button:
:obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by
bots; create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline
keyboard to yourself. This allows you to test your filter by pressing the inline button:
.. code-block:: python
@ -133,26 +136,27 @@ Basic Filters
For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
The code below creates a simple filter for hardcoded callback data. This filter will only allow callback queries
containing "pyrogram" as data:
The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries
containing "Pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data
equals to ``b"Pyrogram"``.
.. code-block:: python
hardcoded_data = Filters.create(
name="HardcodedData",
func=lambda filter, callback_query: callback_query.data == b"pyrogram"
static_data = Filters.create(
name="StaticdData",
func=lambda flt, callback_query: callback_query.data == b"Pyrogram"
)
The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter itself:
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope:
.. code-block:: python
def func(filter, callback_query):
return callback_query.data == b"pyrogram"
def func(flt, callback_query):
return callback_query.data == b"Pyrogram"
hardcoded_data = Filters.create(
name="HardcodedData",
static_data = Filters.create(
name="StaticData",
func=func
)
@ -160,14 +164,14 @@ The filter usage remains the same:
.. code-block:: python
@app.on_callback_query(hardcoded_data)
@app.on_callback_query(static_data)
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")
Filters with Arguments
^^^^^^^^^^^^^^^^^^^^^^
A much cooler filter would be one that accepts "pyrogram" or any other data as argument at usage time.
A much cooler filter would be one that accepts "Pyrogram" or any other data as argument at usage time.
A dynamic filter like this will make use of the third parameter of :meth:`Filters.create() <pyrogram.Filters.create>`.
This is how a dynamic custom filter looks like:
@ -177,7 +181,7 @@ This is how a dynamic custom filter looks like:
def dynamic_data(data):
return Filters.create(
name="DynamicData",
func=lambda filter, callback_query: filter.data == callback_query.data,
func=lambda flt, callback_query: flt.data == callback_query.data,
data=data # "data" kwarg is accessed with "filter.data"
)
@ -185,6 +189,6 @@ And its usage:
.. code-block:: python
@app.on_callback_query(dynamic_data(b"pyrogram"))
@app.on_callback_query(dynamic_data(b"Pyrogram"))
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")

View File

@ -1,11 +1,11 @@
Installation
============
Being a Python library, Pyrogram requires Python to be installed in your system.
Being a Python library, **Pyrogram** requires Python to be installed in your system.
We recommend using the latest version of Python 3 and pip.
Get Python 3 from https://www.python.org/downloads/ (or with your package manager) and pip
by following the instructions at https://pip.pypa.io/en/latest/installing/.
- Get **Python 3** from https://www.python.org/downloads/ (or with your package manager)
- Get **pip** by following the instructions at https://pip.pypa.io/en/latest/installing/.
.. important::
@ -29,8 +29,12 @@ Install Pyrogram
Bleeding Edge
-------------
If you want the latest development version of Pyrogram, you can install it straight from the develop_
branch using this command (note "develop.zip" in the link):
Things are constantly evolving in Pyrogram, although new releases are published only when enough changes are added,
but this doesn't mean you can't try new features right now!
In case you would like to try out the latest Pyrogram features and additions, the `GitHub repo`_ is always kept updated
with new changes; you can install the development version straight from the ``develop`` branch using this command
(note "develop.zip" in the link):
.. code-block:: text
@ -39,10 +43,10 @@ branch using this command (note "develop.zip" in the link):
Asynchronous
------------
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging client library after all), and here's
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging framework after all), and here's
where asyncio shines the most by providing extra performance while running on a single OS-level thread only.
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5+ required).
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5.3+ required).
Use this command to install (note "asyncio.zip" in the link):
.. code-block:: text
@ -85,4 +89,4 @@ If no error shows up you are good to go.
'0.12.0'
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
.. _develop: http://github.com/pyrogram/pyrogram
.. _`Github repo`: http://github.com/pyrogram/pyrogram

View File

@ -15,23 +15,22 @@ If you already have one you can skip this step, otherwise:
#. Fill out the form to register a new Telegram application.
#. Done. The API key consists of two parts: **App api_id** and **App api_hash**.
.. important::
This API key is personal and should be kept secret.
This API key is personal and must be kept secret.
Configuration
-------------
The API key obtained in the `previous step <#api-keys>`_ defines a token for your application allowing you to access
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both Users and Bots**.
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both users and bots**.
Having it handy, it's time to configure your Pyrogram project. There are two ways to do so, and you can choose what
fits better for you:
- Create a new ``config.ini`` file at the root of your working directory, copy-paste the following and replace the
**api_id** and **api_hash** values with your own. This is the preferred method because allows you
to keep your credentials out of your code without having to deal with how to load them:
**api_id** and **api_hash** values with your own. This is the preferred method because allows you to keep your
credentials out of your code without having to deal with how to load them:
.. code-block:: ini
@ -39,8 +38,8 @@ fits better for you:
api_id = 12345
api_hash = 0123456789abcdef0123456789abcdef
- 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:
- 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
@ -54,16 +53,16 @@ fits better for you:
.. 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.
From now on, the code snippets assume you are using the ``config.ini`` file, thus they won't show the *api_id* and
*api_hash* parameters usage to keep them as clean as possible.
User Authorization
------------------
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 <pyrogram.Client>` class by passing to it a ``session_name`` of your choice
(e.g.: "my_account") and call the :meth:`run() <pyrogram.Client.run>` method:
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 <pyrogram.Client>` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call
the :meth:`run() <pyrogram.Client.run>` method:
.. code-block:: python
@ -80,31 +79,40 @@ and the **phone code** you will receive:
Enter phone number: +39**********
Is "+39**********" correct? (y/n): y
Enter phone code: 32768
Logged in successfully as Dan
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.
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`` files are personal and must be kept secret.
.. note::
The code above does nothing except asking for credentials and keeping the client online, hit ``CTRL+C`` now to stop
your application and keep reading.
Bot Authorization
-----------------
Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by
BotFather_. Bot tokens replace the Users' phone numbers only — you still need to
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using Bots.
BotFather_. Bot tokens replace the users' phone numbers only — you still need to
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using bots.
The authorization process is automatically managed. All you need to do is choose a ``session_name`` (can be anything,
usually your bot username) and pass your bot token using the ``bot_token`` parameter.
The session file will be named after the session name, which will be ``pyrogrambot.session`` for the example below.
usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named
after the session name, which will be ``pyrogrambot.session`` for the example below.
.. code-block:: python
from pyrogram import Client
app = Client("pyrogrambot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
app = Client(
"pyrogrambot",
bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
)
app.run()
.. _installed Pyrogram: Installation.html

View File

@ -1,7 +1,7 @@
Usage
=====
Having your `project set up`_ and your account authorized_, it's time to play with the API. Let's start!
Having your `project set up`_ and your account authorized_, it's time to start playing with the API. Let's start!
High-level API
--------------
@ -22,6 +22,7 @@ Here's a simple example:
print(app.get_me())
app.send_message("me", "Hi there! I'm using **Pyrogram**")
app.send_location("me", 51.500729, -0.124583)
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
app.stop()
@ -39,6 +40,7 @@ exceptions in your code:
print(app.get_me())
app.send_message("me", "Hi there! I'm using **Pyrogram**")
app.send_location("me", 51.500729, -0.124583)
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI")
More examples on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/examples>`_.

View File

@ -33,13 +33,6 @@ class OnCallbackQuery(BaseClient):
"""Use this decorator to automatically register a function for handling callback queries.
This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`.
.. note::
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
To reference your own function after it has been decorated, you need to access
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
first element in the tuple.
Args:
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of callback queries to be passed

View File

@ -33,13 +33,6 @@ class OnDeletedMessages(BaseClient):
"""Use this decorator to automatically register a function for handling deleted messages.
This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`.
.. note::
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
To reference your own function after it has been decorated, you need to access
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
first element in the tuple.
Args:
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of messages to be passed

View File

@ -33,13 +33,6 @@ class OnMessage(BaseClient):
"""Use this decorator to automatically register a function for handling messages.
This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`.
.. note::
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
To reference your own function after it has been decorated, you need to access
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
first element in the tuple.
Args:
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of messages to be passed

View File

@ -31,13 +31,6 @@ class OnRawUpdate(BaseClient):
"""Use this decorator to automatically register a function for handling raw updates.
This does the same thing as :meth:`add_handler` using the :class:`RawUpdateHandler`.
.. note::
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
To reference your own function after it has been decorated, you need to access
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
first element in the tuple.
Args:
group (``int``, *optional*):
The group identifier, defaults to 0.

View File

@ -33,13 +33,6 @@ class OnUserStatus(BaseClient):
"""Use this decorator to automatically register a function for handling user status updates.
This does the same thing as :meth:`add_handler` using the :class:`UserStatusHandler`.
.. note::
This decorator will wrap your defined function in a tuple consisting of *(Handler, group)*.
To reference your own function after it has been decorated, you need to access
*my_function[0].callback*, that is, the *callback* field of Handler object which is the the
first element in the tuple.
Args:
filters (:obj:`Filters <pyrogram.Filters>`):
Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function.