internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: python-discord/bot

Issue:
Enhancement: Reverse deleting !dormant command message
The current dormant message reads like this:

> This help channel has been marked as dormant, and has been moved into the Help: Dormant category at the bottom of the channel list. It is no longer possible to send messages in this channel until it becomes available again.
<-- snip -->

Thus, there is no way of knowing whether it was manually made dormant, or automatically made dormant due to inactivity.
If a user mentions that a channel was mistakenly made dormant when they were not done with it, it would be nice to see if it's an issue with the bot or a human error.

**Updated solution:** Reverse the deletion of the message containing the `!dormant` command. It would be clear at a glance if the channel was made dormant manually or automatically.

~~**Proposed messages:** (Relevant sections highlighted)~~

~~*Automatic invocation*:~~
~~> This help channel has been marked as dormant **due to inactivity**, and has been moved into the Help: Dormant category at the bottom of the channel list. It is no longer possible to send messages in this channel until it becomes available again.
<-- snip -->~~

~~*Manual invocation*:~~
~~> This help channel has been marked as dormant **by staff**, and has been moved into the Help: Dormant category at the bottom of the channel list. It is no longer possible to send messages in this channel until it becomes available again.
<-- snip -->~~


Discussion:
I think an easy way of communicating that a channel was marked as dormant manually and making obvious by whom it was marked so is by reversing the bit that deletes the invocation message. That will also make it far more obvious than having to scan an embed message.
> <--snip --> reversing the bit that deletes the invocation message. That will also make it far more obvious than having to scan an embed message.

I second that idea.

Resolving patch:
diff --git a/bot/cogs/help_channels.py b/bot/cogs/help_channels.py
--- a/bot/cogs/help_channels.py
+++ b/bot/cogs/help_channels.py
@@ -224,10 +224,6 @@ async def dormant_command(self, ctx: commands.Context) -> None:
                 with suppress(KeyError):
                     del self.help_channel_claimants[ctx.channel]
 
-                with suppress(discord.errors.NotFound):
-                    log.trace("Deleting dormant invokation message.")
-                    await ctx.message.delete()
-
                 with suppress(discord.errors.HTTPException, discord.errors.NotFound):
                     await self.reset_claimant_send_permission(ctx.channel)
 


Test patch:
Repository: python-discord/bot

