Repository: Rapptz/discord.py

Issue:
Messages aren't hashable
## Summary

<!-- A summary of your bug report -->

The Message type is not hashable.

## Reproduction Steps

<!-- What you did to make it happen. Ideally there should be a short code snippet in this section to help reproduce the bug. -->

Get a message object and try to hash it

## Expected Results

<!-- What you expected to happen -->

The message should have a hash, which would be the value of the guild, user/member sending it, and the message ID itself.

## Actual Results

<!-- What actually happened. If there is a traceback, please show the entire thing. -->

TypeError: unhashable type: 'Message'


## Checklist

<!-- Put an x inside [ ] to check it, like so: [x] -->

- [x] I have searched the open issues for duplicates.
- [x] I have shown the entire traceback, if possible.
- [x] I have removed my token from display, if visible.

## System Information

<!-- Run `python -m discord -v` and paste this information below. -->
<!-- This command is available in v1.1.0 or higher. If you are unable to run this command, paste basic info (ie. Python version, library version, and your operating system -->
- Python v3.8.5-final
- discord.py v1.5.0-final
- aiohttp v3.6.2
- system info: Darwin 19.6.0 Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64



Discussion:
`discord.Message` being an unhashable type is *not a bug*. Please change this issue to a feature request if you so wish it to be.
> `discord.Message` being an unhashable type is _not a bug_. Please change this issue to a feature request if you so wish it to be.

It used to be hashable in V1.4. Also how do I change the bug report into a feature request?
I know this is not a solution, just a workaround, but you can hash `message.jump_url` instead, since the jump_url contains guild, channel and message ID and therefore is unique for every message
Unlike other classes which were deliberately documented as having a hash (see: member, guild, role ...) message was not ever documented as such. If it's intended to be hashable, this was not documented. The reason it stopped being hashable was adding an equality comparison without adding a hash (by default in python, if you implement *neither*, you get object identity as equality and a hash which is based on the same)
I think making messages hashable and documenting them as such would be a good idea since every message is unique.

I'd agree with @MvonK about using the guild, channel and message ID for a message to implement the hash, except I think using a tuple of the three would be a nicer solution for writing the hash of the object.

If needed, we can even include the message content in the tuple, since that would allow us to differentiate an edited message from its original counterpart using the hash.

Of course, we could stick with the guild, channel, and message ID tuple for simplicity, but including the editable properties could also provide some interesting behavior to the hash.

Comments?
> I think making messages hashable and documenting them as such would be a good idea since every message is unique.
> 
> I'd agree with @MvonK about using the guild, channel and message ID for a message to implement the hash, except I think using a tuple of the three would be a nicer solution for writing the hash of the object.
> 
> If needed, we can even include the message content in the tuple, since that would allow us to differentiate an edited message from its original counterpart using the hash.
> 
> Of course, we could stick with the guild, channel, and message ID tuple for simplicity, but including the editable properties could also provide some interesting behavior to the hash.
> 
> Comments?

I took a good look at the `__eq__` method, and it doesn't account for message content, so the hashing algo shouldn't either. But this could lead to issues storing multiple versions of the same message, so that should be addressed as well. I'll open a PR with appropriate code.
Why not use `class Message(Hashable)`?
> Why not use `class Message(Hashable)`?

There's a Hash mixin? This is news to me

Resolving patch:
diff --git a/discord/message.py b/discord/message.py
--- a/discord/message.py
+++ b/discord/message.py
@@ -42,6 +42,7 @@
 from .file import File
 from .utils import escape_mentions
 from .guild import Guild
+from .mixins import Hashable
 
 
 class Attachment:
@@ -252,7 +253,7 @@ def flatten_handlers(cls):
     return cls
 
 @flatten_handlers
-class Message:
+class Message(Hashable):
     r"""Represents a message from Discord.
 
     There should be no need to create one of these manually.
@@ -388,9 +389,6 @@ def __init__(self, *, state, channel, data):
     def __repr__(self):
         return '<Message id={0.id} channel={0.channel!r} type={0.type!r} author={0.author!r} flags={0.flags!r}>'.format(self)
 
-    def __eq__(self, other):
-        return isinstance(other, self.__class__) and self.id == other.id
-
     def _try_patch(self, data, key, transform=None):
         try:
             value = data[key]


Test patch: