Skip to content

Commit cd9ca50

Browse files
NeloBlivionpre-commit-ci[bot]plun1331JustaSqu1dDorukyum
authored
feat: Polls (#2408)
Signed-off-by: UK <[email protected]> Signed-off-by: Lala Sabathil <[email protected]> Signed-off-by: Dorukyum <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: plun1331 <[email protected]> Co-authored-by: JustaSqu1d <[email protected]> Co-authored-by: Dorukyum <[email protected]> Co-authored-by: Lala Sabathil <[email protected]>
1 parent 58a329f commit cd9ca50

21 files changed

+1136
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ These changes are available on the `master` branch, but have not yet been releas
2424
([#2421](https://github.com/Pycord-Development/pycord/pull/2421))
2525
- Added `member` data to the `raw_reaction_remove` event.
2626
([#2412](https://github.com/Pycord-Development/pycord/pull/2412))
27+
- Added `Poll` and all related features.
28+
([#2408](https://github.com/Pycord-Development/pycord/pull/2408))
2729
- Added `stacklevel` param to `utils.warn_deprecated` and `utils.deprecated`.
2830
([#2450](https://github.com/Pycord-Development/pycord/pull/2450))
2931

discord/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from .partial_emoji import *
5959
from .permissions import *
6060
from .player import *
61+
from .poll import *
6162
from .raw_models import *
6263
from .reaction import *
6364
from .role import *

discord/abc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
from .guild import Guild
9090
from .member import Member
9191
from .message import Message, MessageReference, PartialMessage
92+
from .poll import Poll
9293
from .state import ConnectionState
9394
from .threads import Thread
9495
from .types.channel import Channel as ChannelPayload
@@ -1351,6 +1352,7 @@ async def send(
13511352
reference: Message | MessageReference | PartialMessage = ...,
13521353
mention_author: bool = ...,
13531354
view: View = ...,
1355+
poll: Poll = ...,
13541356
suppress: bool = ...,
13551357
silent: bool = ...,
13561358
) -> Message: ...
@@ -1371,6 +1373,7 @@ async def send(
13711373
reference: Message | MessageReference | PartialMessage = ...,
13721374
mention_author: bool = ...,
13731375
view: View = ...,
1376+
poll: Poll = ...,
13741377
suppress: bool = ...,
13751378
silent: bool = ...,
13761379
) -> Message: ...
@@ -1391,6 +1394,7 @@ async def send(
13911394
reference: Message | MessageReference | PartialMessage = ...,
13921395
mention_author: bool = ...,
13931396
view: View = ...,
1397+
poll: Poll = ...,
13941398
suppress: bool = ...,
13951399
silent: bool = ...,
13961400
) -> Message: ...
@@ -1411,6 +1415,7 @@ async def send(
14111415
reference: Message | MessageReference | PartialMessage = ...,
14121416
mention_author: bool = ...,
14131417
view: View = ...,
1418+
poll: Poll = ...,
14141419
suppress: bool = ...,
14151420
silent: bool = ...,
14161421
) -> Message: ...
@@ -1432,6 +1437,7 @@ async def send(
14321437
reference=None,
14331438
mention_author=None,
14341439
view=None,
1440+
poll=None,
14351441
suppress=None,
14361442
silent=None,
14371443
):
@@ -1515,6 +1521,10 @@ async def send(
15151521
Whether to suppress push and desktop notifications for the message.
15161522
15171523
.. versionadded:: 2.4
1524+
poll: :class:`Poll`
1525+
The poll to send.
1526+
1527+
.. versionadded:: 2.6
15181528
15191529
Returns
15201530
-------
@@ -1594,6 +1604,9 @@ async def send(
15941604
else:
15951605
components = None
15961606

1607+
if poll:
1608+
poll = poll.to_dict()
1609+
15971610
if file is not None and files is not None:
15981611
raise InvalidArgument("cannot pass both file and files parameter to send()")
15991612

@@ -1616,6 +1629,7 @@ async def send(
16161629
stickers=stickers,
16171630
components=components,
16181631
flags=flags,
1632+
poll=poll,
16191633
)
16201634
finally:
16211635
file.close()
@@ -1643,6 +1657,7 @@ async def send(
16431657
stickers=stickers,
16441658
components=components,
16451659
flags=flags,
1660+
poll=poll,
16461661
)
16471662
finally:
16481663
for f in files:
@@ -1661,6 +1676,7 @@ async def send(
16611676
stickers=stickers,
16621677
components=components,
16631678
flags=flags,
1679+
poll=poll,
16641680
)
16651681

16661682
ret = state.create_message(channel=channel, data=data)

discord/client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
from .channel import DMChannel
7171
from .member import Member
7272
from .message import Message
73+
from .poll import Poll
7374
from .voice_client import VoiceProtocol
7475

7576
__all__ = ("Client",)
@@ -338,6 +339,14 @@ def stickers(self) -> list[GuildSticker]:
338339
"""
339340
return self._connection.stickers
340341

342+
@property
343+
def polls(self) -> list[Poll]:
344+
"""The polls that the connected client has.
345+
346+
.. versionadded:: 2.6
347+
"""
348+
return self._connection.polls
349+
341350
@property
342351
def cached_messages(self) -> Sequence[Message]:
343352
"""Read-only list of messages the connected client has cached.
@@ -1010,6 +1019,21 @@ def get_sticker(self, id: int, /) -> GuildSticker | None:
10101019
"""
10111020
return self._connection.get_sticker(id)
10121021

1022+
def get_poll(self, id: int, /) -> Poll | None:
1023+
"""Returns a poll attached to the given message ID.
1024+
1025+
Parameters
1026+
----------
1027+
id: :class:`int`
1028+
The message ID of the poll to search for.
1029+
1030+
Returns
1031+
-------
1032+
Optional[:class:`.Poll`]
1033+
The poll or ``None`` if not found.
1034+
"""
1035+
return self._connection.get_poll(id)
1036+
10131037
def get_all_channels(self) -> Generator[GuildChannel, None, None]:
10141038
"""A generator that retrieves every :class:`.abc.GuildChannel` the client can 'access'.
10151039

discord/enums.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,12 @@ class EntitlementOwnerType(Enum):
10201020
user = 2
10211021

10221022

1023+
class PollLayoutType(Enum):
1024+
"""The poll's layout type."""
1025+
1026+
default = 1
1027+
1028+
10231029
T = TypeVar("T")
10241030

10251031

discord/flags.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,8 @@ def messages(self):
885885
- :class:`Message`
886886
- :attr:`Client.cached_messages`
887887
- :meth:`Client.get_message`
888+
- :attr:`Client.polls`
889+
- :meth:`Client.get_poll`
888890
889891
Note that due to an implicit relationship this also corresponds to the following events:
890892
@@ -917,6 +919,8 @@ def guild_messages(self):
917919
- :class:`Message`
918920
- :attr:`Client.cached_messages` (only for guilds)
919921
- :meth:`Client.get_message` (only for guilds)
922+
- :attr:`Client.polls` (only for guilds)
923+
- :meth:`Client.get_poll` (only for guilds)
920924
921925
Note that due to an implicit relationship this also corresponds to the following events:
922926
@@ -931,6 +935,7 @@ def guild_messages(self):
931935
- :attr:`Message.embeds`
932936
- :attr:`Message.attachments`
933937
- :attr:`Message.components`
938+
- :attr:`Message.poll`
934939
935940
For more information go to the :ref:`message content intent documentation <need_message_content_intent>`.
936941
"""
@@ -955,6 +960,8 @@ def dm_messages(self):
955960
- :class:`Message`
956961
- :attr:`Client.cached_messages` (only for DMs)
957962
- :meth:`Client.get_message` (only for DMs)
963+
- :attr:`Client.polls` (only for DMs)
964+
- :meth:`Client.get_poll` (only for DMs)
958965
959966
Note that due to an implicit relationship this also corresponds to the following events:
960967
@@ -1079,6 +1086,7 @@ def message_content(self):
10791086
- :attr:`Message.embeds`
10801087
- :attr:`Message.attachments`
10811088
- :attr:`Message.components`
1089+
- :attr:`Message.poll`
10821090
10831091
These attributes will still be available for messages received from interactions,
10841092
the bot's own messages, messages the bot was mentioned in, and DMs.
@@ -1137,6 +1145,66 @@ def auto_moderation_execution(self):
11371145
"""
11381146
return 1 << 21
11391147

1148+
@flag_value
1149+
def guild_polls(self):
1150+
""":class:`bool`: Whether poll-related events in guilds are enabled.
1151+
1152+
See also :attr:`dm_polls` for DMs or :attr:`polls` for both.
1153+
1154+
This corresponds to the following events:
1155+
1156+
- :func:`on_poll_vote_add` (only for guilds)
1157+
- :func:`on_poll_vote_remove` (only for guilds)
1158+
- :func:`on_raw_poll_vote_add` (only for guilds)
1159+
- :func:`on_raw_poll_vote_remove` (only for guilds)
1160+
1161+
This also corresponds to the following attributes and classes in terms of cache:
1162+
1163+
- :attr:`PollAnswer.count` (only for guild polls)
1164+
- :attr:`PollResults.answer_counts` (only for guild polls)
1165+
"""
1166+
return 1 << 24
1167+
1168+
@flag_value
1169+
def dm_polls(self):
1170+
""":class:`bool`: Whether poll-related events in direct messages are enabled.
1171+
1172+
See also :attr:`guild_polls` for guilds or :attr:`polls` for both.
1173+
1174+
This corresponds to the following events:
1175+
1176+
- :func:`on_poll_vote_add` (only for DMs)
1177+
- :func:`on_poll_vote_remove` (only for DMs)
1178+
- :func:`on_raw_poll_vote_add` (only for DMs)
1179+
- :func:`on_raw_poll_vote_remove` (only for DMs)
1180+
1181+
This also corresponds to the following attributes and classes in terms of cache:
1182+
1183+
- :attr:`PollAnswer.count` (only for DM polls)
1184+
- :attr:`PollResults.answer_counts` (only for DM polls)
1185+
"""
1186+
return 1 << 25
1187+
1188+
@alias_flag_value
1189+
def polls(self):
1190+
""":class:`bool`: Whether poll-related events in guilds and direct messages are enabled.
1191+
1192+
This is a shortcut to set or get both :attr:`guild_polls` and :attr:`dm_polls`.
1193+
1194+
This corresponds to the following events:
1195+
1196+
- :func:`on_poll_vote_add` (both guilds and DMs)
1197+
- :func:`on_poll_vote_remove` (both guilds and DMs)
1198+
- :func:`on_raw_poll_vote_add` (both guilds and DMs)
1199+
- :func:`on_raw_poll_vote_remove` (both guilds and DMs)
1200+
1201+
This also corresponds to the following attributes and classes in terms of cache:
1202+
1203+
- :attr:`PollAnswer.count` (both guild and DM polls)
1204+
- :attr:`PollResults.answer_counts` (both guild and DM polls)
1205+
"""
1206+
return (1 << 24) | (1 << 25)
1207+
11401208

11411209
@fill_with_flags()
11421210
class MemberCacheFlags(BaseFlags):

discord/http.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
message,
7272
monetization,
7373
onboarding,
74+
poll,
7475
role,
7576
scheduled_events,
7677
sticker,
@@ -471,6 +472,7 @@ def send_message(
471472
stickers: list[sticker.StickerItem] | None = None,
472473
components: list[components.Component] | None = None,
473474
flags: int | None = None,
475+
poll: poll.Poll | None = None,
474476
) -> Response[message.Message]:
475477
r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id)
476478
payload = {}
@@ -508,6 +510,9 @@ def send_message(
508510
if flags:
509511
payload["flags"] = flags
510512

513+
if poll:
514+
payload["poll"] = poll
515+
511516
return self.request(r, json=payload)
512517

513518
def send_typing(self, channel_id: Snowflake) -> Response[None]:
@@ -531,6 +536,7 @@ def send_multipart_helper(
531536
stickers: list[sticker.StickerItem] | None = None,
532537
components: list[components.Component] | None = None,
533538
flags: int | None = None,
539+
poll: poll.Poll | None = None,
534540
) -> Response[message.Message]:
535541
form = []
536542

@@ -555,6 +561,8 @@ def send_multipart_helper(
555561
payload["sticker_ids"] = stickers
556562
if flags:
557563
payload["flags"] = flags
564+
if poll:
565+
payload["poll"] = poll
558566

559567
attachments = []
560568
form.append({"name": "payload_json"})
@@ -594,6 +602,7 @@ def send_files(
594602
stickers: list[sticker.StickerItem] | None = None,
595603
components: list[components.Component] | None = None,
596604
flags: int | None = None,
605+
poll: poll.Poll | None = None,
597606
) -> Response[message.Message]:
598607
r = Route("POST", "/channels/{channel_id}/messages", channel_id=channel_id)
599608
return self.send_multipart_helper(
@@ -610,6 +619,7 @@ def send_files(
610619
stickers=stickers,
611620
components=components,
612621
flags=flags,
622+
poll=poll,
613623
)
614624

615625
def edit_multipart_helper(
@@ -3003,6 +3013,43 @@ def edit_onboarding(
30033013
reason=reason,
30043014
)
30053015

3016+
# Polls
3017+
3018+
def expire_poll(
3019+
self, channel_id: Snowflake, message_id: Snowflake
3020+
) -> Response[message.Message]:
3021+
return self.request(
3022+
Route(
3023+
"POST",
3024+
"/channels/{channel_id}/polls/{message_id}/expire",
3025+
channel_id=channel_id,
3026+
message_id=message_id,
3027+
)
3028+
)
3029+
3030+
def get_answer_voters(
3031+
self,
3032+
channel_id: Snowflake,
3033+
message_id: Snowflake,
3034+
answer_id: int,
3035+
limit: int,
3036+
after: Snowflake | None = None,
3037+
) -> Response[list[user.User]]:
3038+
r = Route(
3039+
"GET",
3040+
"/channels/{channel_id}/polls/{message_id}/answers/{answer_id}",
3041+
channel_id=channel_id,
3042+
message_id=message_id,
3043+
answer_id=answer_id,
3044+
)
3045+
3046+
params: dict[str, Any] = {
3047+
"limit": limit,
3048+
}
3049+
if after:
3050+
params["after"] = after
3051+
return self.request(r, params=params)
3052+
30063053
# Misc
30073054

30083055
def application_info(self) -> Response[appinfo.AppInfo]:

0 commit comments

Comments
 (0)