We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add file output for code evaluation commands & Better long output handling
### What component of Red (cog, command, API) would you like to see improvements on?

Dev

### Describe the enhancement you're suggesting.

Currently when evaluating code with a large response, it would be shown in multiple messages. (when typing more)

Dropping a file would be way more convenient. 

Furthermore instead of typing more, a button will be nice. When clicking the button, the button disappears and a new message with a new button appears. (if there is further output)

### Anything else?

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `redbot/core/commands/context.py`
Content:
```
1 from __future__ import annotations
2 
3 import asyncio
4 import contextlib
5 import os
6 import re
7 from typing import Iterable, List, Union, Optional, TYPE_CHECKING
8 import discord
9 from discord.ext.commands import Context as DPYContext
10 
11 from .requires import PermState
12 from ..utils.chat_formatting import box
13 from ..utils.predicates import MessagePredicate
14 from ..utils import can_user_react_in, common_filters
15 
16 if TYPE_CHECKING:
17     from .commands import Command
18     from ..bot import Red
19 
20 TICK = "\N{WHITE HEAVY CHECK MARK}"
21 
22 __all__ = ["Context", "GuildContext", "DMContext"]
23 
24 
25 class Context(DPYContext):
26     """Command invocation context for Red.
27 
28     All context passed into commands will be of this type.
29 
30     This class inherits from `discord.ext.commands.Context`.
31 
32     Attributes
33     ----------
34     assume_yes: bool
35         Whether or not interactive checks should
36         be skipped and assumed to be confirmed.
37 
38         This is intended for allowing automation of tasks.
39 
40         An example of this would be scheduled commands
41         not requiring interaction if the cog developer
42         checks this value prior to confirming something interactively.
43 
44         Depending on the potential impact of a command,
45         it may still be appropriate not to use this setting.
46     permission_state: PermState
47         The permission state the current context is in.
48     """
49 
50     command: "Command"
51     invoked_subcommand: "Optional[Command]"
52     bot: "Red"
53 
54     def __init__(self, **attrs):
55         self.assume_yes = attrs.pop("assume_yes", False)
56         super().__init__(**attrs)
57         self.permission_state: PermState = PermState.NORMAL
58 
59     async def send(self, content=None, **kwargs):
60         """Sends a message to the destination with the content given.
61 
62         This acts the same as `discord.ext.commands.Context.send`, with
63         one added keyword argument as detailed below in *Other Parameters*.
64 
65         Parameters
66         ----------
67         content : str
68             The content of the message to send.
69 
70         Other Parameters
71         ----------------
72         filter : callable (`str`) -> `str`, optional
73             A function which is used to filter the ``content`` before
74             it is sent.
75             This must take a single `str` as an argument, and return
76             the processed `str`. When `None` is passed, ``content`` won't be touched.
77             Defaults to `None`.
78         **kwargs
79             See `discord.ext.commands.Context.send`.
80 
81         Returns
82         -------
83         discord.Message
84             The message that was sent.
85 
86         """
87 
88         _filter = kwargs.pop("filter", None)
89 
90         if _filter and content:
91             content = _filter(str(content))
92 
93         return await super().send(content=content, **kwargs)
94 
95     async def send_help(self, command=None):
96         """Send the command help message."""
97         # This allows people to manually use this similarly
98         # to the upstream d.py version, while retaining our use.
99         command = command or self.command
100         await self.bot.send_help_for(self, command)
101 
102     async def tick(self, *, message: Optional[str] = None) -> bool:
103         """Add a tick reaction to the command message.
104 
105         Keyword Arguments
106         -----------------
107         message : str, optional
108             The message to send if adding the reaction doesn't succeed.
109 
110         Returns
111         -------
112         bool
113             :code:`True` if adding the reaction succeeded.
114 
115         """
116         return await self.react_quietly(TICK, message=message)
117 
118     async def react_quietly(
119         self,
120         reaction: Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str],
121         *,
122         message: Optional[str] = None,
123     ) -> bool:
124         """Adds a reaction to the command message.
125 
126         Parameters
127         ----------
128         reaction : Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str]
129             The emoji to react with.
130 
131         Keyword Arguments
132         -----------------
133         message : str, optional
134             The message to send if adding the reaction doesn't succeed.
135 
136         Returns
137         -------
138         bool
139             :code:`True` if adding the reaction succeeded.
140         """
141         try:
142             if not can_user_react_in(self.me, self.channel):
143                 raise RuntimeError
144             await self.message.add_reaction(reaction)
145         except (RuntimeError, discord.HTTPException):
146             if message is not None:
147                 await self.send(message)
148             return False
149         else:
150             return True
151 
152     async def send_interactive(
153         self, messages: Iterable[str], box_lang: str = None, timeout: int = 15
154     ) -> List[discord.Message]:
155         """Send multiple messages interactively.
156 
157         The user will be prompted for whether or not they would like to view
158         the next message, one at a time. They will also be notified of how
159         many messages are remaining on each prompt.
160 
161         Parameters
162         ----------
163         messages : `iterable` of `str`
164             The messages to send.
165         box_lang : str
166             If specified, each message will be contained within a codeblock of
167             this language.
168         timeout : int
169             How long the user has to respond to the prompt before it times out.
170             After timing out, the bot deletes its prompt message.
171 
172         """
173         messages = tuple(messages)
174         ret = []
175 
176         for idx, page in enumerate(messages, 1):
177             if box_lang is None:
178                 msg = await self.send(page)
179             else:
180                 msg = await self.send(box(page, lang=box_lang))
181             ret.append(msg)
182             n_remaining = len(messages) - idx
183             if n_remaining > 0:
184                 if n_remaining == 1:
185                     plural = ""
186                     is_are = "is"
187                 else:
188                     plural = "s"
189                     is_are = "are"
190                 query = await self.send(
191                     "There {} still {} message{} remaining. "
192                     "Type `more` to continue."
193                     "".format(is_are, n_remaining, plural)
194                 )
195                 try:
196                     resp = await self.bot.wait_for(
197                         "message",
198                         check=MessagePredicate.lower_equal_to("more", self),
199                         timeout=timeout,
200                     )
201                 except asyncio.TimeoutError:
202                     with contextlib.suppress(discord.HTTPException):
203                         await query.delete()
204                     break
205                 else:
206                     try:
207                         await self.channel.delete_messages((query, resp))
208                     except (discord.HTTPException, AttributeError):
209                         # In case the bot can't delete other users' messages,
210                         # or is not a bot account
211                         # or channel is a DM
212                         with contextlib.suppress(discord.HTTPException):
213                             await query.delete()
214         return ret
215 
216     async def embed_colour(self):
217         """
218         Helper function to get the colour for an embed.
219 
220         Returns
221         -------
222         discord.Colour:
223             The colour to be used
224         """
225         return await self.bot.get_embed_color(self)
226 
227     @property
228     def embed_color(self):
229         # Rather than double awaiting.
230         return self.embed_colour
231 
232     async def embed_requested(self):
233         """
234         Short-hand for calling bot.embed_requested with permission checks.
235 
236         Equivalent to:
237 
238         .. code:: python
239 
240             await ctx.bot.embed_requested(ctx)
241 
242         Returns
243         -------
244         bool:
245             :code:`True` if an embed is requested
246         """
247         return await self.bot.embed_requested(self)
248 
249     async def maybe_send_embed(self, message: str) -> discord.Message:
250         """
251         Simple helper to send a simple message to context
252         without manually checking ctx.embed_requested
253         This should only be used for simple messages.
254 
255         Parameters
256         ----------
257         message: `str`
258             The string to send
259 
260         Returns
261         -------
262         discord.Message:
263             the message which was sent
264 
265         Raises
266         ------
267         discord.Forbidden
268             see `discord.abc.Messageable.send`
269         discord.HTTPException
270             see `discord.abc.Messageable.send`
271         ValueError
272             when the message's length is not between 1 and 2000 characters.
273         """
274         if not message or len(message) > 2000:
275             raise ValueError("Message length must be between 1 and 2000")
276         if await self.embed_requested():
277             return await self.send(
278                 embed=discord.Embed(description=message, color=(await self.embed_colour()))
279             )
280         else:
281             return await self.send(
282                 message,
283                 allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False),
284             )
285 
286     @property
287     def me(self) -> Union[discord.ClientUser, discord.Member]:
288         """
289         discord.abc.User: The bot member or user object.
290 
291         If the context is DM, this will be a `discord.User` object.
292         """
293         if self.guild is not None:
294             return self.guild.me
295         else:
296             return self.bot.user
297 
298 
299 if TYPE_CHECKING or os.getenv("BUILDING_DOCS", False):
300 
301     class DMContext(Context):
302         """
303         At runtime, this will still be a normal context object.
304 
305         This lies about some type narrowing for type analysis in commands
306         using a dm_only decorator.
307 
308         It is only correct to use when those types are already narrowed
309         """
310 
311         @property
312         def author(self) -> discord.User:
313             ...
314 
315         @property
316         def channel(self) -> discord.DMChannel:
317             ...
318 
319         @property
320         def guild(self) -> None:
321             ...
322 
323         @property
324         def me(self) -> discord.ClientUser:
325             ...
326 
327     class GuildContext(Context):
328         """
329         At runtime, this will still be a normal context object.
330 
331         This lies about some type narrowing for type analysis in commands
332         using a guild_only decorator.
333 
334         It is only correct to use when those types are already narrowed
335         """
336 
337         @property
338         def author(self) -> discord.Member:
339             ...
340 
341         @property
342         def channel(self) -> Union[discord.TextChannel, discord.VoiceChannel, discord.Thread]:
343             ...
344 
345         @property
346         def guild(self) -> discord.Guild:
347             ...
348 
349         @property
350         def me(self) -> discord.Member:
351             ...
352 
353 else:
354     GuildContext = Context
355     DMContext = Context
356
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/redbot/core/commands/context.py b/redbot/core/commands/context.py
--- a/redbot/core/commands/context.py
+++ b/redbot/core/commands/context.py
@@ -9,7 +9,7 @@
 from discord.ext.commands import Context as DPYContext
 
 from .requires import PermState
-from ..utils.chat_formatting import box
+from ..utils.chat_formatting import box, text_to_file
 from ..utils.predicates import MessagePredicate
 from ..utils import can_user_react_in, common_filters
 
@@ -150,7 +150,11 @@
             return True
 
     async def send_interactive(
-        self, messages: Iterable[str], box_lang: str = None, timeout: int = 15
+        self,
+        messages: Iterable[str],
+        box_lang: str = None,
+        timeout: int = 15,
+        join_character: str = "",
     ) -> List[discord.Message]:
         """Send multiple messages interactively.
 
@@ -168,6 +172,9 @@
         timeout : int
             How long the user has to respond to the prompt before it times out.
             After timing out, the bot deletes its prompt message.
+        join_character : str
+            The character used to join all the messages when the file output
+            is selected.
 
         """
         messages = tuple(messages)
@@ -189,13 +196,14 @@
                     is_are = "are"
                 query = await self.send(
                     "There {} still {} message{} remaining. "
-                    "Type `more` to continue."
+                    "Type `more` to continue or `file` to upload all contents as a file."
                     "".format(is_are, n_remaining, plural)
                 )
+                pred = MessagePredicate.lower_contained_in(("more", "file"), self)
                 try:
                     resp = await self.bot.wait_for(
                         "message",
-                        check=MessagePredicate.lower_equal_to("more", self),
+                        check=pred,
                         timeout=timeout,
                     )
                 except asyncio.TimeoutError:
@@ -211,6 +219,9 @@
                         # or channel is a DM
                         with contextlib.suppress(discord.HTTPException):
                             await query.delete()
+                    if pred.result == 1:
+                        await self.send(file=text_to_file(join_character.join(messages)))
+                        break
         return ret
 
     async def embed_colour(self):

{"golden_diff": "diff --git a/redbot/core/commands/context.py b/redbot/core/commands/context.py\n--- a/redbot/core/commands/context.py\n+++ b/redbot/core/commands/context.py\n@@ -9,7 +9,7 @@\n from discord.ext.commands import Context as DPYContext\n \n from .requires import PermState\n-from ..utils.chat_formatting import box\n+from ..utils.chat_formatting import box, text_to_file\n from ..utils.predicates import MessagePredicate\n from ..utils import can_user_react_in, common_filters\n \n@@ -150,7 +150,11 @@\n             return True\n \n     async def send_interactive(\n-        self, messages: Iterable[str], box_lang: str = None, timeout: int = 15\n+        self,\n+        messages: Iterable[str],\n+        box_lang: str = None,\n+        timeout: int = 15,\n+        join_character: str = \"\",\n     ) -> List[discord.Message]:\n         \"\"\"Send multiple messages interactively.\n \n@@ -168,6 +172,9 @@\n         timeout : int\n             How long the user has to respond to the prompt before it times out.\n             After timing out, the bot deletes its prompt message.\n+        join_character : str\n+            The character used to join all the messages when the file output\n+            is selected.\n \n         \"\"\"\n         messages = tuple(messages)\n@@ -189,13 +196,14 @@\n                     is_are = \"are\"\n                 query = await self.send(\n                     \"There {} still {} message{} remaining. \"\n-                    \"Type `more` to continue.\"\n+                    \"Type `more` to continue or `file` to upload all contents as a file.\"\n                     \"\".format(is_are, n_remaining, plural)\n                 )\n+                pred = MessagePredicate.lower_contained_in((\"more\", \"file\"), self)\n                 try:\n                     resp = await self.bot.wait_for(\n                         \"message\",\n-                        check=MessagePredicate.lower_equal_to(\"more\", self),\n+                        check=pred,\n                         timeout=timeout,\n                     )\n                 except asyncio.TimeoutError:\n@@ -211,6 +219,9 @@\n                         # or channel is a DM\n                         with contextlib.suppress(discord.HTTPException):\n                             await query.delete()\n+                    if pred.result == 1:\n+                        await self.send(file=text_to_file(join_character.join(messages)))\n+                        break\n         return ret\n \n     async def embed_colour(self):\n", "issue": "Add file output for code evaluation commands & Better long output handling\n### What component of Red (cog, command, API) would you like to see improvements on?\n\nDev\n\n### Describe the enhancement you're suggesting.\n\nCurrently when evaluating code with a large response, it would be shown in multiple messages. (when typing more)\r\n\r\nDropping a file would be way more convenient. \r\n\r\nFurthermore instead of typing more, a button will be nice. When clicking the button, the button disappears and a new message with a new button appears. (if there is further output)\n\n### Anything else?\n\n_No response_\n", "before_files": [{"content": "from __future__ import annotations\n\nimport asyncio\nimport contextlib\nimport os\nimport re\nfrom typing import Iterable, List, Union, Optional, TYPE_CHECKING\nimport discord\nfrom discord.ext.commands import Context as DPYContext\n\nfrom .requires import PermState\nfrom ..utils.chat_formatting import box\nfrom ..utils.predicates import MessagePredicate\nfrom ..utils import can_user_react_in, common_filters\n\nif TYPE_CHECKING:\n    from .commands import Command\n    from ..bot import Red\n\nTICK = \"\\N{WHITE HEAVY CHECK MARK}\"\n\n__all__ = [\"Context\", \"GuildContext\", \"DMContext\"]\n\n\nclass Context(DPYContext):\n    \"\"\"Command invocation context for Red.\n\n    All context passed into commands will be of this type.\n\n    This class inherits from `discord.ext.commands.Context`.\n\n    Attributes\n    ----------\n    assume_yes: bool\n        Whether or not interactive checks should\n        be skipped and assumed to be confirmed.\n\n        This is intended for allowing automation of tasks.\n\n        An example of this would be scheduled commands\n        not requiring interaction if the cog developer\n        checks this value prior to confirming something interactively.\n\n        Depending on the potential impact of a command,\n        it may still be appropriate not to use this setting.\n    permission_state: PermState\n        The permission state the current context is in.\n    \"\"\"\n\n    command: \"Command\"\n    invoked_subcommand: \"Optional[Command]\"\n    bot: \"Red\"\n\n    def __init__(self, **attrs):\n        self.assume_yes = attrs.pop(\"assume_yes\", False)\n        super().__init__(**attrs)\n        self.permission_state: PermState = PermState.NORMAL\n\n    async def send(self, content=None, **kwargs):\n        \"\"\"Sends a message to the destination with the content given.\n\n        This acts the same as `discord.ext.commands.Context.send`, with\n        one added keyword argument as detailed below in *Other Parameters*.\n\n        Parameters\n        ----------\n        content : str\n            The content of the message to send.\n\n        Other Parameters\n        ----------------\n        filter : callable (`str`) -> `str`, optional\n            A function which is used to filter the ``content`` before\n            it is sent.\n            This must take a single `str` as an argument, and return\n            the processed `str`. When `None` is passed, ``content`` won't be touched.\n            Defaults to `None`.\n        **kwargs\n            See `discord.ext.commands.Context.send`.\n\n        Returns\n        -------\n        discord.Message\n            The message that was sent.\n\n        \"\"\"\n\n        _filter = kwargs.pop(\"filter\", None)\n\n        if _filter and content:\n            content = _filter(str(content))\n\n        return await super().send(content=content, **kwargs)\n\n    async def send_help(self, command=None):\n        \"\"\"Send the command help message.\"\"\"\n        # This allows people to manually use this similarly\n        # to the upstream d.py version, while retaining our use.\n        command = command or self.command\n        await self.bot.send_help_for(self, command)\n\n    async def tick(self, *, message: Optional[str] = None) -> bool:\n        \"\"\"Add a tick reaction to the command message.\n\n        Keyword Arguments\n        -----------------\n        message : str, optional\n            The message to send if adding the reaction doesn't succeed.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n\n        \"\"\"\n        return await self.react_quietly(TICK, message=message)\n\n    async def react_quietly(\n        self,\n        reaction: Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str],\n        *,\n        message: Optional[str] = None,\n    ) -> bool:\n        \"\"\"Adds a reaction to the command message.\n\n        Parameters\n        ----------\n        reaction : Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str]\n            The emoji to react with.\n\n        Keyword Arguments\n        -----------------\n        message : str, optional\n            The message to send if adding the reaction doesn't succeed.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n        \"\"\"\n        try:\n            if not can_user_react_in(self.me, self.channel):\n                raise RuntimeError\n            await self.message.add_reaction(reaction)\n        except (RuntimeError, discord.HTTPException):\n            if message is not None:\n                await self.send(message)\n            return False\n        else:\n            return True\n\n    async def send_interactive(\n        self, messages: Iterable[str], box_lang: str = None, timeout: int = 15\n    ) -> List[discord.Message]:\n        \"\"\"Send multiple messages interactively.\n\n        The user will be prompted for whether or not they would like to view\n        the next message, one at a time. They will also be notified of how\n        many messages are remaining on each prompt.\n\n        Parameters\n        ----------\n        messages : `iterable` of `str`\n            The messages to send.\n        box_lang : str\n            If specified, each message will be contained within a codeblock of\n            this language.\n        timeout : int\n            How long the user has to respond to the prompt before it times out.\n            After timing out, the bot deletes its prompt message.\n\n        \"\"\"\n        messages = tuple(messages)\n        ret = []\n\n        for idx, page in enumerate(messages, 1):\n            if box_lang is None:\n                msg = await self.send(page)\n            else:\n                msg = await self.send(box(page, lang=box_lang))\n            ret.append(msg)\n            n_remaining = len(messages) - idx\n            if n_remaining > 0:\n                if n_remaining == 1:\n                    plural = \"\"\n                    is_are = \"is\"\n                else:\n                    plural = \"s\"\n                    is_are = \"are\"\n                query = await self.send(\n                    \"There {} still {} message{} remaining. \"\n                    \"Type `more` to continue.\"\n                    \"\".format(is_are, n_remaining, plural)\n                )\n                try:\n                    resp = await self.bot.wait_for(\n                        \"message\",\n                        check=MessagePredicate.lower_equal_to(\"more\", self),\n                        timeout=timeout,\n                    )\n                except asyncio.TimeoutError:\n                    with contextlib.suppress(discord.HTTPException):\n                        await query.delete()\n                    break\n                else:\n                    try:\n                        await self.channel.delete_messages((query, resp))\n                    except (discord.HTTPException, AttributeError):\n                        # In case the bot can't delete other users' messages,\n                        # or is not a bot account\n                        # or channel is a DM\n                        with contextlib.suppress(discord.HTTPException):\n                            await query.delete()\n        return ret\n\n    async def embed_colour(self):\n        \"\"\"\n        Helper function to get the colour for an embed.\n\n        Returns\n        -------\n        discord.Colour:\n            The colour to be used\n        \"\"\"\n        return await self.bot.get_embed_color(self)\n\n    @property\n    def embed_color(self):\n        # Rather than double awaiting.\n        return self.embed_colour\n\n    async def embed_requested(self):\n        \"\"\"\n        Short-hand for calling bot.embed_requested with permission checks.\n\n        Equivalent to:\n\n        .. code:: python\n\n            await ctx.bot.embed_requested(ctx)\n\n        Returns\n        -------\n        bool:\n            :code:`True` if an embed is requested\n        \"\"\"\n        return await self.bot.embed_requested(self)\n\n    async def maybe_send_embed(self, message: str) -> discord.Message:\n        \"\"\"\n        Simple helper to send a simple message to context\n        without manually checking ctx.embed_requested\n        This should only be used for simple messages.\n\n        Parameters\n        ----------\n        message: `str`\n            The string to send\n\n        Returns\n        -------\n        discord.Message:\n            the message which was sent\n\n        Raises\n        ------\n        discord.Forbidden\n            see `discord.abc.Messageable.send`\n        discord.HTTPException\n            see `discord.abc.Messageable.send`\n        ValueError\n            when the message's length is not between 1 and 2000 characters.\n        \"\"\"\n        if not message or len(message) > 2000:\n            raise ValueError(\"Message length must be between 1 and 2000\")\n        if await self.embed_requested():\n            return await self.send(\n                embed=discord.Embed(description=message, color=(await self.embed_colour()))\n            )\n        else:\n            return await self.send(\n                message,\n                allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False),\n            )\n\n    @property\n    def me(self) -> Union[discord.ClientUser, discord.Member]:\n        \"\"\"\n        discord.abc.User: The bot member or user object.\n\n        If the context is DM, this will be a `discord.User` object.\n        \"\"\"\n        if self.guild is not None:\n            return self.guild.me\n        else:\n            return self.bot.user\n\n\nif TYPE_CHECKING or os.getenv(\"BUILDING_DOCS\", False):\n\n    class DMContext(Context):\n        \"\"\"\n        At runtime, this will still be a normal context object.\n\n        This lies about some type narrowing for type analysis in commands\n        using a dm_only decorator.\n\n        It is only correct to use when those types are already narrowed\n        \"\"\"\n\n        @property\n        def author(self) -> discord.User:\n            ...\n\n        @property\n        def channel(self) -> discord.DMChannel:\n            ...\n\n        @property\n        def guild(self) -> None:\n            ...\n\n        @property\n        def me(self) -> discord.ClientUser:\n            ...\n\n    class GuildContext(Context):\n        \"\"\"\n        At runtime, this will still be a normal context object.\n\n        This lies about some type narrowing for type analysis in commands\n        using a guild_only decorator.\n\n        It is only correct to use when those types are already narrowed\n        \"\"\"\n\n        @property\n        def author(self) -> discord.Member:\n            ...\n\n        @property\n        def channel(self) -> Union[discord.TextChannel, discord.VoiceChannel, discord.Thread]:\n            ...\n\n        @property\n        def guild(self) -> discord.Guild:\n            ...\n\n        @property\n        def me(self) -> discord.Member:\n            ...\n\nelse:\n    GuildContext = Context\n    DMContext = Context\n", "path": "redbot/core/commands/context.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport asyncio\nimport contextlib\nimport os\nimport re\nfrom typing import Iterable, List, Union, Optional, TYPE_CHECKING\nimport discord\nfrom discord.ext.commands import Context as DPYContext\n\nfrom .requires import PermState\nfrom ..utils.chat_formatting import box, text_to_file\nfrom ..utils.predicates import MessagePredicate\nfrom ..utils import can_user_react_in, common_filters\n\nif TYPE_CHECKING:\n    from .commands import Command\n    from ..bot import Red\n\nTICK = \"\\N{WHITE HEAVY CHECK MARK}\"\n\n__all__ = [\"Context\", \"GuildContext\", \"DMContext\"]\n\n\nclass Context(DPYContext):\n    \"\"\"Command invocation context for Red.\n\n    All context passed into commands will be of this type.\n\n    This class inherits from `discord.ext.commands.Context`.\n\n    Attributes\n    ----------\n    assume_yes: bool\n        Whether or not interactive checks should\n        be skipped and assumed to be confirmed.\n\n        This is intended for allowing automation of tasks.\n\n        An example of this would be scheduled commands\n        not requiring interaction if the cog developer\n        checks this value prior to confirming something interactively.\n\n        Depending on the potential impact of a command,\n        it may still be appropriate not to use this setting.\n    permission_state: PermState\n        The permission state the current context is in.\n    \"\"\"\n\n    command: \"Command\"\n    invoked_subcommand: \"Optional[Command]\"\n    bot: \"Red\"\n\n    def __init__(self, **attrs):\n        self.assume_yes = attrs.pop(\"assume_yes\", False)\n        super().__init__(**attrs)\n        self.permission_state: PermState = PermState.NORMAL\n\n    async def send(self, content=None, **kwargs):\n        \"\"\"Sends a message to the destination with the content given.\n\n        This acts the same as `discord.ext.commands.Context.send`, with\n        one added keyword argument as detailed below in *Other Parameters*.\n\n        Parameters\n        ----------\n        content : str\n            The content of the message to send.\n\n        Other Parameters\n        ----------------\n        filter : callable (`str`) -> `str`, optional\n            A function which is used to filter the ``content`` before\n            it is sent.\n            This must take a single `str` as an argument, and return\n            the processed `str`. When `None` is passed, ``content`` won't be touched.\n            Defaults to `None`.\n        **kwargs\n            See `discord.ext.commands.Context.send`.\n\n        Returns\n        -------\n        discord.Message\n            The message that was sent.\n\n        \"\"\"\n\n        _filter = kwargs.pop(\"filter\", None)\n\n        if _filter and content:\n            content = _filter(str(content))\n\n        return await super().send(content=content, **kwargs)\n\n    async def send_help(self, command=None):\n        \"\"\"Send the command help message.\"\"\"\n        # This allows people to manually use this similarly\n        # to the upstream d.py version, while retaining our use.\n        command = command or self.command\n        await self.bot.send_help_for(self, command)\n\n    async def tick(self, *, message: Optional[str] = None) -> bool:\n        \"\"\"Add a tick reaction to the command message.\n\n        Keyword Arguments\n        -----------------\n        message : str, optional\n            The message to send if adding the reaction doesn't succeed.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n\n        \"\"\"\n        return await self.react_quietly(TICK, message=message)\n\n    async def react_quietly(\n        self,\n        reaction: Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str],\n        *,\n        message: Optional[str] = None,\n    ) -> bool:\n        \"\"\"Adds a reaction to the command message.\n\n        Parameters\n        ----------\n        reaction : Union[discord.Emoji, discord.Reaction, discord.PartialEmoji, str]\n            The emoji to react with.\n\n        Keyword Arguments\n        -----------------\n        message : str, optional\n            The message to send if adding the reaction doesn't succeed.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n        \"\"\"\n        try:\n            if not can_user_react_in(self.me, self.channel):\n                raise RuntimeError\n            await self.message.add_reaction(reaction)\n        except (RuntimeError, discord.HTTPException):\n            if message is not None:\n                await self.send(message)\n            return False\n        else:\n            return True\n\n    async def send_interactive(\n        self,\n        messages: Iterable[str],\n        box_lang: str = None,\n        timeout: int = 15,\n        join_character: str = \"\",\n    ) -> List[discord.Message]:\n        \"\"\"Send multiple messages interactively.\n\n        The user will be prompted for whether or not they would like to view\n        the next message, one at a time. They will also be notified of how\n        many messages are remaining on each prompt.\n\n        Parameters\n        ----------\n        messages : `iterable` of `str`\n            The messages to send.\n        box_lang : str\n            If specified, each message will be contained within a codeblock of\n            this language.\n        timeout : int\n            How long the user has to respond to the prompt before it times out.\n            After timing out, the bot deletes its prompt message.\n        join_character : str\n            The character used to join all the messages when the file output\n            is selected.\n\n        \"\"\"\n        messages = tuple(messages)\n        ret = []\n\n        for idx, page in enumerate(messages, 1):\n            if box_lang is None:\n                msg = await self.send(page)\n            else:\n                msg = await self.send(box(page, lang=box_lang))\n            ret.append(msg)\n            n_remaining = len(messages) - idx\n            if n_remaining > 0:\n                if n_remaining == 1:\n                    plural = \"\"\n                    is_are = \"is\"\n                else:\n                    plural = \"s\"\n                    is_are = \"are\"\n                query = await self.send(\n                    \"There {} still {} message{} remaining. \"\n                    \"Type `more` to continue or `file` to upload all contents as a file.\"\n                    \"\".format(is_are, n_remaining, plural)\n                )\n                pred = MessagePredicate.lower_contained_in((\"more\", \"file\"), self)\n                try:\n                    resp = await self.bot.wait_for(\n                        \"message\",\n                        check=pred,\n                        timeout=timeout,\n                    )\n                except asyncio.TimeoutError:\n                    with contextlib.suppress(discord.HTTPException):\n                        await query.delete()\n                    break\n                else:\n                    try:\n                        await self.channel.delete_messages((query, resp))\n                    except (discord.HTTPException, AttributeError):\n                        # In case the bot can't delete other users' messages,\n                        # or is not a bot account\n                        # or channel is a DM\n                        with contextlib.suppress(discord.HTTPException):\n                            await query.delete()\n                    if pred.result == 1:\n                        await self.send(file=text_to_file(join_character.join(messages)))\n                        break\n        return ret\n\n    async def embed_colour(self):\n        \"\"\"\n        Helper function to get the colour for an embed.\n\n        Returns\n        -------\n        discord.Colour:\n            The colour to be used\n        \"\"\"\n        return await self.bot.get_embed_color(self)\n\n    @property\n    def embed_color(self):\n        # Rather than double awaiting.\n        return self.embed_colour\n\n    async def embed_requested(self):\n        \"\"\"\n        Short-hand for calling bot.embed_requested with permission checks.\n\n        Equivalent to:\n\n        .. code:: python\n\n            await ctx.bot.embed_requested(ctx)\n\n        Returns\n        -------\n        bool:\n            :code:`True` if an embed is requested\n        \"\"\"\n        return await self.bot.embed_requested(self)\n\n    async def maybe_send_embed(self, message: str) -> discord.Message:\n        \"\"\"\n        Simple helper to send a simple message to context\n        without manually checking ctx.embed_requested\n        This should only be used for simple messages.\n\n        Parameters\n        ----------\n        message: `str`\n            The string to send\n\n        Returns\n        -------\n        discord.Message:\n            the message which was sent\n\n        Raises\n        ------\n        discord.Forbidden\n            see `discord.abc.Messageable.send`\n        discord.HTTPException\n            see `discord.abc.Messageable.send`\n        ValueError\n            when the message's length is not between 1 and 2000 characters.\n        \"\"\"\n        if not message or len(message) > 2000:\n            raise ValueError(\"Message length must be between 1 and 2000\")\n        if await self.embed_requested():\n            return await self.send(\n                embed=discord.Embed(description=message, color=(await self.embed_colour()))\n            )\n        else:\n            return await self.send(\n                message,\n                allowed_mentions=discord.AllowedMentions(everyone=False, roles=False, users=False),\n            )\n\n    @property\n    def me(self) -> Union[discord.ClientUser, discord.Member]:\n        \"\"\"\n        discord.abc.User: The bot member or user object.\n\n        If the context is DM, this will be a `discord.User` object.\n        \"\"\"\n        if self.guild is not None:\n            return self.guild.me\n        else:\n            return self.bot.user\n\n\nif TYPE_CHECKING or os.getenv(\"BUILDING_DOCS\", False):\n\n    class DMContext(Context):\n        \"\"\"\n        At runtime, this will still be a normal context object.\n\n        This lies about some type narrowing for type analysis in commands\n        using a dm_only decorator.\n\n        It is only correct to use when those types are already narrowed\n        \"\"\"\n\n        @property\n        def author(self) -> discord.User:\n            ...\n\n        @property\n        def channel(self) -> discord.DMChannel:\n            ...\n\n        @property\n        def guild(self) -> None:\n            ...\n\n        @property\n        def me(self) -> discord.ClientUser:\n            ...\n\n    class GuildContext(Context):\n        \"\"\"\n        At runtime, this will still be a normal context object.\n\n        This lies about some type narrowing for type analysis in commands\n        using a guild_only decorator.\n\n        It is only correct to use when those types are already narrowed\n        \"\"\"\n\n        @property\n        def author(self) -> discord.Member:\n            ...\n\n        @property\n        def channel(self) -> Union[discord.TextChannel, discord.VoiceChannel, discord.Thread]:\n            ...\n\n        @property\n        def guild(self) -> discord.Guild:\n            ...\n\n        @property\n        def me(self) -> discord.Member:\n            ...\n\nelse:\n    GuildContext = Context\n    DMContext = Context\n", "path": "redbot/core/commands/context.py"}]}