Update docs with new content

This commit is contained in:
Dan 2019-06-04 16:10:32 +02:00
parent 9a44c79a82
commit 1be8ca94cc
8 changed files with 295 additions and 131 deletions

View File

@ -155,6 +155,14 @@ things:
chats).
- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``.
UnicodeEncodeError: '<encoding>' codec can't encode …
-----------------------------------------------------
Where ``<encoding>`` might be *ascii*, *cp932*, *charmap* or anything else other than **utf-8**. This error usually
shows up when you try to print something and has very little to do with Pyrogram itself as it is strictly related to
your own terminal. To fix it, either find a way to change the encoding settings of your terminal to UTF-8 or switch to a
better one.
My verification code expires immediately!
-----------------------------------------
@ -179,8 +187,20 @@ Having said that, here's a list of what Telegram definitely doesn't like:
- Spam, sending unsolicited messages or adding people to unwanted groups and channels.
- Virtual/VoIP and cheap real numbers, because they are relatively easy to get and likely used for spam/flood.
However, you might be right, and your account was deactivated/limited without any reason. This could happen because of
mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at
And here's a good explanation of how, probably, the system works:
.. raw:: html
<script
async src="https://telegram.org/js/telegram-widget.js?5"
data-telegram-post="PyrogramChat/69424"
data-width="100%">
</script>
.. centered:: Join the discussion at `@PyrogramChat <https://t.me/pyrogramchat>`_
However, you might be right, and your account was deactivated/limited without any good reason. This could happen because
of mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at
recover@telegram.org, contact `@smstelegram`_ on Twitter or use `this form`_.
Are there any secret easter eggs?

View File

@ -9,7 +9,11 @@ general. Some words may as well link to dedicated articles in case the topic is
If you think something interesting could be added here, feel free to propose it by opening a `Feature Request`_.
Terms
-----
.. glossary::
:sorted:
API
Application Programming Interface: a set of methods, protocols and tools that make it easier to develop programs

View File

@ -122,7 +122,8 @@ Meta
:hidden:
:caption: Topic Guides
topics/filters
topics/use-filters
topics/create-filters
topics/more-on-updates
topics/config-file
topics/smart-plugins
@ -134,6 +135,7 @@ Meta
topics/proxy
topics/bots-interaction
topics/mtproto-vs-botapi
topics/debugging
topics/test-servers
topics/advanced-usage
topics/voice-calls

View File

@ -24,25 +24,25 @@ Making API method calls with Pyrogram is very simple. Here's an example we are g
app.stop()
Let's begin by importing the Client class from the Pyrogram package:
#. Let's begin by importing the Client class from the Pyrogram package:
.. code-block:: python
from pyrogram import Client
Now instantiate a new Client object, "my_account" is a session name of your choice:
#. Now instantiate a new Client object, "my_account" is a session name of your choice:
.. code-block:: python
app = Client("my_account")
To actually make use of any method, the client has to be started first:
#. To actually make use of any method, the client has to be started first:
.. code-block:: python
app.start()
Now, you can call any method you like:
#. Now, you can call any method you like:
.. code-block:: python
@ -53,7 +53,7 @@ Now, you can call any method you like:
app.send_location("me", 51.500729, -0.124583) # Location
app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") # Sticker
Finally, when done, simply stop the client:
#. Finally, when done, simply stop the client:
.. code-block:: python

View File

