Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(modal, embeds): new method for Embed and metaclass for class Modal #1254

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
style: fix annotations
shayzi3 committed Dec 10, 2024
commit ba2eed8023eb0b64d7447ea678c6aa8c62672c61
1 change: 1 addition & 0 deletions disnake/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: MIT

from __future__ import annotations

import asyncio
import logging
import signal
22 changes: 10 additions & 12 deletions disnake/embeds.py
Original file line number Diff line number Diff line change
@@ -674,19 +674,18 @@ def insert_field_at(self, index: int, name: Any, value: Any, *, inline: bool = T
self._fields = [field]

return self



def add_some_fields(self, *data: Dict[str, Any]) -> Self:
"""This function allows you to create several fields at once
"""Function allows you to create several fields at once

This function returns the class instance to allow for fluent-style
chaining.

Parameters
----------
data: :class:`dict`
data: :class:`dict`
field data in dictionary

Example:
add_some_fields(
{"name": "Jack", "value": "Barker", "inline": False}
@@ -697,22 +696,21 @@ def add_some_fields(self, *data: Dict[str, Any]) -> Self:
for element in data:
if (element.get("name") is None) or (element.get("value") is None):
raise TypeError("Missing argument. Name and Value - required.")

fields.append(
{
"inline": element.get("inline"),
"inline": bool(element.get("inline")),
"name": str(element.get("name")),
"value": str(element.get("value"))
"value": str(element.get("value")),
}
)

if self._fields is not None:
self._fields.extend(fields)
else:
self._fields = fields

return self


def clear_fields(self) -> None:
"""Removes all fields from this embed."""
@@ -931,4 +929,4 @@ def check_limits(self) -> None:
)

if len(self) > 6000:
raise ValueError("Embed total size cannot be longer than 6000 characters")
raise ValueError("Embed total size cannot be longer than 6000 characters")
46 changes: 22 additions & 24 deletions disnake/ui/modal.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
import os
import sys
import traceback
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, TypeVar, Union, Type
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, TypeVar, Union

from ..enums import TextInputStyle
from .action_row import ActionRow, components_to_rows
@@ -26,32 +26,30 @@
ClientT = TypeVar("ClientT", bound="Client")



class ModalMeta(type):
"""A metaclass for defining a modal"""

def __new__(cls: Type[ModalMeta], *args: Any, **kwargs: Any) -> ModalMeta:
name, bases, attrs = args
if not bases:
return super().__new__(cls, name, bases, attrs)

components: Components[ModalUIComponent] = []
for value in attrs.values():
if isinstance(value, TextInput):
components.append(value)

if not components:
raise TypeError(f"No text inputs found for class {name}")

rows: List[ActionRow] = components_to_rows(components)
if len(rows) > 5:
raise ValueError("Maximum number of components exceeded. Max components - 5")

attrs.update({"components": rows})
return super().__new__(cls, name, bases, attrs)



class Modal(metaclass=ModalMeta):
"""Represents a UI Modal.

@@ -65,13 +63,13 @@ class Modal(metaclass=ModalMeta):
The time to wait until the modal is removed from cache, if no interaction is made.
Modals without timeouts are not supported, since there's no event for when a modal is closed.
Defaults to 600 seconds.

Example:
class MyModal(disnake.ui.Modal):
__title__ = "Register"
__custom_id__ = "register-modal"
__timeout__ = 100

username = TextInput(
label="Username",
custom_id="username"
@@ -86,29 +84,30 @@ class MyModal(disnake.ui.Modal):
required=False
)
"""

__title__: str
__custom_id__: str
__timeout__: float

__slots__ = ("title", "custom_id", "components", "timeout")

def __init__(self) -> None:
modal_dict = self.__class__.__dict__
self.title: Union[str, None] = modal_dict.get("__title__")
self.custom_id: Union[str, None] = modal_dict.get("__custom_id__")
self.timeout: Union[float, None] = modal_dict.get("__timeout__")
self.components: Union[List[ActionRow], None] = modal_dict.get("components")
if self.title is None:

self.title: str = modal_dict.get("__title__", str)
self.custom_id: str = modal_dict.get("__custom_id__", str)
self.timeout: float = modal_dict.get("__timeout__", float)
self.components: List[ActionRow] = modal_dict.get("components", List[ActionRow])

if not self.title:
raise TypeError("Missing required argument __title__")
if self.custom_id is None:

if not self.custom_id:
self.custom_id = os.urandom(16).hex()
if self.timeout is None:

if not self.timeout:
self.timeout = 600

def __repr__(self) -> str:
return (
f"<Modal custom_id={self.custom_id!r} title={self.title!r} "
@@ -238,7 +237,6 @@ async def on_timeout(self) -> None:
without an interaction being made.
"""
pass


def to_components(self) -> ModalPayload:
payload: ModalPayload = {
2 changes: 1 addition & 1 deletion examples/interactions/modal.py
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@
class MyModal(disnake.ui.Modal):
__title__ = "Create Tag"
__custom_id__ = "create_tag"

name = disnake.ui.TextInput(
label="Name",
placeholder="The name of the tag",
4 changes: 2 additions & 2 deletions test_bot/cogs/modals.py
Original file line number Diff line number Diff line change
@@ -8,15 +8,15 @@
class MyModal(disnake.ui.Modal):
__title__ = "Create Tag"
__custom_id__ = "create_tag"

name = disnake.ui.TextInput(
label="Name",
placeholder="The name of the tag",
custom_id="name",
style=TextInputStyle.short,
max_length=50,
)

description = disnake.ui.TextInput(
label="Description",
placeholder="The description of the tag",
Loading