Passed
Pull Request — main (#321)
by
unknown
04:13
created

pincer.commands.components.decorators.button()   A

Complexity

Conditions 3

Size

Total Lines 67
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 67
rs 9.232
c 0
b 0
f 0
cc 3
nop 6

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 List
7
8
from .button import Button, ButtonStyle
9
from .select_menu import SelectMenu, SelectOption
10
from .component_handler import ComponentHandler
11
from ...exceptions import CommandIsNotCoroutine
12
from ...objects.message.emoji import Emoji
13
from ...utils.conversion import remove_none
14
15
16
def component(custom_id):
17
    """
18
    Generic handler for Message Components. Can be used with manually constructed
19
    :class:`~pincer.commands.components.button.Button` and
20
    :class:`~pincer.commands.components.select_menu.SelectMenu` objects.
21
22
    Parameters
23
    ---------
24
    custom_id : str
25
        The ID of the message component to handle.
26
    """
27
    def wrap(custom_id, func):
28
        ComponentHandler().register_id(_id=custom_id, func=func)
29
        return func
30
31
    return partial(wrap, custom_id)
32
33
34
def button(
0 ignored issues
show
best-practice introduced by
Too many arguments (6/5)
Loading history...
35
    label: str,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
36
    style: ButtonStyle,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
37
    emoji: Emoji = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
38
    url: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
39
    disabled: bool = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
40
    custom_id: str = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
41
) -> Button:
42
    """
43
    Turn a function into handler for a :class:`~pincer.commands.components.button.Button`.
44
    See :class:`~pincer.commands.components.button.Button` for information on parameters.
45
46
    The function will still be callable.
47
48
    .. code-block:: python
49
50
        from pincer.commands import ActionRow, Button
51
52
        class Bot(Client):
53
54
            @command
55
            async def send_a_button(self):
56
                return Message(
57
                    content="Click a button",
58
                    components=[
59
                        ActionRow(
60
                            self.button_one
61
                        )
62
                    ]
63
                )
64
65
            @button(label="Click me!", style=ButtonStyle.PRIMARY)
66
            async def button_one():
67
                return "Button one pressed"
68
    """  # noqa: E501
69
70
    def wrap(custom_id, func) -> Button:
71
72
        if not iscoroutinefunction(func):
73
            raise CommandIsNotCoroutine(f"`{func.__name__}` must be a coroutine.")
74
75
        if custom_id is None:
76
            custom_id = func.__name__
77
78
        ComponentHandler().register_id(custom_id, func)
79
80
        button = Button(
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 34).

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...
81
            # Hack to not override defaults in button class
82
            **remove_none(
83
                {
84
                    "custom_id": custom_id,
85
                    "style": style,
86
                    "label": label,
87
                    "disabled": disabled,
88
                    "emoji": emoji,
89
                    "url": url,
90
                    "_func": func
91
                }
92
            )
93
        )
94
95
        button.func = func
96
        button.__call__ = partial(func)
97
98
        return button
99
100
    return partial(wrap, custom_id)
101
102
103
def select_menu(
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
104
    func=None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
105
    options: List[SelectOption] = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
106
    placeholder: str = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
107
    min_values: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
108
    max_values: int = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
109
    disabled: bool = None,
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
110
    custom_id: str = None
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation before block (add 4 spaces).
Loading history...
111
) -> SelectMenu:
112
    """
113
    Turn a function into handler for a :class:`~pincer.commands.components.select_menu.SelectMenu`.
114
    See :class:`~pincer.commands.components.select_menu.SelectMenu` for information on paramters.
115
116
    The function will still be callable.
117
118
    .. code-block:: python
119
120
        from pincer.commands import button, ActionRow, ButtonStyle
121
122
        class Bot(Client):
123
124
            @command
125
            async def send_a_select_menu(self):
126
                return Message(
127
                    content="Choose an option",
128
                    components=[
129
                        ActionRow(
130
                            self.select_menu
131
                        )
132
                    ]
133
                )
134
135
            @select_menu(options=[
136
                SelectOption(label="Option 1"),
137
                SelectOption(label="Option 2", value="value different than label")
138
            ])
139
            async def select_menu(values: List[str]):
140
                return f"{values[0]} selected"
141
142
    """  # noqa: E501
143
144
    def wrap(custom_id, func) -> SelectMenu:
145
146
        if not iscoroutinefunction(func):
147
            raise CommandIsNotCoroutine(f"`{func.__name__}` must be a coroutine.")
148
149
        if custom_id is None:
150
            custom_id = func.__name__
151
152
        ComponentHandler().register_id(custom_id, func)
153
154
        menu = SelectMenu(
155
            # Hack to not override defaults in button class
156
            **remove_none(
157
                {
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
                    "_func": func
165
                }
166
            )
167
        )
168
169
        return menu
170
171
    if func is None:
172
        return partial(wrap, custom_id)
173
174
    return wrap(custom_id, func)
175