@ -45,7 +45,7 @@ arrives:
app.run()
Let's examine these four new pieces. First one: a callback function we defined which accepts two arguments -
#. Let's examine these four new pieces. First one: a callback function we defined which accepts two arguments -
*(client, message)*. This will be the function that gets executed every time a new message arrives and Pyrogram will
call that function by passing the client instance and the new message instance as argument.
@ -54,23 +54,24 @@ call that function by passing the client instance and the new message instance a
def my_function(client, message):
print(message)
Second one: the :class:`~pyrogram.MessageHandler`. This object tells Pyrogram the function we defined above must only
handle updates that are in form of a :class:`~pyrogram.Message`:
#. Second one: the :class:`~pyrogram.MessageHandler`. This object tells Pyrogram the function we defined above must
only handle updates that are in form of a :class:`~pyrogram.Message`:
.. code-block:: python
my_handler = MessageHandler(my_function)
Third: the method :meth:`~pyrogram.Client.add_handler`. This method is used to actually register the handler and let
Pyrogram know it needs to be taken into consideration when new updates arrive and the internal dispatching phase begins.
#. Third: the method :meth:`~pyrogram.Client.add_handler`. This method is used to actually register the handler and let
Pyrogram know it needs to be taken into consideration when new updates arrive and the internal dispatching phase
begins.
.. code-block:: python
app.add_handler(my_handler)
Last one, the :meth:`~pyrogram.Client.run` method. What this does is simply call :meth:`~pyrogram.Client.start` and a
special method :meth:`~pyrogram.Client.idle` that keeps your main scripts alive until you press ``CTRL+C``; the client
will be automatically stopped after that.
#. Last one, the :meth:`~pyrogram.Client.run` method. What this does is simply call :meth:`~pyrogram.Client.start` and
a special method :meth:`~pyrogram.Client.idle` that keeps your main scripts alive until you press ``CTRL+C``; the
client will be automatically stopped after that.
.. code-block:: python

View File

