Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] add wait_for guide #7709

Open
wants to merge 14 commits into
base: docs/guide
Choose a base branch
from
9 changes: 9 additions & 0 deletions docs/_static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,15 @@ table.docutils tbody tr td ol.last {
margin-bottom: 0;
}

/* added when the `align` attribute is specified in the `image` directive */
main img.align-left {
margin-left: .5em;
}

main img.align-right {
margin-right: .5em;
}

.align-default {
text-align: left !important;
}
Expand Down
81 changes: 81 additions & 0 deletions docs/topics/wait_for.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
:orphan:
.. currentmodule:: discord

.. _guide_wait_for:

Waiting For Events
=============================
When creating commands or handling events, you often find yourself wanting to wait for an action or user response. In discord.py, we use the :meth:`Client.wait_for` method.

What is ``wait_for``?
~~~~~~~~~~~~~~~~~~~~~
:meth:`Client.wait_for` is similar to client.event/listen, however instead of calling a function, it instead holds execution of your code until the event has been dispatched, and returns the data that was in the event.


Here is a quick example

.. code-block:: python3
:emphasize-lines: 2

await channel.send('say hi!')
message = await client.wait_for('message') # wait for a message, the wait_for will return the message it finds
await message.reply('hello!')

The key line here is line 2. We are waiting for an event to happen, in this case a message event

Wait_for is commonly used to control flow in a code, waiting for message replies or reactions to be added. You can wait for any event you want.

Checks and Timeouts
~~~~~~~~~~~~~~~~~~~~
While the example above allows us to wait for an event, this will pass as soon as *any* event of that type is dispatched. Sometimes, we want to filter it. To do this, we use the check keyward argument.

.. code-block:: python3
:emphasize-lines: 2, 3, 4

await message.channel.send('say hi!')
def check(m):
return m.author == message.author # check that the author is the one who sent the original message
msg = await client.wait_for('message', check=check)
await msg.reply('hello!')

In this example, the wait_for will only terminate after the check returns ``True``, in this case after the message author is equal to the original author.
The check takes the arguments the event would take, in this cause just ``m``, a message.

Sometimes, we only want to wait for a specific amount of time, before timing out the wait_for and allowing the code to continue.

.. code-block:: python3
:emphasize-lines: 2, 3, 4, 5

await message.channel.send('say hi!')
try:
msg = await client.wait_for('message', timeout=5.0) # timeout in seconds.
except asyncio.TimeoutError:
await message.channel.send('You did not respond :(')
else:
await msg.reply('hello!')

We pass the timeout in seconds to the timeout kwarg of wait_for. If the event is not dispatched or the check is not passed in those seconds, the wait_for will terminate and raise :class:`asyncio.TimeoutError`.

.. warning::

avoid using wait_for within a loop to catch events of a specific type. Due to the async nature of discord.py, events may be fired between loops, in return causing your wait_for to miss the event dispatch.

Examples
~~~~~~~~~~~~~~~~~~~~
Wait for reaction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely nitpicky but I feel this could link to the documentation pages for on_reaction_add and mention the raw variant too.

No need for an explanation of raw vs not, just linking them would be good so people can "avoid" the message needing to be in cache to catch a full Reaction.


.. code-block:: python3

def check(reaction, user):
return user == message.author and reaction.message == message # check that the reaction is on a specific message and by a specific user

reaction, user = await client.wait_for('reaction_add', check = check)
await message.channel.send(f'You reacted with {reaction.emoji}!')

Inline check

.. code-block:: python3

await client.wait_for('message', check = lambda m: m.author == message.author)