Finish up asyncio docs

This commit is contained in:
Lonami Exo 2018-06-22 14:44:59 +02:00
parent 3d3698562b
commit f614d3836b
12 changed files with 255 additions and 109 deletions

View File

@ -93,7 +93,7 @@ every time its used, simply call `telethon.utils.get_input_peer`:
.. code-block:: python .. code-block:: python
from telethon import utils from telethon import utils
peer = utils.get_input_user(entity) peer = utils.get_input_peer(entity)
.. note:: .. note::
@ -117,8 +117,8 @@ request we do:
) )
# __call__ is an alias for client.invoke(request). Both will work # __call__ is an alias for client.invoke(request). Both will work
Message sent! Of course, this is only an example. There are nearly 250 Message sent! Of course, this is only an example. There are over 250
methods available as of layer 73, and you can use every single of them methods available as of layer 80, and you can use every single of them
as you wish. Remember to use the right types! To sum up: as you wish. Remember to use the right types! To sum up:
.. code-block:: python .. code-block:: python

View File

@ -24,8 +24,8 @@ loop, you should use `client.run_until_disconnected
Behind the scenes, this method is ``await``'ing on the `client.disconnected Behind the scenes, this method is ``await``'ing on the `client.disconnected
<telethon.client.telegrambaseclient.disconnected>` property, so the code above <telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>` property,
and the following are equivalent: so the code above and the following are equivalent:
.. code-block:: python .. code-block:: python
@ -42,7 +42,8 @@ and the following are equivalent:
You could also run `client.disconnected You could also run `client.disconnected
<telethon.client.telegrambaseclient.disconnected>` until it completed. <telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
until it completed.
But if you don't want to ``await``, then you should know what you want But if you don't want to ``await``, then you should know what you want
to be doing instead! What matters is that you shouldn't let your script to be doing instead! What matters is that you shouldn't let your script

View File

@ -19,9 +19,9 @@ way. You send your request, and eventually, Telegram will process it and
respond to it. It feels natural to make a library that also behaves this respond to it. It feels natural to make a library that also behaves this
way: you send a request, and you can ``await`` for its result. way: you send a request, and you can ``await`` for its result.
Having understood that Telegram's API follows an asynchronous model and Now that we know that Telegram's API follows an asynchronous model, you
developing a library that does the same greatly simplifies the internal should understand the benefits of developing a library that does the same,
code and eases working with the API. it greatly simplifies the internal code and eases working with the API.
Using ``asyncio`` keeps a cleaner library that will be easier to understand, Using ``asyncio`` keeps a cleaner library that will be easier to understand,
develop, and that will be faster than using threads, which are harder to get develop, and that will be faster than using threads, which are harder to get
@ -54,7 +54,7 @@ To get started with ``asyncio``, all you need is to setup your main
Inside ``async def main():``, you can use the ``await`` keyword. Most Inside ``async def main():``, you can use the ``await`` keyword. Most
methods in the :ref:`TelegramClient <telethon-client>` are ``async def``. methods in the :ref:`TelegramClient <telethon-client>` are ``async def``.
You must ``await`` all ``async def``, also known as a coroutine: You must ``await`` all ``async def``, also known as a *coroutines*:
.. code-block:: python .. code-block:: python
@ -78,9 +78,9 @@ Another way to use ``async def`` is to use ``loop.run_until_complete(f())``,
but the loop must not be running before. but the loop must not be running before.
If you want to handle updates (and don't let the script die), you must If you want to handle updates (and don't let the script die), you must
`await client.disconnected <telethon.client.telegrambaseclient.disconnected>` `await client.disconnected <telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
which is a property that you can wait on until you call which is a property that you can wait on until you call
`await client.disconnect() <telethon.client.telegrambaseclient.disconnect>`: `await client.disconnect() <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`:
.. code-block:: python .. code-block:: python
@ -115,6 +115,68 @@ This is the same as using the ``run_until_disconnected()`` method:
client.run_until_disconnected() client.run_until_disconnected()
Which methods should I use and when?
************************************
Something to note is that you must always get an event loop if you
want to be able to make any API calls. This is done as follows:
.. code-block:: python
import asyncio
loop = asyncio.get_event_loop()
The loop must be running, or things will never get sent.
Normally, you use ``run_until_complete``:
.. code-block:: python
async def coroutine():
await asyncio.sleep(1)
loop.run_until_complete(coroutine())
Note that ``asyncio.sleep`` is in itself a coroutine, so this will
work too:
.. code-block:: python
loop.run_until_complete(asyncio.sleep(1))
Generally, you make an ``async def main()`` if you need to ``await``
a lot of things, instead of typing ``run_until_complete`` all the time:
.. code-block:: python
async def main():
message = await client.send_message('me', 'Hi')
await asyncio.sleep(1)
await message.delete()
loop.run_until_complete(main())
# vs
message = loop.run_until_complete(client.send_message('me', 'Hi'))
loop.run_until_complete(asyncio.sleep(1))
loop.run_until_complete(message.delete())
You can see that the first version has more lines, but you had to type
a lot less. You can also rename the run method to something shorter:
.. code-block:: python
# Note no parenthesis (), we're not running it, just copying the method
rc = loop.run_until_complete
message = rc(client.send_message('me', 'Hi'))
rc(asyncio.sleep(1))
rc(message.delete())
The documentation will use all these three styles so you can get used
to them. Which one to use is up to you, but generally you should work
inside an ``async def main()`` and just run the loop there.
More resources to learn asyncio More resources to learn asyncio
******************************* *******************************

