From 007ab7ca51e644b898c9d30afee622ed437539cb Mon Sep 17 00:00:00 2001 From: Kaylynn Morgan <51037748+kaylynn234@users.noreply.github.com> Date: Tue, 1 Mar 2022 17:00:29 +1100 Subject: [PATCH 01/14] Respect the alignment specified by the image directive --- docs/_static/style.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/_static/style.css b/docs/_static/style.css index e1d218b30816..eec62eb3800d 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -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; } From 17306de9f474d2f92b86dd8a6b7f3d3f0416718e Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Thu, 17 Mar 2022 17:05:53 -0700 Subject: [PATCH 02/14] add wait_for guide --- docs/topics/wait_for.rst | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 docs/topics/wait_for.rst diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst new file mode 100644 index 000000000000..e8c3d5af4e1a --- /dev/null +++ b/docs/topics/wait_for.rst @@ -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` 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 + +.. 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) + + From 34d32739564cc23200fcaf9728eb34b3c9d08b12 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Thu, 17 Mar 2022 21:06:56 -0700 Subject: [PATCH 03/14] typo --- docs/topics/wait_for.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index e8c3d5af4e1a..d50481afbf94 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -9,7 +9,7 @@ When creating commands or handling events, you often find yourself wanting to wa What is ``wait_for``? ~~~~~~~~~~~~~~~~~~~~~ -:meth:`Client.wait_for` 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. +: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 From c4f6872bfa177933dd8381eaa241b178b9749348 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sat, 19 Mar 2022 19:51:11 -0700 Subject: [PATCH 04/14] fix some typos and wording --- docs/topics/wait_for.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index d50481afbf94..68d0614029ec 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -21,13 +21,13 @@ Here is a quick example 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 +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. +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 keyword argument. .. code-block:: python3 :emphasize-lines: 2, 3, 4 @@ -38,8 +38,8 @@ While the example above allows us to wait for an event, this will pass as soon a 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. +In this example, the wait_for will only terminate when the check returns ``True``, in this case when the message author is equal to the original author. +The check function takes the same arguments the event would take, in this case 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. @@ -54,11 +54,10 @@ Sometimes, we only want to wait for a specific amount of time, before timing out 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`. - +We pass the timeout in seconds to the timeout kwarg of wait_for. If the wait_for does not complete successfully within the given time it will be terminated and :class:`asyncio.TimeoutError` will be raised. .. 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. + 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, causing your wait_for to miss the event dispatch. Examples ~~~~~~~~~~~~~~~~~~~~ From 13b3cde29ab5ece28287027ce5f9a470810fa8fe Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sat, 9 Apr 2022 16:24:21 -0700 Subject: [PATCH 05/14] add wording suggestions --- docs/topics/wait_for.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index 68d0614029ec..0d04b0d3a3b2 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -9,7 +9,7 @@ When creating commands or handling events, you often find yourself wanting to wa 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. +:meth:`Client.wait_for` is similar to client.event/listen, however instead of calling a function, it instead halts execution of your code until the event has been dispatched, and returns the data that was in the event. Here is a quick example @@ -18,16 +18,16 @@ Here is a quick example :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!') + msg = await client.wait_for('message') # wait for a message, the wait_for will return the message it finds + await msg.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. +``wait_for`` is commonly used to control code flow, 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 keyword argument. +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`` keyword argument. .. code-block:: python3 :emphasize-lines: 2, 3, 4 @@ -38,8 +38,8 @@ While the example above allows us to wait for an event, this will pass as soon a msg = await client.wait_for('message', check=check) await msg.reply('hello!') -In this example, the wait_for will only terminate when the check returns ``True``, in this case when the message author is equal to the original author. -The check function takes the same arguments the event would take, in this case just ``m``, a message. +In this example, ``wait_for`` will only accept the incoming event and move on when the check returns ``True``, in this case when the message author is equal to the original author. +The check function takes the same arguments the event would take, in this case a paramter named ``m``, which represents a ``discord.Message`` instance. This is similar to `:meth:`Client.on_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. @@ -54,7 +54,7 @@ Sometimes, we only want to wait for a specific amount of time, before timing out else: await msg.reply('hello!') -We pass the timeout in seconds to the timeout kwarg of wait_for. If the wait_for does not complete successfully within the given time it will be terminated and :class:`asyncio.TimeoutError` will be raised. +We pass the timeout in seconds to the ``timeout`` kwarg of wait_for. If the wait_for does not complete successfully within the given time it will be terminated and :class:`asyncio.TimeoutError` will be raised. .. 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, causing your wait_for to miss the event dispatch. From 623b0187e2a3330fcd0e6ce0cba5bd9b2337ff19 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sat, 9 Apr 2022 16:40:36 -0700 Subject: [PATCH 06/14] add closing remarks, typehint examples, and add details for the extra examples --- docs/topics/wait_for.rst | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index 0d04b0d3a3b2..63a499296708 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -18,7 +18,7 @@ Here is a quick example :emphasize-lines: 2 await channel.send('say hi!') - msg = await client.wait_for('message') # wait for a message, the wait_for will return the message it finds + msg: discord.Message = await client.wait_for('message') # wait for a message, the wait_for will return the message it finds await msg.reply('hello!') The key line here is line 2. We are waiting for an event to happen, in this case, a message event. @@ -33,9 +33,9 @@ While the example above allows us to wait for an event, this will pass as soon a :emphasize-lines: 2, 3, 4 await message.channel.send('say hi!') - def check(m): + def check(m: discord.Message): 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) + msg: discord.Message = await client.wait_for('message', check=check) await msg.reply('hello!') In this example, ``wait_for`` will only accept the incoming event and move on when the check returns ``True``, in this case when the message author is equal to the original author. @@ -48,7 +48,7 @@ Sometimes, we only want to wait for a specific amount of time, before timing out await message.channel.send('say hi!') try: - msg = await client.wait_for('message', timeout=5.0) # timeout in seconds. + msg: discord.Message = await client.wait_for('message', timeout=5.0) # timeout in seconds. except asyncio.TimeoutError: await message.channel.send('You did not respond :(') else: @@ -62,19 +62,31 @@ We pass the timeout in seconds to the ``timeout`` kwarg of wait_for. If the wait Examples ~~~~~~~~~~~~~~~~~~~~ Wait for reaction ++++++++++++++++++ .. code-block:: python3 - def check(reaction, user): + def check(reaction: discord.Reaction, user: discord.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) + reaction: discord.Reaction, user: discord.User = await client.wait_for('reaction_add', check = check) await message.channel.send(f'You reacted with {reaction.emoji}!') +Notive the ``reaction`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. +Additionally, the wait_for will now return a tuple of the arguments the event recieved, which we are unwraping when recieving. +This is how it works for *any* event that takes more than one argument, a few examples being ``typing`` or ``message_edit``. + Inline check +++++++++++++ .. code-block:: python3 await client.wait_for('message', check = lambda m: m.author == message.author) +As the check kwarg simply takes a function, we can make it inline by making use of a lambda function + +Closing Remarks +~~~~~~~~~~~~~~~~~~~~ +``wait_for`` is a powerful tool used often to wait for responses in code. The examples above only shows 2 types of ``wait_for``, reactions and messages, but you can wait for any event! A full list of events can be seen here: :ref:`event reference `. + From 1531aca8e9e62f87c6d096fa571565d36c624991 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Tue, 19 Apr 2022 21:42:58 -0700 Subject: [PATCH 07/14] Apply suggestions from code review Co-authored-by: numbermaniac <5206120+numbermaniac@users.noreply.github.com> --- docs/topics/wait_for.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index 63a499296708..ce75cc3d9675 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -39,7 +39,7 @@ While the example above allows us to wait for an event, this will pass as soon a await msg.reply('hello!') In this example, ``wait_for`` will only accept the incoming event and move on when the check returns ``True``, in this case when the message author is equal to the original author. -The check function takes the same arguments the event would take, in this case a paramter named ``m``, which represents a ``discord.Message`` instance. This is similar to `:meth:`Client.on_message`. +The check function takes the same arguments the event would take, in this case a parameter named ``m``, which represents a ``discord.Message`` instance. This is similar to `:meth:`Client.on_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. @@ -72,8 +72,8 @@ Wait for reaction reaction: discord.Reaction, user: discord.User = await client.wait_for('reaction_add', check = check) await message.channel.send(f'You reacted with {reaction.emoji}!') -Notive the ``reaction`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. -Additionally, the wait_for will now return a tuple of the arguments the event recieved, which we are unwraping when recieving. +Notice the ``reaction_add`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. +Additionally, the wait_for will now return a tuple of the arguments the event received, which we are unwrapping when receiving. This is how it works for *any* event that takes more than one argument, a few examples being ``typing`` or ``message_edit``. Inline check @@ -83,7 +83,7 @@ Inline check await client.wait_for('message', check = lambda m: m.author == message.author) -As the check kwarg simply takes a function, we can make it inline by making use of a lambda function +As the ``check`` kwarg simply takes a function, we can make it inline by making use of a lambda function. Closing Remarks ~~~~~~~~~~~~~~~~~~~~ From 9caddeb76bf4585d87c2ab349a48ca4c116f906d Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sat, 23 Apr 2022 14:59:26 -0700 Subject: [PATCH 08/14] Change wording Co-authored-by: numbermaniac <5206120+numbermaniac@users.noreply.github.com> --- docs/topics/wait_for.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index ce75cc3d9675..7234ae712abe 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -87,6 +87,6 @@ As the ``check`` kwarg simply takes a function, we can make it inline by making Closing Remarks ~~~~~~~~~~~~~~~~~~~~ -``wait_for`` is a powerful tool used often to wait for responses in code. The examples above only shows 2 types of ``wait_for``, reactions and messages, but you can wait for any event! A full list of events can be seen here: :ref:`event reference `. +``wait_for`` is a powerful tool used often to wait for responses in code. The examples above show only 2 types of ``wait_for``, reactions and messages, but you can wait for any event! A full list of events can be seen here: :ref:`event reference `. From 927796e719b04648e7132974685226fd2c3c084c Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sat, 28 Oct 2023 07:33:24 -0700 Subject: [PATCH 09/14] Fix syntax error in guide example --- docs/topics/wait_for.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index 7234ae712abe..6b0b7e31fe99 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -69,7 +69,9 @@ Wait for reaction def check(reaction: discord.Reaction, user: discord.User): return user == message.author and reaction.message == message # check that the reaction is on a specific message and by a specific user - reaction: discord.Reaction, user: discord.User = await client.wait_for('reaction_add', check = check) + reaction: discord.Reaction + user: discord.User + reaction, user = await client.wait_for('reaction_add', check = check) await message.channel.send(f'You reacted with {reaction.emoji}!') Notice the ``reaction_add`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. From fc316e86237be434c9578c8c22f29b0ddc11adaa Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:04:16 -0800 Subject: [PATCH 10/14] basic changes in response to teru's review(Somoe of the bigger suggested changes will be added later) --- docs/topics/wait_for.rst | 48 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index 6b0b7e31fe99..d2ec005758d0 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -3,46 +3,50 @@ .. _guide_wait_for: -Waiting For Events +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. - +A common step when creating commands or handling events involves having to wait for an action or user-input. To aid with this, the library offers a special method :meth:`Client.wait_for` to wait for an event in-line instead of having to define a separate event listener. What is ``wait_for``? ~~~~~~~~~~~~~~~~~~~~~ -:meth:`Client.wait_for` is similar to client.event/listen, however instead of calling a function, it instead halts execution of your code until the event has been dispatched, and returns the data that was in the event. - +Similar to callbacks decorated with `@client.event`, :meth:`Client.wait_for` waits for the first event it finds tied to the passed event name (without the `on_` prefix!) and returns the event's arguments. -Here is a quick example +Here is a quick example: .. code-block:: python3 :emphasize-lines: 2 await channel.send('say hi!') - msg: discord.Message = await client.wait_for('message') # wait for a message, the wait_for will return the message it finds + msg = await client.wait_for('message') await msg.reply('hello!') -The key line here is line 2. We are waiting for an event to happen, in this case, a message event. +The key line here is line 2. We are waiting for an event to happen, in this case a message event. After one is recieved, the method will return the message associated with the event. -``wait_for`` is commonly used to control code flow, waiting for message replies or reactions to be added. You can wait for any event you want. +``wait_for`` is commonly used to control code flow, waiting for message replies or reactions to be added. The key takeaway here is any event that works with `@client.event` can also be waited on with this method. 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`` keyword argument. +Whilst the above example shows off waiting for a message, this will return as soon as *any* message is sent. +Oftentimes, we want to narrow it down to a specific message, which we can do by passing a predicate to the ``check`` keyword-argument .. code-block:: python3 :emphasize-lines: 2, 3, 4 await message.channel.send('say hi!') + def check(m: discord.Message): - return m.author == message.author # check that the author is the one who sent the original message + # check that the author is the one who sent the original message + return m.author == message.author + msg: discord.Message = await client.wait_for('message', check=check) await msg.reply('hello!') -In this example, ``wait_for`` will only accept the incoming event and move on when the check returns ``True``, in this case when the message author is equal to the original author. -The check function takes the same arguments the event would take, in this case a parameter named ``m``, which represents a ``discord.Message`` instance. This is similar to `:meth:`Client.on_message`. +In this example, ``wait_for`` will only accept the incoming message when the predicate returns ``True``. +The arguments passed to the predicate match the signature of the corresponding event. +For example, when defining a message event handler we do `async def on_message(message)` - a predicate would similarly be defined with `def check(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. +Likewise, a predicate for `reaction_add` would take `def check(reaction, user)`. +It's common to also include a timeout in addition to a check so our code doesn't potentially end up waiting indefinitely, or to add a limited time window for the author to send a message. .. code-block:: python3 :emphasize-lines: 2, 3, 4, 5 @@ -54,10 +58,10 @@ Sometimes, we only want to wait for a specific amount of time, before timing out else: await msg.reply('hello!') -We pass the timeout in seconds to the ``timeout`` kwarg of wait_for. If the wait_for does not complete successfully within the given time it will be terminated and :class:`asyncio.TimeoutError` will be raised. +We pass the timeout in seconds to the ``timeout`` keyword-argument. Timeouts behave like :meth:`asyncio.wait_for`, so we do the usual `try` and `except`, catching :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, causing your wait_for to miss the event dispatch. + Avoid calling :meth:`Client.wait_for` within a loop to catch events. Due to the nature of async IO, events may be fired between loops, causing the loop to miss events. Examples ~~~~~~~~~~~~~~~~~~~~ @@ -69,23 +73,11 @@ Wait for reaction def check(reaction: discord.Reaction, user: discord.User): return user == message.author and reaction.message == message # check that the reaction is on a specific message and by a specific user - reaction: discord.Reaction - user: discord.User reaction, user = await client.wait_for('reaction_add', check = check) await message.channel.send(f'You reacted with {reaction.emoji}!') Notice the ``reaction_add`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. -Additionally, the wait_for will now return a tuple of the arguments the event received, which we are unwrapping when receiving. -This is how it works for *any* event that takes more than one argument, a few examples being ``typing`` or ``message_edit``. - -Inline check -++++++++++++ - -.. code-block:: python3 - - await client.wait_for('message', check = lambda m: m.author == message.author) -As the ``check`` kwarg simply takes a function, we can make it inline by making use of a lambda function. Closing Remarks ~~~~~~~~~~~~~~~~~~~~ From 57f2e47d588039d2b563007806c450cee485e606 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:04:57 -0800 Subject: [PATCH 11/14] remove extra spaces around equal sign --- docs/topics/wait_for.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/wait_for.rst b/docs/topics/wait_for.rst index d2ec005758d0..8e55e5e7e5a8 100644 --- a/docs/topics/wait_for.rst +++ b/docs/topics/wait_for.rst @@ -73,7 +73,7 @@ Wait for reaction def check(reaction: discord.Reaction, user: discord.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) + reaction, user = await client.wait_for('reaction_add', check=check) await message.channel.send(f'You reacted with {reaction.emoji}!') Notice the ``reaction_add`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. From 36dcd7bc57edc78be58b83ca1915f406c556c243 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:35:36 -0800 Subject: [PATCH 12/14] move location and implement minor changes --- docs/{ => guide}/topics/wait_for.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) rename docs/{ => guide}/topics/wait_for.rst (89%) diff --git a/docs/topics/wait_for.rst b/docs/guide/topics/wait_for.rst similarity index 89% rename from docs/topics/wait_for.rst rename to docs/guide/topics/wait_for.rst index 8e55e5e7e5a8..ff40c35dbfd7 100644 --- a/docs/topics/wait_for.rst +++ b/docs/guide/topics/wait_for.rst @@ -4,11 +4,12 @@ .. _guide_wait_for: Waiting for Events -============================= +================== A common step when creating commands or handling events involves having to wait for an action or user-input. To aid with this, the library offers a special method :meth:`Client.wait_for` to wait for an event in-line instead of having to define a separate event listener. + What is ``wait_for``? ~~~~~~~~~~~~~~~~~~~~~ -Similar to callbacks decorated with `@client.event`, :meth:`Client.wait_for` waits for the first event it finds tied to the passed event name (without the `on_` prefix!) and returns the event's arguments. +Similar to callbacks decorated with ``@client.event``, :meth:`Client.wait_for` waits for the first event it finds tied to the passed event name (without the `on_` prefix!) and returns the event's arguments. Here is a quick example: @@ -42,11 +43,12 @@ Oftentimes, we want to narrow it down to a specific message, which we can do by In this example, ``wait_for`` will only accept the incoming message when the predicate returns ``True``. The arguments passed to the predicate match the signature of the corresponding event. -For example, when defining a message event handler we do `async def on_message(message)` - a predicate would similarly be defined with `def check(message)`. +For example, when defining a message event handler we do ``async def on_message(message)`` - a predicate would similarly be defined with ``def check(message)``. Likewise, a predicate for `reaction_add` would take `def check(reaction, user)`. It's common to also include a timeout in addition to a check so our code doesn't potentially end up waiting indefinitely, or to add a limited time window for the author to send a message. + .. code-block:: python3 :emphasize-lines: 2, 3, 4, 5 @@ -59,12 +61,14 @@ It's common to also include a timeout in addition to a check so our code doesn't await msg.reply('hello!') We pass the timeout in seconds to the ``timeout`` keyword-argument. Timeouts behave like :meth:`asyncio.wait_for`, so we do the usual `try` and `except`, catching :class:`asyncio.TimeoutError`: + .. warning:: Avoid calling :meth:`Client.wait_for` within a loop to catch events. Due to the nature of async IO, events may be fired between loops, causing the loop to miss events. Examples -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~ + Wait for reaction +++++++++++++++++ From f5b0fd8ef9d99f15cc14bf90fd7b4dedbcf2f0e1 Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:14:00 -0800 Subject: [PATCH 13/14] add an example for waiting for a list of events --- docs/guide/topics/wait_for.rst | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/guide/topics/wait_for.rst b/docs/guide/topics/wait_for.rst index ff40c35dbfd7..2561d1778d28 100644 --- a/docs/guide/topics/wait_for.rst +++ b/docs/guide/topics/wait_for.rst @@ -25,7 +25,7 @@ The key line here is line 2. We are waiting for an event to happen, in this case ``wait_for`` is commonly used to control code flow, waiting for message replies or reactions to be added. The key takeaway here is any event that works with `@client.event` can also be waited on with this method. Checks and Timeouts -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ Whilst the above example shows off waiting for a message, this will return as soon as *any* message is sent. Oftentimes, we want to narrow it down to a specific message, which we can do by passing a predicate to the ``check`` keyword-argument @@ -64,12 +64,12 @@ We pass the timeout in seconds to the ``timeout`` keyword-argument. Timeouts beh .. warning:: - Avoid calling :meth:`Client.wait_for` within a loop to catch events. Due to the nature of async IO, events may be fired between loops, causing the loop to miss events. + Avoid calling :meth:`Client.wait_for` within a loop to catch events. Due to the nature of async IO, events may be fired between loops, causing the loop to miss events. See the example for multiple events. Examples ~~~~~~~~ -Wait for reaction +Wait for Reaction +++++++++++++++++ .. code-block:: python3 @@ -81,6 +81,28 @@ Wait for reaction await message.channel.send(f'You reacted with {reaction.emoji}!') Notice the ``reaction_add`` event, unlike the ``message`` event, takes 2 arguments. Thus, the check function takes the same arguments as that, ``reaction, user``. +wait_for will follow the same constraints and nuances as the corresponding event, in this case: :meth:`discord.on_reaction_add`. + +Waiting for Multiple Events ++++++++++++++++++++++++++++ + +.. code-block:: python3 + :emphasize-lines 2, 5, 6, 7 + + participants = [] + + def check(message: discord.Message): + participants.append(message.author) + if len(participants) >= 10: + return True + return False + + await client.wait_for('message', check=check) + + mentions = ', '.join([user.mention for user in particpants]) + await message.channel.send(f'Welcome {mentions}!') + +Instead of creating a new wait_for for every new message, in order to catch all new messages sent, we allow our check function to accept all messages until a condition is met, saving `inside` the check itself. Closing Remarks From 85fe2e97e963730b1d7bf7fbfc5bf79a4f28da7f Mon Sep 17 00:00:00 2001 From: pikaninja <38714028+pikaninja@users.noreply.github.com> Date: Sun, 4 Feb 2024 14:16:46 -0800 Subject: [PATCH 14/14] typo --- docs/guide/topics/wait_for.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/topics/wait_for.rst b/docs/guide/topics/wait_for.rst index 2561d1778d28..f5f879611342 100644 --- a/docs/guide/topics/wait_for.rst +++ b/docs/guide/topics/wait_for.rst @@ -87,7 +87,7 @@ Waiting for Multiple Events +++++++++++++++++++++++++++ .. code-block:: python3 - :emphasize-lines 2, 5, 6, 7 + :emphasize-lines: 2, 5, 6, 7 participants = []