@ -0,0 +1,92 @@
Creating Filters
================
Pyrogram already provides lots of built-in :class:`~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 kind of handler,
for example) you can use :meth:`~pyrogram.Filters.create`.
.. note::
At the moment, the built-in filters are intended to be used with the :class:`~pyrogram.MessageHandler` only.
Custom Filters
--------------
An example to demonstrate how custom filters work is to show how to create and use one for the
:class:`~pyrogram.CallbackQueryHandler`. Note that callback queries updates are only received by bots; create and
:doc:`authorize your bot <../start/auth>`, 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
from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton
app.send_message(
"username", # Change this to your username or id
"Pyrogram's custom filter test",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("Press me", b"pyrogram")]]
)
)
Basic Filters
-------------
For this basic filter we will be using only the first two parameters of :meth:`~pyrogram.Filters.create`.
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
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's scope:
.. code-block:: python
def func(flt, callback_query):
return callback_query.data == b"Pyrogram"
static_data = Filters.create(
name="StaticData",
func=func
)
The filter usage remains the same:
.. code-block:: python
@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 dynamic filter like this will make use of the third parameter of :meth:`~pyrogram.Filters.create`.
This is how a dynamic custom filter looks like:
.. code-block:: python
def dynamic_data(data):
return Filters.create(
name="DynamicData",
func=lambda flt, callback_query: flt.data == callback_query.data,
data=data # "data" kwarg is accessed with "filter.data"
)
And its usage:
.. code-block:: python
@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

@ -0,0 +1,135 @@
Debugging
=========
When working with the API, chances are you'll stumble upon bugs, get stuck and start wondering how to continue. Nothing
to actually worry about -- that's normal -- and luckily for you, Pyrogram provides some commodities to help you in this.
Caveman Debugging
-----------------
*The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.*
-- Brian Kernighan, "Unix for Beginners" (1979)
Adding ``print()`` statements in crucial parts of your code is by far the most ancient, yet efficient technique for
debugging programs, especially considering the concurrent nature of the framework itself. Pyrogram goodness in this
respect comes with the fact that any object can be nicely printed just by calling ``print(obj)``, thus giving to you
an insight of all its inner details.
Consider the following code:
.. code-block:: python
dan = app.get_users("haskell")
print(dan) # User
This will show a JSON representation of the object returned by :meth:`~pyrogram.Client.get_users`, which is a
:class:`~pyrogram.User` instance, in this case. The output on your terminal will be something similar to this:
.. code-block:: json
{
"_": "pyrogram.User",
"id": 23122162,
"is_self": false,
"is_contact": false,
"is_mutual_contact": false,
"is_deleted": false,
"is_bot": false,
"is_verified": false,
"is_restricted": false,
"is_support": false,
"is_scam": false,
"first_name": "Dan",
"status": {
"_": "pyrogram.UserStatus",
"user_id": 23122162,
"recently": true
},
"username": "haskell",
"language_code": "en",
"photo": {
"_": "pyrogram.ChatPhoto",
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
}
}
As you've probably guessed already, Pyrogram objects can be nested. That's how compound data are built, and nesting
keeps going until we are left with base data types only, such as ``str``, ``int``, ``bool``, etc.
Accessing Attributes
--------------------
Even though you see a JSON output, it doesn't mean we are dealing with dictionaries; in fact, all Pyrogram types are
full-fledged Python objects and the correct way to access any attribute of them is by using the dot notation ``.``:
.. code-block:: python
dan_photo = dan.photo
print(dan_photo) # ChatPhoto
.. code-block:: json
{
"_": "pyrogram.ChatPhoto",
"small_file_id": "AQADBAAD8tBgAQAEJjCxGgAEo5IBAAIC",
"big_file_id": "AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg"
}
However, the bracket notation ``[]`` is also supported, but its usage is discouraged:
.. warning::
Bracket notation in Python is not commonly used for getting/setting object attributes. While it works for Pyrogram
objects, it might not work for anything else and you should not rely on this.
.. code-block:: python
dan_photo_big = dan["photo"]["big_file_id"]
print(dan_photo_big) # str
.. code-block:: text
AQADBAAD8tBgAQAEJjCxGgAEpZIBAAEBAg
Checking an Object's Type
-------------------------
Another thing worth talking about is how to tell and check for an object's type.
As you noticed already, when printing an object you'll see the special attribute ``"_"``. This is just a visual thing
useful to show humans the object type, but doesn't really exist anywhere; any attempt in accessing it will lead to an
error. The correct way to get the object type is by using the built-in function ``type()``:
.. code-block:: python
dan_status = dan.status
print(type(dan_status))
.. code-block:: text
<class 'pyrogram.UserStatus'>
And to check if an object is an instance of a given class, you use the built-in function ``isinstance()``:
.. code-block:: python
:name: this-py
from pyrogram import UserStatus
dan_status = dan.status
print(isinstance(dan_status, UserStatus))
.. code-block:: text
True
.. raw:: html
<script>
var e = document.querySelector("blockquote p.attribution");
var s = e.innerHTML;
e.innerHTML = s[0] + " " + s.slice(1);
</script>

View File

@ -105,93 +105,3 @@ More handlers using different filters can also live together.
@app.on_message(Filters.chat("PyrogramChat"))
def from_pyrogramchat(client, message):
print("New message in @PyrogramChat")
Custom Filters
--------------
Pyrogram already provides lots of built-in :class:`~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 kind of handler,
for example) you can use :meth:`~pyrogram.Filters.create`.
.. note::
At the moment, the built-in filters are intended to be used with the :class:`~pyrogram.MessageHandler` only.
An example to demonstrate how custom filters work is to show how to create and use one for the
:class:`~pyrogram.CallbackQueryHandler`. Note that callback queries updates are only received by bots; create and
:doc:`authorize your bot <../start/auth>`, 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
from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton
app.send_message(
"username", # Change this to your username or id
"Pyrogram's custom filter test",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("Press me", b"pyrogram")]]
)
)
Basic Filters
^^^^^^^^^^^^^
For this basic filter we will be using only the first two parameters of :meth:`~pyrogram.Filters.create`.
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
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's scope:
.. code-block:: python
def func(flt, callback_query):
return callback_query.data == b"Pyrogram"
static_data = Filters.create(
name="StaticData",
func=func
)
The filter usage remains the same:
.. code-block:: python
@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 dynamic filter like this will make use of the third parameter of :meth:`~pyrogram.Filters.create`.
This is how a dynamic custom filter looks like:
.. code-block:: python
def dynamic_data(data):
return Filters.create(
name="DynamicData",
func=lambda flt, callback_query: flt.data == callback_query.data,
data=data # "data" kwarg is accessed with "filter.data"
)
And its usage:
.. code-block:: python
@app.on_callback_query(dynamic_data(b"Pyrogram"))
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")