View File

@ -30,14 +30,16 @@ this is, any "method" listed on the API. There are a few methods (and
growing!) on the :ref:`TelegramClient <telethon-client>` class that abstract growing!) on the :ref:`TelegramClient <telethon-client>` class that abstract
you from the need of manually importing the requests you need. you from the need of manually importing the requests you need.
For instance, retrieving your own user can be done in a single line: For instance, retrieving your own user can be done in a single line
(if we ignore the boilerplate needed to setup ``asyncio``, which only
needs to be done once for your entire program):
.. code-block:: python .. code-block:: python
import asyncio import asyncio
async def main(): async def main():
myself = await client.get_me() myself = await client.get_me() # <- a single line!
if __name__ == '__main__': if __name__ == '__main__':
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()

View File

@ -82,7 +82,8 @@ the callback function you're about to define will be called:
If a `NewMessage If a `NewMessage
<telethon.events.newmessage.NewMessage>` event occurs, <telethon.events.newmessage.NewMessage>` event occurs,
and ``'hello'`` is in the text of the message, we ``reply`` to the event and ``'hello'`` is in the text of the message, we `.reply()
<telethon.tl.custom.message.Message.reply>` to the event
with a ``'hi!'`` message. with a ``'hi!'`` message.
.. code-block:: python .. code-block:: python
@ -101,23 +102,35 @@ More on events
************** **************
The `NewMessage <telethon.events.newmessage.NewMessage>` event has much The `NewMessage <telethon.events.newmessage.NewMessage>` event has much
more than what was shown. You can access the ``.sender`` of the message more than what was shown. You can access the `.sender
through that member, or even see if the message had ``.media``, a ``.photo`` <telethon.tl.custom.message.Message.sender>` of the message
or a ``.document`` (which you could download with for example through that member, or even see if the message had `.media
`client.download_media(event.photo) <telethon.client.downloads.DownloadMethods.download_media>`. <telethon.tl.custom.message.Message.media>`, a `.photo
<telethon.tl.custom.message.Message.photo>` or a `.document
<telethon.tl.custom.message.Message.document>` (which you
could download with for example `client.download_media(event.photo)
<telethon.client.downloads.DownloadMethods.download_media>`.
If you don't want to ``.reply`` as a reply, you can use the ``.respond()`` If you don't want to `.reply()
method instead. Of course, there are more events such as ``ChatAction`` or <telethon.tl.custom.message.Message.reply>` as a reply,
``UserUpdate``, and they're all used in the same way. Simply add the you can use the `.respond() <telethon.tl.custom.message.Message.respond>`
``@client.on(events.XYZ)`` decorator on the top of your handler and you're method instead. Of course, there are more events such as `ChatAction
done! The event that will be passed always is of type ``XYZ.Event`` (for <telethon.events.chataction.ChatAction>` or `UserUpdate
instance, ``NewMessage.Event``), except for the ``Raw`` event which just <telethon.events.userupdate.UserUpdate>`, and they're all
passes the ``Update`` object. used in the same way. Simply add the `@client.on(events.XYZ)
<telethon.client.updates.UpdateMethods.on>` decorator on the top
of your handler and you're done! The event that will be passed always
is of type ``XYZ.Event`` (for instance, `NewMessage.Event
<telethon.events.newmessage.NewMessage.Event>`), except for the `Raw
<telethon.events.raw.Raw>` event which just passes the :tl:`Update` object.
Note that ``.reply()`` and ``.respond()`` are just wrappers around the Note that `.reply()
<telethon.tl.custom.message.Message.reply>` and `.respond()
<telethon.tl.custom.message.Message.respond>` are just wrappers around the
`client.send_message() <telethon.client.messages.MessageMethods.send_message>` `client.send_message() <telethon.client.messages.MessageMethods.send_message>`
method which supports the ``file=`` parameter. method which supports the ``file=`` parameter.
This means you can reply with a photo if you do ``event.reply(file=photo)``. This means you can reply with a photo if you do `event.reply(file=photo)
<telethon.tl.custom.message.Message.reply>`.
You can put the same event on many handlers, and even different events on You can put the same event on many handlers, and even different events on
the same handler. You can also have a handler work on only specific chats, the same handler. You can also have a handler work on only specific chats,
@ -154,6 +167,45 @@ random number, while if you say ``'eval 4+4'``, you will reply with the
solution. Try it! solution. Try it!
Properties vs. methods
**********************
The event shown above acts just like a `custom.Message
<telethon.tl.custom.message.Message>`, which means you
can access all the properties it has, like ``.sender``.
**However** events are different to other methods in the client, like
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
Events *may not* send information about the sender or chat, which means it
can be ``None``, but all the methods defined in the client always have this
information so it doesn't need to be re-fetched. For this reason, you have
``get_`` methods, which will make a network call if necessary.
In short, you should do this:
.. code-block:: python
@client.on(events.NewMessage)
async def handler(event):
# event.input_chat may be None, use event.get_input_chat()
chat = await event.get_input_chat()
sender = await event.get_sender()
buttons = await event.get_buttons()
async def main():
async for message in client.iter_messages('me', 10):
# Methods from the client always have these properties ready
chat = message.input_chat
sender = message.sender
buttons = message.buttons
Notice, properties (`message.sender
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
methods (`message.get_sender
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
and you should use methods in events for these properties that may need network.
Events without decorators Events without decorators
************************* *************************

View File

@ -32,4 +32,6 @@ times, in this case, ``22222`` so we can hardcode that:
client = TelegramClient(None, api_id, api_hash) client = TelegramClient(None, api_id, api_hash)
client.session.set_dc(2, '149.154.167.40', 80) client.session.set_dc(2, '149.154.167.40', 80)
client.start(phone='9996621234', code_callback=lambda: '22222') loop.run_until_complete(client.start(
phone='9996621234', code_callback=lambda: '22222'
))

View File

@ -19,9 +19,9 @@ not *interact* with a voting message), by making use of the
from telethon.tl.functions.messages import GetInlineBotResultsRequest from telethon.tl.functions.messages import GetInlineBotResultsRequest
bot_results = client(GetInlineBotResultsRequest( bot_results = loop.run_until_complete(client(GetInlineBotResultsRequest(
bot, user_or_chat, 'query', '' bot, user_or_chat, 'query', ''
)) )))
And you can select any of their results by using And you can select any of their results by using
:tl:`SendInlineBotResultRequest`: :tl:`SendInlineBotResultRequest`:
@ -30,16 +30,27 @@ And you can select any of their results by using
from telethon.tl.functions.messages import SendInlineBotResultRequest from telethon.tl.functions.messages import SendInlineBotResultRequest
client(SendInlineBotResultRequest( loop.run_until_complete(client(SendInlineBotResultRequest(
get_input_peer(user_or_chat), get_input_peer(user_or_chat),
obtained_query_id, obtained_query_id,
obtained_str_id obtained_str_id
)) )))
Talking to Bots with special reply markup Talking to Bots with special reply markup
***************************************** *****************************************
Generally, you just use the `message.click()
<telethon.tl.custom.message.Message.click>` method:
.. code-block:: python
async def main():
messages = await client.get_messages('somebot')
await messages[0].click(0)
You can also do it manually.
To interact with a message that has a special reply markup, such as To interact with a message that has a special reply markup, such as
`@VoteBot`__ polls, you would use :tl:`GetBotCallbackAnswerRequest`: `@VoteBot`__ polls, you would use :tl:`GetBotCallbackAnswerRequest`:
@ -47,11 +58,11 @@ To interact with a message that has a special reply markup, such as
from telethon.tl.functions.messages import GetBotCallbackAnswerRequest from telethon.tl.functions.messages import GetBotCallbackAnswerRequest
client(GetBotCallbackAnswerRequest( loop.run_until_complete(client(GetBotCallbackAnswerRequest(
user_or_chat, user_or_chat,
msg.id, msg.id,
data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data
)) )))
It's a bit verbose, but it has all the information you would need to It's a bit verbose, but it has all the information you would need to
show it visually (button rows, and buttons within each row, each with show it visually (button rows, and buttons within each row, each with

View File

@ -12,7 +12,7 @@ Joining a chat or channel
************************* *************************
Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a
special form of ``Chat``, which can also be super-groups if special form of :tl:`Chat`, which can also be super-groups if
their ``megagroup`` member is ``True``. their ``megagroup`` member is ``True``.
@ -25,11 +25,11 @@ to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
.. code-block:: python .. code-block:: python
from telethon.tl.functions.channels import JoinChannelRequest from telethon.tl.functions.channels import JoinChannelRequest
client(JoinChannelRequest(channel)) loop.run_until_complete(client(JoinChannelRequest(channel)))
# In the same way, you can also leave such channel # In the same way, you can also leave such channel
from telethon.tl.functions.channels import LeaveChannelRequest from telethon.tl.functions.channels import LeaveChannelRequest
client(LeaveChannelRequest(input_channel)) loop.run_until_complete(client(LeaveChannelRequest(input_channel)))
For more on channels, check the `channels namespace`__. For more on channels, check the `channels namespace`__.
@ -51,7 +51,9 @@ example, is the ``hash`` of the chat or channel. Now you can use
.. code-block:: python .. code-block:: python
from telethon.tl.functions.messages import ImportChatInviteRequest from telethon.tl.functions.messages import ImportChatInviteRequest
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg')) updates = loop.run_until_complete(
client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
)
Adding someone else to such chat or channel Adding someone else to such chat or channel
@ -68,19 +70,19 @@ use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
# Note that ``user_to_add`` is NOT the name of the parameter. # Note that ``user_to_add`` is NOT the name of the parameter.
# It's the user you want to add (``user_id=user_to_add``). # It's the user you want to add (``user_id=user_to_add``).
client(AddChatUserRequest( loop.run_until_complete(client(AddChatUserRequest(
chat_id, chat_id,
user_to_add, user_to_add,
fwd_limit=10 # Allow the user to see the 10 last messages fwd_limit=10 # Allow the user to see the 10 last messages
)) )))
# For channels (which includes megagroups) # For channels (which includes megagroups)
from telethon.tl.functions.channels import InviteToChannelRequest from telethon.tl.functions.channels import InviteToChannelRequest
client(InviteToChannelRequest( loop.run_until_complete(client(InviteToChannelRequest(
channel, channel,
[users_to_add] [users_to_add]
)) )))
Checking a link without joining Checking a link without joining
@ -102,6 +104,14 @@ Retrieving all chat members (channels too)
This method will handle different chat types for you automatically. This method will handle different chat types for you automatically.
Here is the easy way to do it:
.. code-block:: python
participants = loop.run_until_complete(client.get_participants(group))
Now we will show how the method works internally.
In order to get all the members from a mega-group or channel, you need In order to get all the members from a mega-group or channel, you need
to use :tl:`GetParticipantsRequest`. As we can see it needs an to use :tl:`GetParticipantsRequest`. As we can see it needs an
:tl:`InputChannel`, (passing the mega-group or channel you're going to :tl:`InputChannel`, (passing the mega-group or channel you're going to
@ -123,10 +133,9 @@ a fixed limit:
all_participants = [] all_participants = []
while True: while True:
participants = client(GetParticipantsRequest( participants = loop.run_until_complete(client(GetParticipantsRequest(
channel, ChannelParticipantsSearch(''), offset, limit, channel, ChannelParticipantsSearch(''), offset, limit, hash=0
hash=0 )))
))
if not participants.users: if not participants.users:
break break
all_participants.extend(participants.users) all_participants.extend(participants.users)
@ -193,7 +202,7 @@ Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`
# ) # )
# Once you have a ChannelAdminRights, invoke it # Once you have a ChannelAdminRights, invoke it
client(EditAdminRequest(channel, user, rights)) loop.run_until_complete(client(EditAdminRequest(channel, user, rights)))
# User will now be able to change group info, delete other people's # User will now be able to change group info, delete other people's
# messages and pin messages. # messages and pin messages.
@ -252,7 +261,7 @@ banned rights of an user through :tl:`EditBannedRequest` and its parameter
embed_links=True embed_links=True
) )
client(EditBannedRequest(channel, user, rights)) loop.run_until_complete(client(EditBannedRequest(channel, user, rights)))
Kicking a member Kicking a member
@ -267,9 +276,11 @@ is enough:
from telethon.tl.functions.channels import EditBannedRequest from telethon.tl.functions.channels import EditBannedRequest
from telethon.tl.types import ChannelBannedRights from telethon.tl.types import ChannelBannedRights
client(EditBannedRequest(channel, user, ChannelBannedRights( loop.run_until_complete(client(EditBannedRequest(
until_date=None, channel, user, ChannelBannedRights(
view_messages=True until_date=None,
view_messages=True
)
))) )))
@ -291,11 +302,11 @@ use :tl:`GetMessagesViewsRequest`, setting ``increment=True``:
# Obtain `channel' through dialogs or through client.get_entity() or anyhow. # Obtain `channel' through dialogs or through client.get_entity() or anyhow.
# Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list. # Obtain `msg_ids' through `.get_messages()` or anyhow. Must be a list.
client(GetMessagesViewsRequest( loop.run_until_complete(client(GetMessagesViewsRequest(
peer=channel, peer=channel,
id=msg_ids, id=msg_ids,
increment=True increment=True
)) )))
Note that you can only do this **once or twice a day** per account, Note that you can only do this **once or twice a day** per account,

View File

@ -19,11 +19,12 @@ you should use :tl:`GetFullUser`:
from telethon.tl.functions.users import GetFullUserRequest from telethon.tl.functions.users import GetFullUserRequest
full = client(GetFullUserRequest(user)) async def main():
# or even full = await client(GetFullUserRequest(user))
full = client(GetFullUserRequest('username')) # or even
full = await client(GetFullUserRequest('username'))
bio = full.about bio = full.about
See :tl:`UserFull` to know what other fields you can access. See :tl:`UserFull` to know what other fields you can access.
@ -39,7 +40,9 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
from telethon.tl.functions.account import UpdateProfileRequest from telethon.tl.functions.account import UpdateProfileRequest
client(UpdateProfileRequest(about='This is a test from Telethon')) loop.run_until_complete(client(UpdateProfileRequest(a
bout='This is a test from Telethon'
)))
Updating your username Updating your username
@ -51,7 +54,7 @@ You need to use :tl:`account.UpdateUsername`:
from telethon.tl.functions.account import UpdateUsernameRequest from telethon.tl.functions.account import UpdateUsernameRequest
client(UpdateUsernameRequest('new_username')) loop.run_until_complete(client(UpdateUsernameRequest('new_username')))
Updating your profile photo Updating your profile photo
@ -65,6 +68,6 @@ through :tl:`UploadProfilePhoto`:
from telethon.tl.functions.photos import UploadProfilePhotoRequest from telethon.tl.functions.photos import UploadProfilePhotoRequest
client(UploadProfilePhotoRequest( loop.run_until_complete(client(UploadProfilePhotoRequest(
client.upload_file('/path/to/some/file') client.upload_file('/path/to/some/file')
)) )))

View File

@ -13,38 +13,39 @@ Forwarding messages
.. note:: .. note::
Use the `telethon.telegram_client.TelegramClient.forward_messages` Use the `telethon.client.messages.MessageMethods.forward_messages`
friendly method instead unless you have a better reason not to! friendly method instead unless you have a better reason not to!
This method automatically accepts either a single message or many of them. This method automatically accepts either a single message or many of them.
.. code-block:: python .. code-block:: python
# If you only have the message IDs async def main():
client.forward_messages( # If you only have the message IDs
entity, # to which entity you are forwarding the messages await client.forward_messages(
message_ids, # the IDs of the messages (or message) to forward entity, # to which entity you are forwarding the messages
from_entity # who sent the messages? message_ids, # the IDs of the messages (or message) to forward
) from_entity # who sent the messages?
)
# If you have ``Message`` objects # If you have ``Message`` objects
client.forward_messages( await client.forward_messages(
entity, # to which entity you are forwarding the messages entity, # to which entity you are forwarding the messages
messages # the messages (or message) to forward messages # the messages (or message) to forward
) )
# You can also do it manually if you prefer # You can also do it manually if you prefer
from telethon.tl.functions.messages import ForwardMessagesRequest from telethon.tl.functions.messages import ForwardMessagesRequest
messages = foo() # retrieve a few messages (or even one, in a list) messages = foo() # retrieve a few messages (or even one, in a list)
from_entity = bar() from_entity = bar()
to_entity = baz() to_entity = baz()
client(ForwardMessagesRequest( await client(ForwardMessagesRequest(
from_peer=from_entity, # who sent these messages? from_peer=from_entity, # who sent these messages?
id=[msg.id for msg in messages], # which are the messages? id=[msg.id for msg in messages], # which are the messages?
to_peer=to_entity # who are we forwarding them to? to_peer=to_entity # who are we forwarding them to?
)) ))
The named arguments are there for clarity, although they're not needed because The named arguments are there for clarity, although they're not needed because
they appear in order. You can obviously just wrap a single message on the list they appear in order. You can obviously just wrap a single message on the list
@ -56,7 +57,7 @@ Searching Messages
.. note:: .. note::
Use the `telethon.telegram_client.TelegramClient.iter_messages` Use the `telethon.client.messages.MessageMethods.iter_messages`
friendly method instead unless you have a better reason not to! friendly method instead unless you have a better reason not to!
This method has ``search`` and ``filter`` parameters that will This method has ``search`` and ``filter`` parameters that will
@ -71,7 +72,7 @@ into issues_. A valid example would be:
from telethon.tl.types import InputMessagesFilterEmpty from telethon.tl.types import InputMessagesFilterEmpty
filter = InputMessagesFilterEmpty() filter = InputMessagesFilterEmpty()
result = client(SearchRequest( result = loop.run_until_complete(client(SearchRequest(
peer=peer, # On which chat/conversation peer=peer, # On which chat/conversation
q='query', # What to search for q='query', # What to search for
filter=filter, # Filter to use (maybe filter for media) filter=filter, # Filter to use (maybe filter for media)
@ -84,7 +85,7 @@ into issues_. A valid example would be:
min_id=0, # Minimum message ID min_id=0, # Minimum message ID
from_id=None, # Who must have sent the message (peer) from_id=None, # Who must have sent the message (peer)
hash=0 # Special number to return nothing on no-change hash=0 # Special number to return nothing on no-change
)) )))
It's important to note that the optional parameter ``from_id`` could have It's important to note that the optional parameter ``from_id`` could have
been omitted (defaulting to ``None``). Changing it to :tl:`InputUserEmpty`, as one been omitted (defaulting to ``None``). Changing it to :tl:`InputUserEmpty`, as one
@ -99,7 +100,7 @@ you tried setting the ``from_id`` filter, and as the error says, you can't
do that. Leave it set to ``None`` and it should work. do that. Leave it set to ``None`` and it should work.
As with every method, make sure you use the right ID/hash combination for As with every method, make sure you use the right ID/hash combination for
your ``InputUser`` or ``InputChat``, or you'll likely run into errors like your :tl:`InputUser` or :tl:`InputChat`, or you'll likely run into errors like
``UserIdInvalidError``. ``UserIdInvalidError``.
@ -115,29 +116,25 @@ send yourself the very first sticker you have:
.. code-block:: python .. code-block:: python
# Get all the sticker sets this user has async def main():
sticker_sets = client(GetAllStickersRequest(0)) # Get all the sticker sets this user has
from telethon.tl.functions.messages import GetAllStickersRequest
sticker_sets = await client(GetAllStickersRequest(0))
# Choose a sticker set # Choose a sticker set
sticker_set = sticker_sets.sets[0] from telethon.tl.functions.messages import GetStickerSetRequest
from telethon.tl.types import InputStickerSetID
sticker_set = sticker_sets.sets[0]
# Get the stickers for this sticker set # Get the stickers for this sticker set
stickers = client(GetStickerSetRequest( stickers = await client(GetStickerSetRequest(
stickerset=InputStickerSetID( stickerset=InputStickerSetID(
id=sticker_set.id, access_hash=sticker_set.access_hash id=sticker_set.id, access_hash=sticker_set.access_hash
)
))
# Stickers are nothing more than files, so send that
client(SendMediaRequest(
peer=client.get_me(),
media=InputMediaDocument(
id=InputDocument(
id=stickers.documents[0].id,
access_hash=stickers.documents[0].access_hash
) )
) ))
))
# Stickers are nothing more than files, so send that
await client.send_file('me', stickers.documents[0])
.. _issues: https://github.com/LonamiWebs/Telethon/issues/215 .. _issues: https://github.com/LonamiWebs/Telethon/issues/215

