Skip to content

Commit 4742b65

Browse files
committed
paillait comment
1 parent 38e0034 commit 4742b65

5 files changed

Lines changed: 155 additions & 45 deletions

File tree

discord/guild.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4330,7 +4330,7 @@ async def create_scheduled_event(
43304330
entity_type: ScheduledEventEntityType = MISSING,
43314331
entity_metadata: ScheduledEventEntityMetadata | None = MISSING,
43324332
channel_id: int = MISSING,
4333-
privacy_level: ScheduledEventPrivacyLevel = MISSING,
4333+
privacy_level: ScheduledEventPrivacyLevel = ScheduledEventPrivacyLevel.guild_only,
43344334
reason: str | None = None,
43354335
image: bytes = MISSING,
43364336
start_time: datetime.datetime = MISSING,
@@ -4382,26 +4382,19 @@ async def create_scheduled_event(
43824382
ValidationError
43834383
Invalid parameters for the event type.
43844384
"""
4385-
if privacy_level is not MISSING:
4386-
warn_deprecated(
4387-
"privacy_level",
4388-
None,
4389-
"3.0",
4390-
extra="It is ignored by the API and will be removed in a future version.",
4391-
)
43924385
if location is MISSING and entity_type is MISSING:
43934386
raise TypeError("Either location or entity_type must be provided.")
43944387
if start_time is MISSING and scheduled_start_time is MISSING:
43954388
raise TypeError(
43964389
"Either start_time or scheduled_start_time must be provided."
43974390
)
43984391
if start_time is not MISSING:
4399-
warn_deprecated("start_time", "scheduled_start_time", "2.7")
4392+
warn_deprecated("start_time", "scheduled_start_time", "2.7", "3.0")
44004393
if scheduled_start_time is MISSING:
44014394
scheduled_start_time = start_time
44024395

44034396
if end_time is not MISSING:
4404-
warn_deprecated("end_time", "scheduled_end_time", "2.7")
4397+
warn_deprecated("end_time", "scheduled_end_time", "2.7", "3.0")
44054398
if scheduled_end_time is MISSING:
44064399
scheduled_end_time = end_time
44074400

@@ -4422,10 +4415,12 @@ async def create_scheduled_event(
44224415
"entity_type could not be resolved. Pass entity_type explicitly "
44234416
"or provide a location with a resolvable type."
44244417
)
4418+
44254419
payload: dict[str, str | int] = {
44264420
"name": name,
44274421
"scheduled_start_time": scheduled_start_time.isoformat(),
44284422
"entity_type": int(entity_type),
4423+
"privacy_level": int(privacy_level),
44294424
}
44304425

44314426
if scheduled_end_time is not MISSING:

discord/scheduled_events.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,7 @@
5656
from .member import Member
5757
from .state import ConnectionState
5858
from .types.scheduled_events import ScheduledEvent as ScheduledEventPayload
59-
else:
60-
ConnectionState = None
61-
StageChannel = None
62-
VoiceChannel = None
59+
6360

6461
MISSING = utils.MISSING
6562

@@ -100,10 +97,12 @@ def __init__(
10097
*,
10198
state: ConnectionState | None = None,
10299
value: str | int | StageChannel | VoiceChannel | None = None,
100+
_suppress_deprecation: bool = False,
103101
) -> None:
104-
warn_deprecated("ScheduledEventLocation", "ScheduledEventEntityMetadata", "2.7")
102+
if not _suppress_deprecation:
103+
warn_deprecated("ScheduledEventLocation", "ScheduledEventEntityMetadata", "2.7")
105104
self._state: ConnectionState | None = state
106-
self.value: str | StageChannel | VoiceChannel | Object | None
105+
self.value: str | "StageChannel" | "VoiceChannel" | Object | None
107106
if value is None:
108107
self.value = None
109108
elif isinstance(value, int):
@@ -161,12 +160,12 @@ def __repr__(self) -> str:
161160
def __str__(self) -> str:
162161
return self.location or ""
163162

164-
def to_payload(self) -> dict[str, str]:
163+
def to_payload(self) -> dict[str, str | None]:
165164
"""Converts the entity metadata to a Discord API payload.
166165
167166
Returns
168167
-------
169-
dict[str, str]
168+
dict[str, str | None]
170169
A dictionary with the entity metadata fields for the API.
171170
"""
172171
return {"location": self.location}
@@ -322,9 +321,9 @@ def location(self) -> ScheduledEventLocation | None:
322321
if self.entity_metadata is None:
323322
return None
324323
return ScheduledEventLocation(
325-
state=self._state, value=self.entity_metadata.location
324+
state=self._state, value=self.entity_metadata.location, _suppress_deprecation=True
326325
)
327-
return ScheduledEventLocation(state=self._state, value=self.channel_id)
326+
return ScheduledEventLocation(state=self._state, value=self.channel_id, _suppress_deprecation=True)
328327

329328
@property
330329
def created_at(self) -> datetime.datetime:
@@ -422,6 +421,8 @@ async def edit(
422421
privacy_level: ScheduledEventPrivacyLevel = MISSING,
423422
entity_type: ScheduledEventEntityType = MISSING,
424423
entity_metadata: ScheduledEventEntityMetadata | None = MISSING,
424+
start_time: datetime.datetime = MISSING,
425+
end_time: datetime.datetime = MISSING,
425426
) -> ScheduledEvent | None:
426427
"""|coro|
427428
@@ -519,6 +520,16 @@ async def edit(
519520
if image is MISSING:
520521
image = cover
521522

523+
if start_time is not MISSING:
524+
warn_deprecated("start_time", "scheduled_start_time", "2.7", "3.0")
525+
if scheduled_start_time is MISSING:
526+
scheduled_start_time = start_time
527+
528+
if end_time is not MISSING:
529+
warn_deprecated("end_time", "scheduled_end_time", "2.7", "3.0")
530+
if scheduled_end_time is MISSING:
531+
scheduled_end_time = end_time
532+
522533
if entity_type is not MISSING:
523534
payload["entity_type"] = int(entity_type)
524535

@@ -563,12 +574,13 @@ async def edit(
563574

564575
payload["channel_id"] = None
565576

566-
data = await self._state.http.edit_scheduled_event(
567-
self.guild.id, self.id, **payload, reason=reason
568-
)
569-
return ScheduledEvent(
570-
data=data, guild=self.guild, creator=self.creator, state=self._state
571-
)
577+
if payload != {}:
578+
data = await self._state.http.edit_scheduled_event(
579+
self.guild.id, self.id, **payload, reason=reason
580+
)
581+
return ScheduledEvent(
582+
data=data, guild=self.guild, creator=self.creator, state=self._state
583+
)
572584

573585
async def delete(self) -> None:
574586
"""|coro|

discord/ui/checkbox.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from ..components import Checkbox as CheckboxComponent
3131
from ..enums import ComponentType
32+
from .core import ComponentLimits
3233
from .item import ModalItem
3334

3435
__all__ = ("Checkbox",)
@@ -105,8 +106,10 @@ def custom_id(self) -> str:
105106
def custom_id(self, value: str):
106107
if not isinstance(value, str):
107108
raise TypeError(f"custom_id must be str not {value.__class__.__name__}")
108-
if len(value) > 100:
109-
raise ValueError("custom_id must be 100 characters or fewer")
109+
if len(value) > ComponentLimits.CUSTOM_ID_MAX:
110+
raise ValueError(
111+
f"custom_id must be {ComponentLimits.CUSTOM_ID_MAX} characters or fewer"
112+
)
110113
self.underlying.custom_id = value
111114

112115
@property

discord/ui/core.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,77 @@
3434

3535
__all__ = ("ItemInterface",)
3636

37+
class ComponentLimits:
38+
# View constraints
39+
VIEW_CHILDREN_MAX = 40
40+
41+
# ActionRow constraints
42+
ACTION_ROW_CHILDREN_MAX = 5
43+
44+
# Button constraints
45+
BUTTON_LABEL_MAX = 80
46+
47+
# MediaGallery constraints
48+
MEDIA_GALLERY_ITEMS_MIN = 1
49+
MEDIA_GALLERY_ITEMS_MAX = 10
50+
51+
# MediaGalleryItem constraints
52+
MEDIA_GALLERY_ITEM_DESCRIPTION_MAX = 256
53+
54+
# Select constraints
55+
SELECT_PLACEHOLDER_MAX = 150
56+
SELECT_OPTIONS_MAX = 25
57+
SELECT_DEFAULT_VALUES_MAX = 25
58+
59+
# Select option constraints
60+
SELECT_OPTION_LABEL_MAX = 100
61+
SELECT_OPTION_VALUE_MAX = 100
62+
SELECT_OPTION_DESCRIPTION_MAX = 100
63+
64+
# Section constraints
65+
SECTION_ACCESSORY_MAX = 1
66+
SECTION_CHILDREN_MIN = 1
67+
SECTION_CHILDREN_MAX = 3
68+
69+
# TextInput constraints
70+
TEXT_INPUT_MAX_COUNT = 5
71+
TEXT_INPUT_LABEL_MAX = 45
72+
TEXT_INPUT_PLACEHOLDER_MAX = 100
73+
TEXT_INPUT_MIN_LENGTH_MIN = 0
74+
TEXT_INPUT_MIN_LENGTH_MAX = 4000
75+
TEXT_INPUT_MAX_LENGTH_MIN = 1
76+
TEXT_INPUT_MAX_LENGTH_MAX = 4000
77+
TEXT_INPUT_VALUE_MAX = 4000
78+
79+
# TextDisplay constraints
80+
TEXT_DISPLAY_CONTENT_MAX = 4000
81+
82+
# Thumbnail constraints
83+
THUMBNAIL_DESCRIPTION_MAX = 256
84+
85+
# Custom ID constraints
86+
CUSTOM_ID_MIN = 1
87+
CUSTOM_ID_MAX = 100
88+
89+
# RadioGroup constraints
90+
RADIO_OPTIONS_MAX = 10
91+
92+
# CheckboxGroup constraints
93+
CHECKBOX_OPTIONS_MAX = 10
94+
CHECKBOX_MIN_VALUES_MIN = 0
95+
CHECKBOX_MIN_VALUES_MAX = 10
96+
CHECKBOX_MAX_VALUES_MIN = 1
97+
CHECKBOX_MAX_VALUES_MAX = 10
98+
99+
# FileUpload constraints
100+
FILE_UPLOAD_MIN_FILES = 0
101+
FILE_UPLOAD_MAX_FILES_MIN = 1
102+
FILE_UPLOAD_MAX_FILES_MAX = 10
103+
104+
# Modal constraints
105+
MODAL_TITLE_MAX = 45
106+
MODAL_ROWS_MAX = 5
107+
37108

38109
if TYPE_CHECKING:
39110
from typing_extensions import Self

discord/ui/select.py

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from ..threads import Thread
4646
from ..user import User
4747
from ..utils import MISSING
48+
from .core import ComponentLimits
4849
from .item import ItemCallbackType, ModalItem, ViewItem
4950

5051
__all__ = (
@@ -265,12 +266,24 @@ def __init__(
265266
super().__init__()
266267
self._selected_values: list[str] = []
267268
self._interaction: Interaction | None = None
268-
if min_values < 0 or min_values > 25:
269-
raise ValueError("min_values must be between 0 and 25")
270-
if max_values < 1 or max_values > 25:
271-
raise ValueError("max_values must be between 1 and 25")
272-
if placeholder and len(placeholder) > 150:
273-
raise ValueError("placeholder must be 150 characters or fewer")
269+
if (
270+
min_values < ComponentLimits.SELECT_MIN_VALUE_MIN
271+
or min_values > ComponentLimits.SELECT_MIN_VALUE_MAX
272+
):
273+
raise ValueError(
274+
f"min_values must be between {ComponentLimits.SELECT_MIN_VALUE_MIN} and {ComponentLimits.SELECT_MIN_VALUE_MAX}"
275+
)
276+
if (
277+
max_values < ComponentLimits.SELECT_MAX_VALUE_MIN
278+
or max_values > ComponentLimits.SELECT_MAX_VALUE_MAX
279+
):
280+
raise ValueError(
281+
f"max_values must be between {ComponentLimits.SELECT_MAX_VALUE_MIN} and {ComponentLimits.SELECT_MAX_VALUE_MAX}"
282+
)
283+
if placeholder and len(placeholder) > ComponentLimits.SELECT_PLACEHOLDER_MAX:
284+
raise ValueError(
285+
f"placeholder must be {ComponentLimits.SELECT_PLACEHOLDER_MAX} characters or fewer"
286+
)
274287
if not isinstance(custom_id, str) and custom_id is not None:
275288
raise TypeError(
276289
f"expected custom_id to be str, not {custom_id.__class__.__name__}"
@@ -377,8 +390,10 @@ def custom_id(self) -> str:
377390
def custom_id(self, value: str):
378391
if not isinstance(value, str):
379392
raise TypeError("custom_id must be None or str")
380-
if len(value) > 100:
381-
raise ValueError("custom_id must be 100 characters or fewer")
393+
if len(value) > ComponentLimits.CUSTOM_ID_MAX:
394+
raise ValueError(
395+
f"custom_id must be {ComponentLimits.CUSTOM_ID_MAX} characters or fewer"
396+
)
382397
self.underlying.custom_id = value
383398
self._provided_custom_id = value is not None
384399

@@ -391,8 +406,10 @@ def placeholder(self) -> str | None:
391406
def placeholder(self, value: str | None):
392407
if value is not None and not isinstance(value, str):
393408
raise TypeError("placeholder must be None or str")
394-
if value and len(value) > 150:
395-
raise ValueError("placeholder must be 150 characters or fewer")
409+
if value and len(value) > ComponentLimits.SELECT_PLACEHOLDER_MAX:
410+
raise ValueError(
411+
f"placeholder must be {ComponentLimits.SELECT_PLACEHOLDER_MAX} characters or fewer"
412+
)
396413

397414
self.underlying.placeholder = value
398415

@@ -403,8 +420,13 @@ def min_values(self) -> int:
403420

404421
@min_values.setter
405422
def min_values(self, value: int):
406-
if value < 0 or value > 25:
407-
raise ValueError("min_values must be between 0 and 25")
423+
if (
424+
value < ComponentLimits.SELECT_MIN_VALUE_MIN
425+
or value > ComponentLimits.SELECT_MIN_VALUE_MAX
426+
):
427+
raise ValueError(
428+
f"min_values must be between {ComponentLimits.SELECT_MIN_VALUE_MIN} and {ComponentLimits.SELECT_MIN_VALUE_MAX}"
429+
)
408430
self.underlying.min_values = int(value)
409431

410432
@property
@@ -414,8 +436,13 @@ def max_values(self) -> int:
414436

415437
@max_values.setter
416438
def max_values(self, value: int):
417-
if value < 1 or value > 25:
418-
raise ValueError("max_values must be between 1 and 25")
439+
if (
440+
value < ComponentLimits.SELECT_MAX_VALUE_MIN
441+
or value > ComponentLimits.SELECT_MAX_VALUE_MAX
442+
):
443+
raise ValueError(
444+
f"max_values must be between {ComponentLimits.SELECT_MAX_VALUE_MIN} and {ComponentLimits.SELECT_MAX_VALUE_MAX}"
445+
)
419446
self.underlying.max_values = int(value)
420447

421448
@property
@@ -575,8 +602,10 @@ def append_default_value(
575602
if self.type is ComponentType.string_select:
576603
raise TypeError("string_select selects do not allow default_values")
577604

578-
if len(self.default_values) >= 25:
579-
raise ValueError("maximum number of default values exceeded (25)")
605+
if len(self.default_values) >= ComponentLimits.SELECT_DEFAULT_VALUES_MAX:
606+
raise ValueError(
607+
f"maximum number of default values exceeded ({ComponentLimits.SELECT_DEFAULT_VALUES_MAX})"
608+
)
580609

581610
if not isinstance(value, SelectDefaultValue):
582611
value = SelectDefaultValue._handle_model(value)
@@ -654,7 +683,7 @@ def append_option(self, option: SelectOption) -> Self:
654683
if self.underlying.type is not ComponentType.string_select:
655684
raise Exception("options can only be set on string selects")
656685

657-
if len(self.underlying.options) > 25:
686+
if len(self.underlying.options) > ComponentLimits.SELECT_OPTIONS_MAX:
658687
raise ValueError("maximum number of options already provided")
659688

660689
self.underlying.options.append(option)

0 commit comments

Comments
 (0)