Issue:
Set event loop to Selector on windows
With the [3.8 python update](https://docs.python.org/3/whatsnew/3.8.html#asyncio), the default event loop on windows is now the `ProactorEventLoop`; one of aiohttp's dependencies uses features which are not supported in this event loop leading to crashes on startup on windows with an undescriptive error

```
From cffi callback <function _sock_state_cb at 0x0000000003816040>:
Traceback (most recent call last):
  File "C:\Users\Numerlor\.virtualenvs\bot-K_QdelnW\lib\site-packages\pycares\__init__.py", line 91, in _sock_state_cb
    sock_state_cb(socket_fd, readable, writable)
  File "C:\Users\Numerlor\.virtualenvs\bot-K_QdelnW\lib\site-packages\aiodns\__init__.py", line 105, in _sock_state_cb
    self.loop.add_reader(fd, self._handle_event, fd, READ)
  File "C:\Users\Numerlor\AppData\Local\Programs\Python\Python38\Lib\asyncio\events.py", line 501, in add_reader
    raise NotImplementedError
NotImplementedError
```
This can be fixed by setting the event loop policy to `WindowsSelectorEventLoopPolicy` through `asyncio.set_event_loop_policy` when the platform is detected to be windows


Discussion:

Resolving patch:
diff --git a/bot/__init__.py b/bot/__init__.py
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -1,3 +1,4 @@
+import asyncio
 import logging
 import os
 import sys
@@ -59,3 +60,8 @@ def monkeypatch_trace(self: logging.Logger, msg: str, *args, **kwargs) -> None:
 logging.getLogger("discord").setLevel(logging.WARNING)
 logging.getLogger("websockets").setLevel(logging.WARNING)
 logging.getLogger(__name__)
+
+
+# On Windows, the selector event loop is required for aiodns.
+if os.name == "nt":
+    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
diff --git a/bot/bot.py b/bot/bot.py
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -76,7 +76,7 @@ async def close(self) -> None:
             await self._resolver.close()
 
         if self.stats._transport:
-            await self.stats._transport.close()
+            self.stats._transport.close()
 
     async def login(self, *args, **kwargs) -> None:
         """Re-create the connector and set up sessions before logging into Discord."""


Test patch:
Repository: python-discord/bot

Issue:
Use appropriate log level for exceptions from event listeners
From @SebastiaanZ:

> Finally, `discord.py` currently "hides" errors/tracebacks that happen in event listeners as we only have a custom error handler for commands. This isn't too bad locally, since `d.py` **prints** those exceptions to stderr, but it obviously means they'll never show up in Sentry, as they are **not actually logged** with the appropriate level.


Discussion:
Right, thanks. I should have added this myself.

Resolving patch:
diff --git a/bot/bot.py b/bot/bot.py
--- a/bot/bot.py
+++ b/bot/bot.py
@@ -7,6 +7,7 @@
 import aiohttp
 import discord
 from discord.ext import commands
+from sentry_sdk import push_scope
 
 from bot import DEBUG_MODE, api, constants
 from bot.async_stats import AsyncStatsClient
@@ -155,3 +156,14 @@ async def wait_until_guild_available(self) -> None:
         gateway event before giving up and thus not populating the cache for unavailable guilds.
         """
         await self._guild_available.wait()
+
+    async def on_error(self, event: str, *args, **kwargs) -> None:
+        """Log errors raised in event listeners rather than printing them to stderr."""
+        self.stats.incr(f"errors.event.{event}")
+
+        with push_scope() as scope:
+            scope.set_tag("event", event)
+            scope.set_extra("args", args)
+            scope.set_extra("kwargs", kwargs)
+
+            log.exception(f"Unhandled exception in {event}.")


Test patch:
Repository: python-discord/bot

Issue:
User's avatar in `!user` is not animated.
## Problem
Right now, when doing `!user` the avatar is always set to `png`, even if the user's avatar is a gif.

## Proposal
Similar to how we are handling avatars in other places, instead of using the `format` keyword, we can use the `static_format` keyword instead, as [documented in discord.py](https://discordpy.readthedocs.io/en/latest/api.html#discord.User.avatar_url_as)

The code responsible for the command can be found here:
https://github.com/python-discord/bot/blob/fe325adc66e9621ea970abd83db58df4b792caa5/bot/cogs/information.py#L209-L212

You can see how filter is formating it here:
https://github.com/python-discord/bot/blob/fe325adc66e9621ea970abd83db58df4b792caa5/bot/cogs/filtering.py#L233-L243


Discussion:

Resolving patch:
diff --git a/bot/cogs/information.py b/bot/cogs/information.py
--- a/bot/cogs/information.py
+++ b/bot/cogs/information.py
@@ -206,7 +206,7 @@ async def create_user_embed(self, ctx: Context, user: Member) -> Embed:
             description="\n\n".join(description)
         )
 
-        embed.set_thumbnail(url=user.avatar_url_as(format="png"))
+        embed.set_thumbnail(url=user.avatar_url_as(static_format="png"))
         embed.colour = user.top_role.colour if roles else Colour.blurple()
 
         return embed


Test patch:
diff --git a/tests/bot/cogs/test_information.py b/tests/bot/cogs/test_information.py
--- a/tests/bot/cogs/test_information.py
+++ b/tests/bot/cogs/test_information.py
@@ -485,7 +485,7 @@ def test_create_user_embed_uses_png_format_of_user_avatar_as_thumbnail(self):
         user.avatar_url_as.return_value = "avatar url"
         embed = asyncio.run(self.cog.create_user_embed(ctx, user))
 
-        user.avatar_url_as.assert_called_once_with(format="png")
+        user.avatar_url_as.assert_called_once_with(static_format="png")
         self.assertEqual(embed.thumbnail.url, "avatar url")
Repository: python-discord/bot

Issue:
Message Filters Should Not Attempt to Delete Messages in DMs
Filters that attempt to delete offending message(s) should check whether or not the message was sent in a DM, since the bot cannot delete others' DM messages.

```
Forbidden: 403 Forbidden (error code: 50003): Cannot execute action on a DM channel
  File "discord/client.py", line 312, in _run_event
    await coro(*args, **kwargs)
  File "bot/cogs/filtering.py", line 114, in on_message
    await self._filter_message(msg)
  File "bot/cogs/filtering.py", line 176, in _filter_message
    await msg.delete()
  File "discord/message.py", line 762, in delete
    await self._state.http.delete_message(self.channel.id, self.id)
  File "discord/http.py", line 221, in request
    raise Forbidden(r, data)

Unhandled exception in on_message.
```

Sentry Issue: [BOT-3W](https://sentry.io/organizations/python-discord/issues/1650443849/?referrer=github_integration)


Discussion:

Resolving patch:
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py
--- a/bot/cogs/filtering.py
+++ b/bot/cogs/filtering.py
@@ -4,7 +4,7 @@
 
 import discord.errors
 from dateutil.relativedelta import relativedelta
-from discord import Colour, DMChannel, Member, Message, TextChannel
+from discord import Colour, Member, Message, TextChannel
 from discord.ext.commands import Cog
 from discord.utils import escape_markdown
 
@@ -161,8 +161,10 @@ async def _filter_message(self, msg: Message, delta: Optional[int] = None) -> No
                         match = await _filter["function"](msg)
 
                     if match:
-                        # If this is a filter (not a watchlist), we should delete the message.
-                        if _filter["type"] == "filter":
+                        is_private = msg.channel.type is discord.ChannelType.private
+
+                        # If this is a filter (not a watchlist) and not in a DM, delete the message.
+                        if _filter["type"] == "filter" and not is_private:
                             try:
                                 # Embeds (can?) trigger both the `on_message` and `on_message_edit`
                                 # event handlers, triggering filtering twice for the same message.
@@ -181,7 +183,7 @@ async def _filter_message(self, msg: Message, delta: Optional[int] = None) -> No
                             if _filter["user_notification"]:
                                 await self.notify_member(msg.author, _filter["notification_msg"], msg.channel)
 
-                        if isinstance(msg.channel, DMChannel):
+                        if is_private:
                             channel_str = "via DM"
                         else:
                             channel_str = f"in {msg.channel.mention}"


Test patch:
Repository: python-discord/bot

Issue:
Modlog Events Should Check for DM
At least one of the event handlers in the modlog do not properly account for messages being sent in DMs & attempt to perform a guild ID comparison, which doesn't exist in a DM. This should be guarded against across the cog.

```
AttributeError: 'NoneType' object has no attribute 'id'
  File "discord/client.py", line 312, in _run_event
    await coro(*args, **kwargs)
  File "bot/cogs/moderation/modlog.py", line 555, in on_message_delete
    if message.guild.id != GuildConstant.id or channel.id in GuildConstant.modlog_blacklist:

Unhandled exception in on_message_delete.
```

Sentry Issue: [BOT-44](https://sentry.io/organizations/python-discord/issues/1656406094/?referrer=github_integration)


Discussion:

Resolving patch:
diff --git a/bot/cogs/moderation/modlog.py b/bot/cogs/moderation/modlog.py
--- a/bot/cogs/moderation/modlog.py
+++ b/bot/cogs/moderation/modlog.py
@@ -555,6 +555,10 @@ async def on_message_delete(self, message: discord.Message) -> None:
         channel = message.channel
         author = message.author
 
+        # Ignore DMs.
+        if not message.guild:
+            return
+
         if message.guild.id != GuildConstant.id or channel.id in GuildConstant.modlog_blacklist:
             return
 


Test patch:
Repository: python-discord/bot

Issue:
Invite Filter Raises on Invalid Invites
Currently, if the [`_has_invites`](https://github.com/python-discord/bot/blob/007f771b9cdf9de608920feea7f0e4a98b61fcab/bot/cogs/filtering.py#L290) catches an invalid/expired/etc. link it returns `True`, which motors down the filtering logic to a point where we're expecting a dictionary (a valid guild response from Discord's API):

https://github.com/python-discord/bot/blob/007f771b9cdf9de608920feea7f0e4a98b61fcab/bot/cogs/filtering.py#L215-L217

Since booleans don't have items, this will raise an `AttributeError`

The following logic block needs to be adjusted to prevent this issue from occurring:

https://github.com/python-discord/bot/blob/007f771b9cdf9de608920feea7f0e4a98b61fcab/bot/cogs/filtering.py#L314-L318

There are two approaches for resolution here:
  * Rather than return `True`, this conditional should generate a dictionary that's compatible with the above embed generation logic, indicating that an invite was provided but it's invalid
  * Return `False` instead, since we probably don't care about invite links that don't resolve


Discussion:
Sentry issue: [BOT-3Z](https://sentry.io/organizations/python-discord/issues/1652649945/?referrer=github_integration)

Resolving patch:
diff --git a/bot/cogs/filtering.py b/bot/cogs/filtering.py
--- a/bot/cogs/filtering.py
+++ b/bot/cogs/filtering.py
@@ -214,7 +214,9 @@ async def _filter_message(self, msg: Message, delta: Optional[int] = None) -> No
                         additional_embeds = None
                         additional_embeds_msg = None
 
-                        if filter_name == "filter_invites":
+                        # The function returns True for invalid invites.
+                        # They have no data so additional embeds can't be created for them.
+                        if filter_name == "filter_invites" and match is not True:
                             additional_embeds = []
                             for invite, data in match.items():
                                 embed = discord.Embed(description=(


Test patch:
Repository: python-discord/bot

Issue:
Publish messages to the #reddit channel
Since the #reddit channel has moved to the new News category we should convert it to an announcement channel and use the `.publish()` method on messages sent there so users can subscribe to daily reddit updates.

[Message.publish() in the discord.py docs](https://discordpy.readthedocs.io/en/latest/api.html#discord.Message.publish)


Discussion:

Resolving patch:
diff --git a/bot/cogs/reddit.py b/bot/cogs/reddit.py
--- a/bot/cogs/reddit.py
+++ b/bot/cogs/reddit.py
@@ -218,7 +218,10 @@ async def auto_poster_loop(self) -> None:
 
         for subreddit in RedditConfig.subreddits:
             top_posts = await self.get_top_posts(subreddit=subreddit, time="day")
-            await self.webhook.send(username=f"{subreddit} Top Daily Posts", embed=top_posts)
+            message = await self.webhook.send(username=f"{subreddit} Top Daily Posts", embed=top_posts)
+
+            if message.channel.is_news():
+                await message.publish()
 
     async def top_weekly_posts(self) -> None:
         """Post a summary of the top posts."""
@@ -242,6 +245,9 @@ async def top_weekly_posts(self) -> None:
 
                 await message.pin()
 
+                if message.channel.is_news():
+                    await message.publish()
+
     @group(name="reddit", invoke_without_command=True)
     async def reddit_group(self, ctx: Context) -> None:
         """View the top posts from various subreddits."""


Test patch:
Repository: python-discord/bot

Issue:
Charinfo doesn't escape backticks
The Unicode escapes are formatted in code blocks. When the embed tries to also render a literal backtick, this ends up interfering with the code blocks and creating a mess.

![bild](https://user-images.githubusercontent.com/1515135/84466837-32909d00-ac2f-11ea-8287-3792a84c9169.png)



Discussion:

Resolving patch:
diff --git a/bot/cogs/utils.py b/bot/cogs/utils.py
--- a/bot/cogs/utils.py
+++ b/bot/cogs/utils.py
@@ -6,7 +6,7 @@
 from io import StringIO
 from typing import Tuple, Union
 
-from discord import Colour, Embed
+from discord import Colour, Embed, utils
 from discord.ext.commands import BadArgument, Cog, Context, command
 
 from bot.bot import Bot
@@ -145,7 +145,7 @@ def get_info(char: str) -> Tuple[str, str]:
                 u_code = f"\\U{digit:>08}"
             url = f"https://www.compart.com/en/unicode/U+{digit:>04}"
             name = f"[{unicodedata.name(char, '')}]({url})"
-            info = f"`{u_code.ljust(10)}`: {name} - {char}"
+            info = f"`{u_code.ljust(10)}`: {name} - {utils.escape_markdown(char)}"
             return info, u_code
 
         charlist, rawlist = zip(*(get_info(c) for c in characters))


Test patch:
Repository: python-discord/bot

Issue:
Providing a single apostrophe-like character behind `!help` raises warning
Issuing an help command like `!help '` (a single single quote character as the help query) results in the following warning:

```py
2020-06-02 21:52:38 | root | WARNING | Applied processor reduces input query to empty string, all comparisons will have score 0. [Query: ''']
```

The same goes for at least  the queries:

```
[Query: '´']
[Query: '"']
[Query: '`']
```

The warning message hints at that such a "query" will be reduces to an empty string and, in turn, to a comparison score of `0`. The latter suggests that this warning is probably given by something in our fuzzy matching procedure. (But I haven't taken steps to confirm this yet.)

I think the best solution is to just show the normal help embed for such queries, but what the most robust way to do this is needs to be determined by the one who takes on this issue.

Sentry Issue: [BOT-5W](https://sentry.io/organizations/python-discord/issues/1705336367/?referrer=github_integration)


Discussion:
This is annoying. It uses the root logger, so it's not possible to suppress the warning. The error comes from `fuzzywuzzy`. Its default processor replaces all non-letters and non-numbers with whitespace using this regex for the substition `(?ui)\W`. `strip()` is called later, which makes it an empty string.

Three solutions I can think of:

1. Specify a custom processor (or `None`) to avoid removal of symbols.
2. Invoke the default processor before the fuzzy match to be able to avoid matching if the result is an empty string. To avoid redundantly invoking the processor, fuzzywuzzy could be given `None` for the processor so it does a no-op.
3. Simply ignore the warnings in sentry.

I like № 2 the most
I agree, No. 2 highlights the issue the clearest. I'll get this done.

Resolving patch:
diff --git a/bot/cogs/help.py b/bot/cogs/help.py
--- a/bot/cogs/help.py
+++ b/bot/cogs/help.py
@@ -8,6 +8,7 @@
 from discord import Colour, Embed, Member, Message, NotFound, Reaction, User
 from discord.ext.commands import Bot, Cog, Command, Context, Group, HelpCommand
 from fuzzywuzzy import fuzz, process
+from fuzzywuzzy.utils import full_process
 
 from bot import constants
 from bot.constants import Channels, Emojis, STAFF_ROLES
@@ -145,7 +146,13 @@ async def command_not_found(self, string: str) -> "HelpQueryNotFound":
         Will return an instance of the `HelpQueryNotFound` exception with the error message and possible matches.
         """
         choices = await self.get_all_help_choices()
-        result = process.extractBests(string, choices, scorer=fuzz.ratio, score_cutoff=60)
+
+        # Run fuzzywuzzy's processor beforehand, and avoid matching if processed string is empty
+        # This avoids fuzzywuzzy from raising a warning on inputs with only non-alphanumeric characters
+        if (processed := full_process(string)):
+            result = process.extractBests(processed, choices, scorer=fuzz.ratio, score_cutoff=60, processor=None)
+        else:
+            result = []
 
         return HelpQueryNotFound(f'Query "{string}" not found.', dict(result))
 


Test patch:
Repository: python-discord/bot

Issue:
Suppress NotFound exception when removing reactions for help command
Sentry Issue: [BOT-6X](https://sentry.io/organizations/python-discord/issues/1781203963/?referrer=github_integration)

```
TimeoutError: 
  File "bot/cogs/help.py", line 40, in help_cleanup
    await bot.wait_for("reaction_add", check=check, timeout=300)
  File "asyncio/tasks.py", line 490, in wait_for
    raise exceptions.TimeoutError()

NotFound: 404 Not Found (error code: 10008): Unknown Message
(3 additional frame(s) were not displayed)
...
  File "discord/ext/commands/help.py", line 817, in command_callback
    return await self.send_command_help(cmd)
  File "bot/cogs/help.py", line 203, in send_command_help
    await help_cleanup(self.context.bot, self.context.author, message)
  File "bot/cogs/help.py", line 43, in help_cleanup
    await message.remove_reaction(DELETE_EMOJI, bot.user)
  File "discord/message.py", line 982, in remove_reaction
    await self._state.http.remove_own_reaction(self.channel.id, self.id, emoji)
  File "discord/http.py", line 223, in request
    raise NotFound(r, data)

Error executing command invoked by <REDACTED>: !help purge user
```


Discussion:

Resolving patch:
diff --git a/bot/cogs/help.py b/bot/cogs/help.py
--- a/bot/cogs/help.py
+++ b/bot/cogs/help.py
@@ -36,13 +36,12 @@ def check(reaction: Reaction, user: User) -> bool:
 
     await message.add_reaction(DELETE_EMOJI)
 
-    try:
-        await bot.wait_for("reaction_add", check=check, timeout=300)
-        await message.delete()
-    except TimeoutError:
-        await message.remove_reaction(DELETE_EMOJI, bot.user)
-    except NotFound:
-        pass
+    with suppress(NotFound):
+        try:
+            await bot.wait_for("reaction_add", check=check, timeout=300)
+            await message.delete()
+        except TimeoutError:
+            await message.remove_reaction(DELETE_EMOJI, bot.user)
 
 
 class HelpQueryNotFound(ValueError):


Test patch:
Repository: python-discord/bot

Issue:
Ensure Embed description is not Embed.Empty before stripping
Sentry Issue: [BOT-6K](https://sentry.io/organizations/python-discord/issues/1764434612/?referrer=github_integration)

It's a special value instead of simply an empty string, so trying to strip it may fail. Other code should also be reviewed to ensure it can't fail for similar reasons.

```
AttributeError: '_EmptyEmbed' object has no attribute 'strip'
  File "discord/client.py", line 312, in _run_event
    await coro(*args, **kwargs)
  File "bot/cogs/help_channels.py", line 719, in on_message_delete
    if not await self.is_empty(msg.channel):
  File "bot/cogs/help_channels.py", line 733, in is_empty
    return self.match_bot_embed(msg, AVAILABLE_MSG)
  File "bot/cogs/help_channels.py", line 443, in match_bot_embed
    return message.author == self.bot.user and embed.description.strip() == description.strip()

Unhandled exception in on_message_delete.
```


Discussion:

Resolving patch:
diff --git a/bot/cogs/help_channels.py b/bot/cogs/help_channels.py
--- a/bot/cogs/help_channels.py
+++ b/bot/cogs/help_channels.py
@@ -428,8 +428,11 @@ def match_bot_embed(self, message: t.Optional[discord.Message], description: str
         if not message or not message.embeds:
             return False
 
-        embed = message.embeds[0]
-        return message.author == self.bot.user and embed.description.strip() == description.strip()
+        bot_msg_desc = message.embeds[0].description
+        if bot_msg_desc is discord.Embed.Empty:
+            log.trace("Last message was a bot embed but it was empty.")
+            return False
+        return message.author == self.bot.user and bot_msg_desc.strip() == description.strip()
 
     @staticmethod
     def is_in_category(channel: discord.TextChannel, category_id: int) -> bool:


Test patch: