Passed
Pull Request — main (#389)
by
unknown
01:49
created

_PartialSelectMenu.register()   A

Complexity

Conditions 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from functools import partial
5
from inspect import iscoroutinefunction
6
from typing import Any, List
7
8
from .button import Button, ButtonStyle
9
from .select_menu import SelectMenu, SelectOption
10
from .component_handler import ComponentHandler
11
from ..interactable import PartialInteractable
12
from ...objects.app.command import InteractableStructure
13
from ...exceptions import CommandIsNotCoroutine
14
from ...objects.message.emoji import Emoji
15
from ...utils.conversion import remove_none
16
17
18
def component(custom_id):
19
    """
20
    Generic handler for Message Components. Can be used with manually constructed
21
    :class:`~pincer.commands.components.button.Button` and
22
    :class:`~pincer.commands.components.select_menu.SelectMenu` objects.
23
24
    Parameters
25
    ---------
26
    custom_id : str
27
        The ID of the message component to handle.
28
    """
29
    def wrap(custom_id, func):
30
        ComponentHandler().register_id(_id=custom_id, func=func)
31
        return func
32
33
    return partial(wrap, custom_id)
34
35
36
def button(
0 ignored issues
show
best-practice introduced by
Too many arguments (6/5)
Loading history...
37
    label: str,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
38
    style: ButtonStyle,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
39
    emoji: Emoji = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
40
    url: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
41
    disabled: bool = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
42
    custom_id: str = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
43
) -> Button:
44
    """
45
    Turn a function into handler for a :class:`~pincer.commands.components.button.Button`.
46
    See :class:`~pincer.commands.components.button.Button` for information on parameters.
47
48
    The function will still be callable.
49
50
    .. code-block:: python
51
52
        from pincer.commands import ActionRow, Button
53
54
        class Bot(Client):
55
56
            @command
57
            async def send_a_button(self):
58
                return Message(
59
                    content="Click a button",
60
                    components=[
61
                        ActionRow(
62
                            self.button_one
63
                        )
64
                    ]
65
                )
66
67
            @button(label="Click me!", style=ButtonStyle.PRIMARY)
68
            async def button_one():
69
                return "Button one pressed"
70
    """  # noqa: E501
71
72
    def wrap(custom_id, func) -> Button:
73
        if not iscoroutinefunction(func):
74
            raise CommandIsNotCoroutine(f"`{func.__name__}` must be a coroutine.")
75
76
        if custom_id is None:
77
            custom_id = func.__name__
78
79
        return _PartialButton(
80
            func=func,
81
            custom_id=custom_id,
82
            style=style,
83
            label=label,
84
            disabled=disabled,
85
            emoji=emoji,
86
            url=url,
87
        )
88
89
    return partial(wrap, custom_id)
90
91
92
class _PartialButton(PartialInteractable):
93
    def register(self, manager: Any) -> Button:
94
        button = Button(*self.args, _func=self.func, **remove_none(self.kwargs))
0 ignored issues
show
Comprehensibility Bug introduced by
button is re-defining a name which is already available in the outer-scope (previously defined on line 36).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
95
        button.func = self.func
96
        button.__call__ = partial(self.func)
97
98
        ComponentHandler.register[self.kwargs.get("custom_id")] = InteractableStructure(
99
            call=self.func,
100
            manager=manager
101
        )
102
103
        return button
104
105
106
def select_menu(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
107
    func=None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
108
    options: List[SelectOption] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
109
    placeholder: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
110
    min_values: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
111
    max_values: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
112
    disabled: bool = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
113
    custom_id: str = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
114
115
116
) -> SelectMenu:
117
    """
118
    Turn a function into handler for a :class:`~pincer.commands.components.select_menu.SelectMenu`.
119
    See :class:`~pincer.commands.components.select_menu.SelectMenu` for information on parameters.
120
121
    The function will still be callable.
122
123
    .. code-block:: python
124
125
        from pincer.commands import button, ActionRow, ButtonStyle
126
127
        class Bot(Client):
128
129
            @command
130
            async def send_a_select_menu(self):
131
                return Message(
132
                    content="Choose an option",
133
                    components=[
134
                        ActionRow(
135
                            self.select_menu
136
                        )
137
                    ]
138
                )
139
140
            @select_menu(options=[
141
                SelectOption(label="Option 1"),
142
                SelectOption(label="Option 2", value="value different than label")
143
            ])
144
            async def select_menu(values: List[str]):
145
                return f"{values[0]} selected"
146
147
    """  # noqa: E501
148
149
    def wrap(custom_id, func) -> SelectMenu:
150
        if not iscoroutinefunction(func):
151
            raise CommandIsNotCoroutine(f"`{func.__name__}` must be a coroutine.")
152
153
        if custom_id is None:
154
            custom_id = func.__name__
155
156
        return _PartialSelectMenu(
0 ignored issues
show
Bug introduced by
It seems like a value for argument func is missing in the constructor call.
Loading history...
157
            _func=func,
158
            custom_id=custom_id,
159
            options=options,
160
            placeholder=placeholder,
161
            min_values=min_values,
162
            max_values=max_values,
163
            disabled=disabled,
164
        )
165
166
    if func is None:
167
        return partial(wrap, custom_id)
168
169
    return wrap(custom_id, func)
170
171
172
class _PartialSelectMenu(PartialInteractable):
173
    def register(self, manager: Any) -> SelectMenu:
174
        ComponentHandler.register[self.kwargs.get("custom_id")] = InteractableStructure(
175
            call=self.func,
176
            manager=manager
177
        )
178
179
        return SelectMenu(
180
            *self.args,
181
            _func=self.func,
182
            **remove_none(self.kwargs)
183
        )
184