Skip to content

Commit 3ddef7d

Browse files
committed
updates and typings and things
1 parent 2ca6a00 commit 3ddef7d

File tree

3 files changed

+31
-26
lines changed

3 files changed

+31
-26
lines changed

discord/ui/select.py

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import inspect
2929
import os
3030
from collections.abc import Sequence
31-
from typing import TYPE_CHECKING, Callable, TypeVar
31+
from typing import TYPE_CHECKING, Any, Callable, Generic, TypeVar
3232

3333
from ..channel import _threaded_guild_channel_factory
3434
from ..components import SelectDefaultValue, SelectMenu, SelectOption
@@ -62,11 +62,15 @@
6262
from ..types.interactions import ComponentInteractionData
6363
from .view import View
6464

65+
ST = TypeVar("ST", bound=Snowflake | str, covariant=True, default=Any)
66+
else:
67+
ST = TypeVar("ST", bound="Snowflake | str", covariant=True)
68+
6569
S = TypeVar("S", bound="Select")
6670
V = TypeVar("V", bound="View", covariant=True)
6771

6872

69-
class Select(Item[V]):
73+
class Select(Generic[V, ST], Item[V]):
7074
"""Represents a UI select menu.
7175
7276
This is usually represented as a drop down menu.
@@ -198,7 +202,7 @@ def __init__(
198202
label: str | None = None,
199203
description: str | None = None,
200204
required: bool | None = None,
201-
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
205+
default_values: Sequence[SelectDefaultValue | ST] | None = None,
202206
) -> None:
203207
if options and select_type is not ComponentType.string_select:
204208
raise InvalidArgument("options parameter is only valid for string selects")
@@ -247,7 +251,7 @@ def __init__(
247251
self.row = row
248252

249253
def _handle_default_values(
250-
self, default_values: Sequence[Snowflake] | None, select_type: ComponentType
254+
self, default_values: Sequence[Snowflake | ST] | None, select_type: ComponentType
251255
) -> list[SelectDefaultValue]:
252256
if not default_values:
253257
return []
@@ -320,7 +324,7 @@ def disabled(self) -> bool:
320324
@property
321325
def required(self) -> bool:
322326
"""Whether the select is required or not. Only applicable in modal selects."""
323-
return self._underlying.required
327+
return bool(self._underlying.required)
324328

325329
@required.setter
326330
def required(self, value: bool):
@@ -368,7 +372,7 @@ def default_values(self) -> list[SelectDefaultValue]:
368372

369373
@default_values.setter
370374
def default_values(
371-
self, values: list[SelectDefaultValue | Snowflake] | None
375+
self, values: Sequence[SelectDefaultValue | ST] | None
372376
) -> None:
373377
default_values = self._handle_default_values(values, self.type)
374378
self._underlying.default_values = default_values
@@ -555,29 +559,25 @@ def append_option(self, option: SelectOption) -> Self:
555559
return self
556560

557561
@property
558-
def values(
559-
self,
560-
) -> (
561-
list[str]
562-
| list[Member | User]
563-
| list[Role]
564-
| list[Member | User | Role]
565-
| list[GuildChannel | Thread]
566-
):
562+
def values(self) -> list[ST]:
567563
"""List[:class:`str`] | List[:class:`discord.Member` | :class:`discord.User`]] | List[:class:`discord.Role`]] |
568564
List[:class:`discord.Member` | :class:`discord.User` | :class:`discord.Role`]] | List[:class:`discord.abc.GuildChannel`] | None:
569565
A list of values that have been selected by the user. This will be ``None`` if the select has not been interacted with yet.
570566
"""
571-
if self._interaction is None:
567+
if self._interaction is None or self._interaction.data is None:
572568
# The select has not been interacted with yet
573-
return None
569+
return []
574570
select_type = self._underlying.type
575571
if select_type is ComponentType.string_select:
576-
return self._selected_values
572+
return self._selected_values # type: ignore # ST is str
577573
resolved = []
578574
selected_values = list(self._selected_values)
579575
state = self._interaction._state
580576
guild = self._interaction.guild
577+
578+
if guild is None:
579+
return []
580+
581581
resolved_data = self._interaction.data.get("resolved", {})
582582
if select_type is ComponentType.channel_select:
583583
for channel_id, _data in resolved_data.get("channels", {}).items():
@@ -602,6 +602,9 @@ def values(
602602
# For threads, if this fallback occurs, info like thread owner id, message count,
603603
# flags, and more will be missing due to a lack of data sent by Discord.
604604
obj_type = _threaded_guild_channel_factory(_data["type"])[0]
605+
if obj_type is None:
606+
# should not be None, but assert anyways
607+
continue
605608
result = obj_type(state=state, data=_data, guild=guild)
606609
resolved.append(result)
607610
elif select_type in (
@@ -642,7 +645,7 @@ def refresh_component(self, component: SelectMenu) -> None:
642645

643646
def refresh_state(self, interaction: Interaction | dict) -> None:
644647
data: ComponentInteractionData = (
645-
interaction.data if isinstance(interaction, Interaction) else interaction
648+
interaction.data if isinstance(interaction, Interaction) else interaction # type: ignore
646649
)
647650
self._selected_values = data.get("values", [])
648651
self._interaction = interaction
@@ -704,7 +707,7 @@ def select(
704707
row: int | None = None,
705708
id: int | None = None,
706709
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
707-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
710+
) -> Callable[[ItemCallbackType[Select[V, ST]]], Select[V, ST]]:
708711
"""A decorator that attaches a select menu to a component.
709712
710713
The function being decorated should have three parameters, ``self`` representing
@@ -842,7 +845,7 @@ def string_select(
842845
disabled: bool = False,
843846
row: int | None = None,
844847
id: int | None = None,
845-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
848+
) -> Callable[[ItemCallbackType[Select[V, str]]], Select[V, str]]:
846849
"""A shortcut for :meth:`discord.ui.select` with select type :attr:`discord.ComponentType.string_select`.
847850
848851
.. versionadded:: 2.3
@@ -870,7 +873,7 @@ def user_select(
870873
row: int | None = None,
871874
id: int | None = None,
872875
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
873-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
876+
) -> Callable[[ItemCallbackType[Select[V, User | Member]]], Select[V, User | Member]]:
874877
"""A shortcut for :meth:`discord.ui.select` with select type :attr:`discord.ComponentType.user_select`.
875878
876879
.. versionadded:: 2.3
@@ -898,7 +901,7 @@ def role_select(
898901
row: int | None = None,
899902
id: int | None = None,
900903
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
901-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
904+
) -> Callable[[ItemCallbackType[Select[V, Any]]], Select[V, Role]]:
902905
"""A shortcut for :meth:`discord.ui.select` with select type :attr:`discord.ComponentType.role_select`.
903906
904907
.. versionadded:: 2.3
@@ -926,7 +929,7 @@ def mentionable_select(
926929
row: int | None = None,
927930
id: int | None = None,
928931
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
929-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
932+
) -> Callable[[ItemCallbackType[Select[V, Role | User | Member]]], Select[V, Role | User | Member]]:
930933
"""A shortcut for :meth:`discord.ui.select` with select type :attr:`discord.ComponentType.mentionable_select`.
931934
932935
.. versionadded:: 2.3
@@ -955,7 +958,7 @@ def channel_select(
955958
row: int | None = None,
956959
id: int | None = None,
957960
default_values: Sequence[SelectDefaultValue | Snowflake] | None = None,
958-
) -> Callable[[ItemCallbackType[Select[V]]], Select[V]]:
961+
) -> Callable[[ItemCallbackType[Select[V, GuildChannel]]], Select[V, GuildChannel]]:
959962
"""A shortcut for :meth:`discord.ui.select` with select type :attr:`discord.ComponentType.channel_select`.
960963
961964
.. versionadded:: 2.3

examples/views/channel_select.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ async def channel_select_dropdown(
1717
select.default_values = select.values # this is a list of GuildChannels
1818
await interaction.response.send_message(
1919
"You selected the following channels:"
20-
+ ", ".join(f"{channel.mention}" for channel in select.values)
20+
+ ", ".join(f"{channel.mention}" for channel in select.values),
21+
view=self,
2122
)
2223

2324

examples/views/role_select.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from typing import Self
12
import discord
23

34
# Role selects (dropdowns) are a new type of select menu/dropdown Discord has added so people can select server roles from a dropdown.

0 commit comments

Comments
 (0)