Skip to content

Commit

Permalink
Merge branch 'master' into invokable
Browse files Browse the repository at this point in the history
  • Loading branch information
Middledot authored Nov 6, 2023
2 parents 931db35 + 9e4b3ff commit d899980
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2156](https://github.com/Pycord-Development/pycord/pull/2156))
- Fixed `ScheduledEvent.creator_id` returning `str` instead of `int`.
([#2162](https://github.com/Pycord-Development/pycord/pull/2162))
- Fixed `_bytes_to_base64_data` not defined.
([#2185](https://github.com/Pycord-Development/pycord/pull/2185))
- Fixed type-hinting of `values` argument of `basic_autocomplete` to include
type-hinting of `Iterable[OptionChoice]`.
([#2164](https://github.com/Pycord-Development/pycord/pull/2164))
Expand Down
8 changes: 8 additions & 0 deletions discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"AutoModActionType",
"AutoModKeywordPresetType",
"ApplicationRoleConnectionMetadataType",
"ReactionType",
)


Expand Down Expand Up @@ -944,6 +945,13 @@ class ApplicationRoleConnectionMetadataType(Enum):
boolean_not_equal = 8


class ReactionType(Enum):
"""The reaction type"""

normal = 0
burst = 1


T = TypeVar("T")


Expand Down
2 changes: 1 addition & 1 deletion discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -2908,7 +2908,7 @@ async def create_role(
if icon is None:
fields["icon"] = None
else:
fields["icon"] = _bytes_to_base64_data(icon)
fields["icon"] = utils._bytes_to_base64_data(icon)
fields["unicode_emoji"] = None

if unicode_emoji is not MISSING:
Expand Down
3 changes: 3 additions & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@ def get_reaction_users(
emoji: str,
limit: int,
after: Snowflake | None = None,
type: int | None = None,
) -> Response[list[user.User]]:
r = Route(
"GET",
Expand All @@ -771,6 +772,8 @@ def get_reaction_users(
}
if after:
params["after"] = after
if type:
params["type"] = type
return self.request(r, params=params)

def clear_reactions(
Expand Down
10 changes: 8 additions & 2 deletions discord/iterators.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,11 @@ async def next(self) -> T:


class ReactionIterator(_AsyncIterator[Union["User", "Member"]]):
def __init__(self, message, emoji, limit=100, after=None):
def __init__(self, message, emoji, limit=100, after=None, type=None):
self.message = message
self.limit = limit
self.after = after
self.type = type
state = message._state
self.getter = state.http.get_reaction_users
self.state = state
Expand All @@ -212,7 +213,12 @@ async def fill_users(self):

after = self.after.id if self.after else None
data: list[PartialUserPayload] = await self.getter(
self.channel_id, self.message.id, self.emoji, retrieve, after=after
self.channel_id,
self.message.id,
self.emoji,
retrieve,
after=after,
type=self.type,
)

if data:
Expand Down
33 changes: 31 additions & 2 deletions discord/raw_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from typing import TYPE_CHECKING

from .automod import AutoModAction, AutoModTriggerType
from .enums import AuditLogAction, ChannelType, try_enum
from .enums import AuditLogAction, ChannelType, ReactionType, try_enum
from .types.user import User

if TYPE_CHECKING:
Expand Down Expand Up @@ -214,6 +214,15 @@ class RawReactionActionEvent(_RawReprMixin):
``REACTION_REMOVE`` for reaction removal.
.. versionadded:: 1.3
burst: :class:`bool`
Whether this reaction is a burst (super) reaction.
burst_colours: Optional[:class:`list`]
A list of hex codes this reaction can be. Only available if `event_type` is `REACTION_ADD`
and this emoji has super reactions available.
burst_colors: Optional[:class:`list`]
Alias for :attr:`burst_colours`.
type: :class:`ReactionType`
The type of reaction added.
data: :class:`dict`
The raw data sent by the `gateway <https://discord.com/developers/docs/topics/gateway-events#message-reaction-add>`_.
Expand All @@ -226,6 +235,10 @@ class RawReactionActionEvent(_RawReprMixin):
"channel_id",
"guild_id",
"emoji",
"burst",
"burst_colours",
"burst_colors",
"type",
"event_type",
"member",
"data",
Expand All @@ -240,6 +253,10 @@ def __init__(
self.emoji: PartialEmoji = emoji
self.event_type: str = event_type
self.member: Member | None = None
self.burst: bool = data.get("burst")
self.burst_colours: list = data.get("burst_colors", [])
self.burst_colors: list = self.burst_colours
self.type: ReactionType = try_enum(data.get("type", 0))

try:
self.guild_id: int | None = int(data["guild_id"])
Expand Down Expand Up @@ -293,18 +310,30 @@ class RawReactionClearEmojiEvent(_RawReprMixin):
The guild ID where the reactions got cleared.
emoji: :class:`PartialEmoji`
The custom or unicode emoji being removed.
burst: :class:`bool`
Whether this reaction was a burst (super) reaction.
burst_colours: :class:`list`
The available HEX codes of the removed super reaction.
burst_colors: Optional[:class:`list`]
Alias for :attr:`burst_colours`.
type: :class:`ReactionType`
The type of reaction removed.
data: :class:`dict`
The raw data sent by the `gateway <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-emoji>`_.
.. versionadded:: 2.5
"""

__slots__ = ("message_id", "channel_id", "guild_id", "emoji", "data")
__slots__ = ("message_id", "channel_id", "guild_id", "emoji", "burst", "data")

def __init__(self, data: ReactionClearEmojiEvent, emoji: PartialEmoji) -> None:
self.emoji: PartialEmoji = emoji
self.message_id: int = int(data["message_id"])
self.channel_id: int = int(data["channel_id"])
self.burst: bool = data.get("burst")
self.burst_colours: list = data.get("burst_colors", [])
self.burst_colors: list = self.burst_colours
self.type: ReactionType = try_enum(data.get("type", 0))

try:
self.guild_id: int | None = int(data["guild_id"])
Expand Down
85 changes: 79 additions & 6 deletions discord/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@

from typing import TYPE_CHECKING, Any

from .colour import Colour
from .enums import ReactionType
from .iterators import ReactionIterator

__all__ = ("Reaction",)
__all__ = ("Reaction", "ReactionCountDetails")

if TYPE_CHECKING:
from .abc import Snowflake
from .emoji import Emoji
from .message import Message
from .partial_emoji import PartialEmoji
from .types.message import Reaction as ReactionPayload
from .types.message import ReactionCountDetails as ReactionCountDetailsPayload


class Reaction:
Expand Down Expand Up @@ -70,14 +73,27 @@ class Reaction:
emoji: Union[:class:`Emoji`, :class:`PartialEmoji`, :class:`str`]
The reaction emoji. May be a custom emoji, or a unicode emoji.
count: :class:`int`
Number of times this reaction was made
The combined total of normal and super reactions for this emoji.
me: :class:`bool`
If the user sent this reaction.
If the user sent this as a normal reaction.
me_burst: :class:`bool`
If the user sent this as a super reaction.
message: :class:`Message`
Message this reaction is for.
burst: :class:`bool`
Whether this reaction is a burst (super) reaction.
"""

__slots__ = ("message", "count", "emoji", "me")
__slots__ = (
"message",
"count",
"emoji",
"me",
"burst",
"me_burst",
"_count_details",
"_burst_colours",
)

def __init__(
self,
Expand All @@ -91,7 +107,35 @@ def __init__(
emoji or message._state.get_reaction_emoji(data["emoji"])
)
self.count: int = data.get("count", 1)
self._count_details: ReactionCountDetailsPayload = data.get("count_details", {})
self.me: bool = data.get("me")
self.burst: bool = data.get("burst")
self.me_burst: bool = data.get("me_burst")
self._burst_colours: list[Colour] = data.get("burst_colors", [])

@property
def burst_colours(self) -> list[Colour]:
"""Returns a list possible :class:`Colour` this super reaction can be.
There is an alias for this named :attr:`burst_colors`.
"""

# We recieve a list of #FFFFFF, so omit the # and convert to base 16
return [Colour(int(c[1:], 16)) for c in self._burst_colours]

@property
def burst_colors(self) -> list[Colour]:
"""Returns a list possible :class:`Colour` this super reaction can be.
There is an alias for this named :attr:`burst_colours`.
"""

return self.burst_colours

@property
def count_details(self):
"""Returns :class:`ReactionCountDetails` for the individual counts of normal and super reactions made."""
return ReactionCountDetails(self._count_details)

# TODO: typeguard
def is_custom_emoji(self) -> bool:
Expand Down Expand Up @@ -166,7 +210,11 @@ async def clear(self) -> None:
await self.message.clear_reaction(self.emoji)

def users(
self, *, limit: int | None = None, after: Snowflake | None = None
self,
*,
limit: int | None = None,
after: Snowflake | None = None,
type: ReactionType | None = None,
) -> ReactionIterator:
"""Returns an :class:`AsyncIterator` representing the users that have reacted to the message.
Expand All @@ -181,6 +229,8 @@ def users(
reacted to the message.
after: Optional[:class:`abc.Snowflake`]
For pagination, reactions are sorted by member.
type: Optional[:class:`ReactionType`]
The type of reaction to get users for. Defaults to `normal`.
Yields
------
Expand Down Expand Up @@ -210,6 +260,10 @@ def users(
# users is now a list of User...
winner = random.choice(users)
await channel.send(f'{winner} has won the raffle.')
Getting super reactors: ::
users = await reaction.users(type=ReactionType.burst).flatten()
"""

if not isinstance(self.emoji, str):
Expand All @@ -220,4 +274,23 @@ def users(
if limit is None:
limit = self.count

return ReactionIterator(self.message, emoji, limit, after)
if isinstance(type, ReactionType):
type = type.value

return ReactionIterator(self.message, emoji, limit, after, type)


class ReactionCountDetails:
"""Represents a breakdown of the normal and burst reaction counts for the emoji.
Attributes
----------
normal: :class:`int`
The number of normal reactions for this emoji.
burst: :class:`bool`
The number of super reactions for this emoji.
"""

def __init__(self, data: ReactionCountDetailsPayload):
self.normal = data.get("normal", 0)
self.burst = data.get("burst", 0)
6 changes: 6 additions & 0 deletions discord/types/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class Reaction(TypedDict):
count: int
me: bool
emoji: PartialEmoji
burst: bool


class ReactionCountDetails(TypedDict):
normal: int
burst: int


class Attachment(TypedDict):
Expand Down
6 changes: 6 additions & 0 deletions discord/types/raw_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class ReactionActionEvent(_ReactionEventOptional):
channel_id: Snowflake
message_id: Snowflake
emoji: PartialEmoji
burst: bool
burst_colors: list
type: int


class ReactionClearEvent(_ReactionEventOptional):
Expand All @@ -73,6 +76,9 @@ class ReactionClearEmojiEvent(_ReactionEventOptional):
channel_id: int
message_id: int
emoji: PartialEmoji
burst: bool
burst_colors: list
type: int


class IntegrationDeleteEvent(TypedDict):
Expand Down
14 changes: 14 additions & 0 deletions docs/api/enums.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2292,3 +2292,17 @@ of :class:`enum.Enum`.
.. attribute:: slurs

Represents the slurs keyword preset rule.

.. class:: ReactionType

Represents a Reaction's type.

.. versionadded:: 2.5

.. attribute:: normal

Represents a normal reaction.

.. attribute:: burst

Represents a super reaction.
3 changes: 3 additions & 0 deletions docs/api/models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ Messages
.. automethod:: users
:async-for:

.. autoclass:: ReactionCountDetails()
:members:

Guild
-----

Expand Down
2 changes: 1 addition & 1 deletion requirements/dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-r _.txt
pylint~=2.17.5
pytest~=7.4.2
pytest~=7.4.3
pytest-asyncio~=0.21.1
# pytest-order~=1.0.1
mypy~=1.5.1
Expand Down

0 comments on commit d899980

Please sign in to comment.