View File

@ -59,6 +59,11 @@ their methods.
:undoc-members: :undoc-members:
:show-inheritance: :show-inheritance:
.. automodule:: telethon.client.downloads
:members:
:undoc-members:
:show-inheritance:
.. automodule:: telethon.client.uploads .. automodule:: telethon.client.uploads
:members: :members:
:undoc-members: :undoc-members:

View File

@ -22,7 +22,7 @@ FILE_PART_X_MISSING=Part {} of the file is missing from storage
FILE_PART_INVALID=The file part number is invalid FILE_PART_INVALID=The file part number is invalid
FIRSTNAME_INVALID=The first name is invalid FIRSTNAME_INVALID=The first name is invalid
INPUT_METHOD_INVALID=The invoked method does not exist anymore or has never existed INPUT_METHOD_INVALID=The invoked method does not exist anymore or has never existed
INPUT_REQUEST_TOO_LONG=The input request was too long. This may be a bug in the library as it can occur when serializing more bytes than it should (likeappending the vector constructor code at the end of a message) INPUT_REQUEST_TOO_LONG=The input request was too long. This may be a bug in the library as it can occur when serializing more bytes than it should (like appending the vector constructor code at the end of a message)
LASTNAME_INVALID=The last name is invalid LASTNAME_INVALID=The last name is invalid
LIMIT_INVALID=An invalid limit was provided. See https://core.telegram.org/api/files#downloading-files LIMIT_INVALID=An invalid limit was provided. See https://core.telegram.org/api/files#downloading-files
LOCATION_INVALID=The location given for a file was invalid. See https://core.telegram.org/api/files#downloading-files LOCATION_INVALID=The location given for a file was invalid. See https://core.telegram.org/api/files#downloading-files