PycordViews 1.0.2__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {PycordViews-1.0.2.dist-info → PycordViews-1.1.1.dist-info}/METADATA +20 -2
- PycordViews-1.1.1.dist-info/RECORD +23 -0
- {PycordViews-1.0.2.dist-info → PycordViews-1.1.1.dist-info}/top_level.txt +2 -0
- pycordViews/__init__.py +2 -0
- pycordViews/menu/__init__.py +3 -0
- pycordViews/menu/errors.py +17 -0
- pycordViews/menu/menu.py +57 -0
- pycordViews/menu/selectMenu.py +124 -0
- pycordViews/multibot/__init__.py +5 -0
- pycordViews/multibot/errors.py +10 -0
- pycordViews/multibot/process_for_bots.py +112 -0
- pycordViews/multibot/process_messages.py +7 -0
- pycordViews/multibot/runner.py +14 -0
- pycordViews/multibot/start_multibot.py +80 -0
- pycordViews/pagination/pagination_view.py +8 -9
- pycordViews/views/easy_modified_view.py +24 -16
- PycordViews-1.0.2.dist-info/RECORD +0 -13
- {PycordViews-1.0.2.dist-info → PycordViews-1.1.1.dist-info}/LICENSE +0 -0
- {PycordViews-1.0.2.dist-info → PycordViews-1.1.1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: PycordViews
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.1
|
4
4
|
Summary: Views for py-cord library
|
5
5
|
Home-page: https://github.com/BOXERRMD/Py-cord_Views
|
6
6
|
Author: Chronos (alias BOXERRMD)
|
@@ -36,6 +36,7 @@ Dynamic: summary
|
|
36
36
|
|
37
37
|
```python
|
38
38
|
from pycordViews.pagination import Pagination
|
39
|
+
from pycordViews.menu import SelectMenu
|
39
40
|
import discord
|
40
41
|
|
41
42
|
intents = discord.Intents.all()
|
@@ -57,6 +58,23 @@ async def pagination_command(ctx):
|
|
57
58
|
|
58
59
|
await pages.respond(ctx=ctx) # respond to the command
|
59
60
|
await pages.send(send_to=ctx.author) # send the message to the command author
|
60
|
-
|
61
|
+
|
62
|
+
@bot.command(name="My command select")
|
63
|
+
async def select_command(ctx):
|
64
|
+
"""
|
65
|
+
Create a command select
|
66
|
+
"""
|
67
|
+
async def your_response(select, interaction):
|
68
|
+
await interaction.response.send(f"You have selected {select.values[0]} !")
|
69
|
+
|
70
|
+
my_selector = SelectMenu(timeout=None, disabled_on_timeout=False) # A basic selector menu
|
71
|
+
my_menu = my_selector.add_string_select_menu(placeholder="Choice anything !") # add string_select UI
|
72
|
+
|
73
|
+
my_menu.add_option(label="My first choice !", emoji="😊", default=True, description="It's the first choice !", value='first choice')
|
74
|
+
my_menu.add_option(label="My second choice !", value='second choice')
|
75
|
+
my_menu.set_callable(your_response)
|
76
|
+
|
77
|
+
await my_selector.respond(ctx)
|
78
|
+
|
61
79
|
bot.run("Your token")
|
62
80
|
```
|
@@ -0,0 +1,23 @@
|
|
1
|
+
pycordViews/__init__.py,sha256=SihgmXFTu75CxGmvRhVRHsRm4aDjMy8ZgiXfPuE3suE,223
|
2
|
+
pycordViews/typeViews.py,sha256=5q_-FTUGMg2QjA7bsjbb2ep41Y4sm2sBPTCOV6b5X1w,122
|
3
|
+
pycordViews/menu/__init__.py,sha256=SoAHnpJXxwTYDX5esYkgvSqpPqkuF1hDx22a-_U7ieU,83
|
4
|
+
pycordViews/menu/errors.py,sha256=0Um-oH5qMdWSZB_bGlqILsf9WSDtC4n_HwkheekiMV4,480
|
5
|
+
pycordViews/menu/menu.py,sha256=piouHpZLhHSo8MtJjx3eUp0zLzZoxj0n05pwdy0EJl4,1786
|
6
|
+
pycordViews/menu/selectMenu.py,sha256=lxgMfTFt-pEu1BRm1zqcJJgMpBWHwwuDtY4hOY4deyA,9809
|
7
|
+
pycordViews/multibot/__init__.py,sha256=fP7jipm2AfsNyMLGgh4TEhvASA7NrPSLhSl2hU_xkw4,175
|
8
|
+
pycordViews/multibot/errors.py,sha256=8C6jRRCOs3Y_tY_cvZIsGvz7XSreCkvWQ5ikj2hOf2s,238
|
9
|
+
pycordViews/multibot/process_for_bots.py,sha256=O7Drpyy_A4y1zQq2D3SXLySWLJPnz6WVdynvTPk8gKM,3920
|
10
|
+
pycordViews/multibot/process_messages.py,sha256=tt39bcfVOxTgo7_O4FPYA88spQMqx2Dvee1T2FyURmQ,108
|
11
|
+
pycordViews/multibot/runner.py,sha256=ZyHTDu-wdZFbnoyEC00qe8MTf-STqFvrXytUE8Hr-Ec,406
|
12
|
+
pycordViews/multibot/start_multibot.py,sha256=mHDBhiy7-Z3rvLbr8Ibqe9J9RXe_BusbZxq0aO3a16w,2598
|
13
|
+
pycordViews/pagination/__init__.py,sha256=Z9BcdoTWyC1KXGwQ1_C0tu9rkZpdrrjEHwMmjXsckeE,81
|
14
|
+
pycordViews/pagination/errors.py,sha256=CYb5gBcXx0kYDUDkNpfUrqSxQAcJE_qfpomWtUFOsTk,316
|
15
|
+
pycordViews/pagination/pagination_view.py,sha256=RRx4Ldr7RYp5n6-y7JttAu6fN_kD5QN9ROmuhkMCt_4,4307
|
16
|
+
pycordViews/views/__init__.py,sha256=yligptZmw-np8tjKLr76SVmi0807Nk6jCyKkKYLhbCY,89
|
17
|
+
pycordViews/views/easy_modified_view.py,sha256=umura9gYSt15z6nc5-YfRAF80ZtfmHJ88mYqdTgpxzM,8139
|
18
|
+
pycordViews/views/errors.py,sha256=0NBjBDaSFZChJua1ho9qyfbNzwXy1U6Kcob5CCUxBK8,218
|
19
|
+
PycordViews-1.1.1.dist-info/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
|
20
|
+
PycordViews-1.1.1.dist-info/METADATA,sha256=cExBqgdH5v8HMB4-mzfrZhnphqKtaxHpU_8wv0k-IK4,2897
|
21
|
+
PycordViews-1.1.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
22
|
+
PycordViews-1.1.1.dist-info/top_level.txt,sha256=nqBU40KmnSCjtry8kmv97-RvZC-8xQrhrrloOJX2ROs,91
|
23
|
+
PycordViews-1.1.1.dist-info/RECORD,,
|
pycordViews/__init__.py
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
from typing import Any
|
2
|
+
class MenuError(Exception):
|
3
|
+
pass
|
4
|
+
|
5
|
+
class NotCoroutineError(MenuError):
|
6
|
+
def __init__(self, callable: Any):
|
7
|
+
"""
|
8
|
+
If callable is not a coroutine
|
9
|
+
"""
|
10
|
+
super().__init__(f"{callable} is not a coroutine")
|
11
|
+
|
12
|
+
class ComponentTypeError(MenuError):
|
13
|
+
def __init__(self):
|
14
|
+
"""
|
15
|
+
If the component type is not a string_select
|
16
|
+
"""
|
17
|
+
super().__init__(f"Only string select type is available")
|
pycordViews/menu/menu.py
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
from discord.components import ComponentType
|
2
|
+
from discord.ui import Select
|
3
|
+
from discord import MISSING, Emoji, PartialEmoji
|
4
|
+
from typing import Callable, Union
|
5
|
+
|
6
|
+
from .errors import NotCoroutineError, ComponentTypeError
|
7
|
+
|
8
|
+
|
9
|
+
class Menu:
|
10
|
+
|
11
|
+
def __init__(self, menu_type: ComponentType, selectmenu: "SelectMenu", **kwargs):
|
12
|
+
"""
|
13
|
+
A basic menu from selectMenu class
|
14
|
+
"""
|
15
|
+
self.__menu: Select = Select(select_type=menu_type, **kwargs)
|
16
|
+
self.__selectMenu = selectmenu
|
17
|
+
|
18
|
+
def set_callable(self, _callable: Callable) -> "Menu":
|
19
|
+
"""
|
20
|
+
Add a coroutine to the menu
|
21
|
+
"""
|
22
|
+
if not isinstance(_callable, Callable):
|
23
|
+
raise NotCoroutineError(_callable)
|
24
|
+
|
25
|
+
self.__selectMenu.set_callable(self.__menu.custom_id, _callable=_callable)
|
26
|
+
return self
|
27
|
+
|
28
|
+
def add_option(self, label: str, value: str = MISSING, description: Union[str, None] = None, emoji: Union[str, Emoji, PartialEmoji, None] = None, default: bool = False) -> "Menu":
|
29
|
+
"""
|
30
|
+
Add an option to choice.
|
31
|
+
Only from string_select type !
|
32
|
+
"""
|
33
|
+
if self.__menu.type != ComponentType.string_select:
|
34
|
+
raise ComponentTypeError()
|
35
|
+
|
36
|
+
self.__menu.add_option(label=label, value=value, description=description, emoji=emoji, default=default)
|
37
|
+
return self
|
38
|
+
|
39
|
+
@property
|
40
|
+
def component(self) -> Select:
|
41
|
+
"""
|
42
|
+
Get the component
|
43
|
+
"""
|
44
|
+
return self.__menu
|
45
|
+
|
46
|
+
@property
|
47
|
+
def callable(self) -> Callable:
|
48
|
+
"""
|
49
|
+
Get the callable link to the menu
|
50
|
+
"""
|
51
|
+
return self.__callable
|
52
|
+
|
53
|
+
@callable.setter
|
54
|
+
def callable(self, _callable: Callable):
|
55
|
+
"""
|
56
|
+
Set the callable link to menu
|
57
|
+
"""
|
@@ -0,0 +1,124 @@
|
|
1
|
+
from ..views.easy_modified_view import EasyModifiedViews
|
2
|
+
from .menu import Menu
|
3
|
+
|
4
|
+
from typing import Union, Callable
|
5
|
+
from discord.components import ComponentType
|
6
|
+
from discord import ChannelType, Member, TextChannel, ApplicationContext
|
7
|
+
|
8
|
+
class SelectMenu:
|
9
|
+
"""
|
10
|
+
Create a simply select menu
|
11
|
+
"""
|
12
|
+
|
13
|
+
def __init__(self, timeout: Union[float, None] = None, disabled_on_timeout: bool = False):
|
14
|
+
"""
|
15
|
+
Init the select menu
|
16
|
+
"""
|
17
|
+
self.__select_menu: EasyModifiedViews = EasyModifiedViews(timeout=timeout, disabled_on_timeout=disabled_on_timeout)
|
18
|
+
|
19
|
+
def add_string_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None) -> Menu:
|
20
|
+
"""
|
21
|
+
Add a string select menu in the ui
|
22
|
+
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
23
|
+
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
24
|
+
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
25
|
+
:param min_values: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
26
|
+
:param disabled: Whether the select is disabled or not.
|
27
|
+
:param row: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed).
|
28
|
+
"""
|
29
|
+
return self.__global_add_component(ComponentType.string_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row)
|
30
|
+
|
31
|
+
def add_user_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None) -> Menu:
|
32
|
+
"""
|
33
|
+
Add an user select menu in the ui
|
34
|
+
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
35
|
+
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
36
|
+
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
37
|
+
:param min_values: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
38
|
+
:param disabled: Whether the select is disabled or not.
|
39
|
+
:param row: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed).
|
40
|
+
"""
|
41
|
+
return self.__global_add_component(ComponentType.user_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row)
|
42
|
+
|
43
|
+
def add_role_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None) -> Menu:
|
44
|
+
"""
|
45
|
+
Add a role select menu in the ui
|
46
|
+
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
47
|
+
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
48
|
+
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
49
|
+
:param min_values: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
50
|
+
:param disabled: Whether the select is disabled or not.
|
51
|
+
:param row: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed).
|
52
|
+
"""
|
53
|
+
return self.__global_add_component(ComponentType.role_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row)
|
54
|
+
|
55
|
+
def add_mentionnable_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None) -> Menu:
|
56
|
+
"""
|
57
|
+
Add a role select menu in the ui
|
58
|
+
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
59
|
+
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
60
|
+
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
61
|
+
:param min_values: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
62
|
+
:param disabled: Whether the select is disabled or not.
|
63
|
+
:param row: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed).
|
64
|
+
"""
|
65
|
+
return self.__global_add_component(ComponentType.mentionable_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row)
|
66
|
+
|
67
|
+
def add_channel_select_menu(self, custom_id: str = None, placeholder: str = None, min_values: int = 1, max_values: int = 1, disabled=False, row=None, channel_types: list[ChannelType] = None):
|
68
|
+
"""
|
69
|
+
Add a role select menu in the ui
|
70
|
+
:param custom_id: The ID of the select menu that gets received during an interaction. If not given then one is generated for you.
|
71
|
+
:param placeholder: The placeholder text that is shown if nothing is selected, if any.
|
72
|
+
:param max_values: The maximum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
73
|
+
:param min_values: The minimum number of items that must be chosen for this select menu. Defaults to 1 and must be between 1 and 25.
|
74
|
+
:param disabled: Whether the select is disabled or not.
|
75
|
+
:param row: The relative row this select menu belongs to. A Discord component can only have 5 rows. By default, items are arranged automatically into those 5 rows. If you’d like to control the relative positioning of the row then passing an index is advised. For example, row=1 will show up before row=2. Defaults to None, which is automatic ordering. The row number must be between 0 and 4 (i.e. zero indexed).
|
76
|
+
:param channel_types: A list of channel types that can be selected in this menu.
|
77
|
+
"""
|
78
|
+
return self.__global_add_component(ComponentType.channel_select, custom_id=custom_id, placeholder=placeholder, max_values=max_values, min_values=min_values, disabled=disabled, row=row, channel_types=channel_types)
|
79
|
+
|
80
|
+
def __global_add_component(self, component_type: ComponentType,
|
81
|
+
custom_id: Union[str, None] = None,
|
82
|
+
placeholder: Union[str, None] = None,
|
83
|
+
min_values: int = 1,
|
84
|
+
max_values: int = 1,
|
85
|
+
disabled: bool = False,
|
86
|
+
row: Union[int, None] = None,
|
87
|
+
channel_types: Union[ChannelType, None] = None) -> Menu:
|
88
|
+
"""
|
89
|
+
global function to add a Select component
|
90
|
+
"""
|
91
|
+
menu = Menu(component_type,
|
92
|
+
self.__select_menu,
|
93
|
+
**{'custom_id': custom_id, 'placeholder': placeholder, 'min_values': min_values,
|
94
|
+
'max_values': max_values, 'disabled': disabled, 'row': row, 'channel_types': channel_types})
|
95
|
+
|
96
|
+
self.__select_menu.add_items(menu.component)
|
97
|
+
|
98
|
+
return menu
|
99
|
+
|
100
|
+
def set_callable(self, *custom_ids: str, _callable : Callable):
|
101
|
+
"""
|
102
|
+
Set a callable for the menu associated with the custom_id
|
103
|
+
:param custom_ids: IDs to menus
|
104
|
+
"""
|
105
|
+
self.__select_menu.set_callable(*custom_ids, _callable=_callable)
|
106
|
+
|
107
|
+
async def respond(self, ctx: ApplicationContext, *args, **kwargs) -> None:
|
108
|
+
"""
|
109
|
+
Respond at the ApplicationContext
|
110
|
+
"""
|
111
|
+
await self.__select_menu.respond(ctx=ctx, *args, view=self.__select_menu, **kwargs)
|
112
|
+
|
113
|
+
async def send(self, target: Union[Member, TextChannel], *args, **kwargs) -> None:
|
114
|
+
"""
|
115
|
+
Send at the target
|
116
|
+
"""
|
117
|
+
await self.__select_menu.send(target=target, *args, view=self.__select_menu, **kwargs)
|
118
|
+
|
119
|
+
@property
|
120
|
+
def get_view(self) -> EasyModifiedViews:
|
121
|
+
"""
|
122
|
+
Get the current view
|
123
|
+
"""
|
124
|
+
return self.__select_menu
|
@@ -0,0 +1,112 @@
|
|
1
|
+
from discord import AutoShardedBot, Bot
|
2
|
+
from random import choice
|
3
|
+
from string import ascii_letters
|
4
|
+
from asyncio import set_event_loop, new_event_loop, sleep, run, create_task
|
5
|
+
from multiprocessing import Queue
|
6
|
+
|
7
|
+
from .errors import *
|
8
|
+
from .runner import Runner
|
9
|
+
from .process_messages import ProcessMessage
|
10
|
+
|
11
|
+
|
12
|
+
class ProcessBot:
|
13
|
+
|
14
|
+
def __init__(self, queue_parent: Queue, queue_children: Queue, limit_bots_in_tread: int = -1):
|
15
|
+
"""
|
16
|
+
Class to manage process and thread
|
17
|
+
"""
|
18
|
+
self.__threads: dict = {}
|
19
|
+
self.__all_bots: dict = {}
|
20
|
+
|
21
|
+
self.__limit_bots_in_tread: int = limit_bots_in_tread
|
22
|
+
|
23
|
+
self.__queue_parent: Queue = queue_parent
|
24
|
+
self.__queue_children: Queue = queue_children
|
25
|
+
self.__loop = None
|
26
|
+
run(self.run_process())
|
27
|
+
|
28
|
+
async def run_process(self):
|
29
|
+
"""
|
30
|
+
Function run with the process
|
31
|
+
"""
|
32
|
+
await create_task(self.__message_process_receiver()) # Run the process
|
33
|
+
|
34
|
+
async def __message_process_receiver(self):
|
35
|
+
"""
|
36
|
+
Wait message from parent process (always a dict with the key "parent_message")
|
37
|
+
"""
|
38
|
+
while True:
|
39
|
+
await sleep(0.02)
|
40
|
+
while not self.__queue_children.empty():
|
41
|
+
try:
|
42
|
+
message = self.__queue_children.get_nowait()
|
43
|
+
await self.__decode_message(message)
|
44
|
+
except:
|
45
|
+
break
|
46
|
+
|
47
|
+
def __message_process_sender(self, message: dict):
|
48
|
+
"""
|
49
|
+
Send a message to parent process
|
50
|
+
"""
|
51
|
+
self.__queue_parent.put(message)
|
52
|
+
|
53
|
+
async def __decode_message(self, message: dict):
|
54
|
+
"""
|
55
|
+
Decode the current message sent by the parent process
|
56
|
+
:param message: The message.
|
57
|
+
"""
|
58
|
+
action = message['parent_message']
|
59
|
+
|
60
|
+
if ProcessMessage.ADD_BOT.value == action:
|
61
|
+
self.add_bot(**message)
|
62
|
+
|
63
|
+
elif ProcessMessage.RUN_ALL.value == action:
|
64
|
+
print("run all bots")
|
65
|
+
|
66
|
+
def add_bot(self, token: str, *args, autoshared: bool = False, name: str = None, **kwargs) -> None:
|
67
|
+
"""
|
68
|
+
Add a bot in the instance to manage it.
|
69
|
+
Use this function to set the bot's intents and other subtleties.
|
70
|
+
:param name: The name of the bot to find it. If None, a random name is given
|
71
|
+
:param token: The token bot
|
72
|
+
:param autoshared: Autoshare the bot in Discord
|
73
|
+
:param args: all arguments of the Discord class Bot.
|
74
|
+
:param kwargs: all kwargs of the Discord class Bot
|
75
|
+
See : https://docs.pycord.dev/en/stable/api/clients.html#discord.Bot
|
76
|
+
"""
|
77
|
+
print(f"Ajout du bot {name} avec le token {token}")
|
78
|
+
if name is None:
|
79
|
+
name = ''.join([choice(ascii_letters) for _ in range(20)])
|
80
|
+
|
81
|
+
if autoshared:
|
82
|
+
self.__all_bots[name] = {'runner': Runner(AutoShardedBot(*args, **kwargs)),
|
83
|
+
'token': token,
|
84
|
+
'thread': None}
|
85
|
+
|
86
|
+
else:
|
87
|
+
self.__all_bots[name] = {'runner': Runner(Bot(*args, **kwargs)),
|
88
|
+
'token': token,
|
89
|
+
'thread': None}
|
90
|
+
|
91
|
+
print(f"Envoi de la réponse 'coucou' pour {name}")
|
92
|
+
self.__message_process_sender({'children_message': "coucou"})
|
93
|
+
|
94
|
+
|
95
|
+
def get_bots_names(self) -> list[str]:
|
96
|
+
"""
|
97
|
+
Return all bots names registered in the class.
|
98
|
+
"""
|
99
|
+
print('coucou', self.__event)
|
100
|
+
return list(self.__all_bots.keys())
|
101
|
+
|
102
|
+
|
103
|
+
def get_runner(self, name: str) -> "Runner":
|
104
|
+
"""
|
105
|
+
Run the bot runner associated with this name
|
106
|
+
:raise: BotNotFoundError
|
107
|
+
"""
|
108
|
+
|
109
|
+
if name not in self.__all_bots.keys():
|
110
|
+
raise BotNotFoundError(name)
|
111
|
+
|
112
|
+
return self.__all_bots[name]['runner']
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from discord import AutoShardedBot, Bot
|
2
|
+
from typing import Union
|
3
|
+
|
4
|
+
class Runner:
|
5
|
+
|
6
|
+
def __init__(self, bot: Union[AutoShardedBot, Bot]):
|
7
|
+
"""
|
8
|
+
Run the bot
|
9
|
+
"""
|
10
|
+
self.bot: Union[AutoShardedBot, Bot] = bot
|
11
|
+
|
12
|
+
def __reduce__(self):
|
13
|
+
# Renvoyer un tuple avec les informations nécessaires pour reconstruire l'objet
|
14
|
+
return self.__class__, (self.bot,)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
from typing import Union, Any
|
3
|
+
from multiprocessing import Process, Queue, set_start_method, get_start_method
|
4
|
+
from asyncio import create_task, sleep
|
5
|
+
from time import sleep as tsleep
|
6
|
+
|
7
|
+
from .process_for_bots import ProcessBot
|
8
|
+
from .process_messages import ProcessMessage
|
9
|
+
|
10
|
+
|
11
|
+
class Multibot:
|
12
|
+
|
13
|
+
def __init__(self, limit_bots_in_tread: int = 10):
|
14
|
+
"""
|
15
|
+
Create an instance of Multibot_asyncio class to manage few bots with asyncio.
|
16
|
+
:param limit_bots_in_tread: Max running bot in a single asyncio loop in a thread.
|
17
|
+
"""
|
18
|
+
if get_start_method() != "spawn":
|
19
|
+
set_start_method("spawn")
|
20
|
+
|
21
|
+
self.__queue_parent: Queue = Queue()
|
22
|
+
self.__queue_children: Queue = Queue()
|
23
|
+
|
24
|
+
self.__process: Union[Process] = Process(target=ProcessBot, args=(self.__queue_parent, self.__queue_children, limit_bots_in_tread)) # Process to run all bots
|
25
|
+
|
26
|
+
async def start_process(self) -> "Multibot":
|
27
|
+
"""
|
28
|
+
Start the process. It is required !
|
29
|
+
"""
|
30
|
+
self.__process.start()
|
31
|
+
create_task(self.__message_process_receiver())
|
32
|
+
|
33
|
+
def __message_process_sender(self, message: dict):
|
34
|
+
"""
|
35
|
+
Send a message to children process
|
36
|
+
"""
|
37
|
+
print(f"Message envoyé par le parent : {message}")
|
38
|
+
self.__queue_children.put(message)
|
39
|
+
|
40
|
+
async def __message_process_receiver(self):
|
41
|
+
"""
|
42
|
+
Wait message from children process (always a dict with the key "children_message")
|
43
|
+
"""
|
44
|
+
while True:
|
45
|
+
await sleep(0.02)
|
46
|
+
while not self.__queue_parent.empty():
|
47
|
+
try:
|
48
|
+
message = self.__queue_parent.get_nowait()
|
49
|
+
await self.__decode_message(message)
|
50
|
+
except:
|
51
|
+
break
|
52
|
+
|
53
|
+
async def __decode_message(self, message: Any):
|
54
|
+
"""
|
55
|
+
Decode the current message sent by the parent process
|
56
|
+
:param message: The message.
|
57
|
+
"""
|
58
|
+
print(message)
|
59
|
+
|
60
|
+
async def add_bot(self, token: str, name: str = None, autoshared: bool = False, **kwargs):
|
61
|
+
"""
|
62
|
+
Add a bot
|
63
|
+
"""
|
64
|
+
data = {
|
65
|
+
'parent_message': ProcessMessage.ADD_BOT.value,
|
66
|
+
'token': token,
|
67
|
+
'name': name,
|
68
|
+
'autoshared': autoshared,
|
69
|
+
}
|
70
|
+
data.update(kwargs)
|
71
|
+
|
72
|
+
self.__message_process_sender(data)
|
73
|
+
|
74
|
+
async def run_all_bots(self):
|
75
|
+
"""
|
76
|
+
Run all bots
|
77
|
+
"""
|
78
|
+
self.__message_process_sender({'parent_message': ProcessMessage.RUN_ALL.value})
|
79
|
+
|
80
|
+
|
@@ -13,7 +13,7 @@ class Pagination:
|
|
13
13
|
Allows you to easily setup a view pagination
|
14
14
|
"""
|
15
15
|
|
16
|
-
def __init__(self, timeout: Union[float, None] = None, disabled_on_timeout:bool = False):
|
16
|
+
def __init__(self, timeout: Union[float, None] = None, disabled_on_timeout: bool = False):
|
17
17
|
"""
|
18
18
|
Initialisation for pagination
|
19
19
|
:param timeout: The time before disable items on the view
|
@@ -25,7 +25,7 @@ class Pagination:
|
|
25
25
|
self.__view.add_items(Button(label='◀', row=0, custom_id='back', style=ButtonStyle.blurple))
|
26
26
|
self.__view.add_items(Button(label='▶', row=0, custom_id='forward', style=ButtonStyle.blurple))
|
27
27
|
self.__view.add_items(Button(label='⏭', row=0, custom_id='forward+', style=ButtonStyle.blurple))
|
28
|
-
self.__view.set_callable('back+', 'back', 'forward', 'forward+',
|
28
|
+
self.__view.set_callable('back+', 'back', 'forward', 'forward+', _callable=self.__turn_page)
|
29
29
|
|
30
30
|
self.__pages: list[tuple[tuple, dict]] = []
|
31
31
|
self.__current_page: int = 0
|
@@ -44,7 +44,7 @@ class Pagination:
|
|
44
44
|
Deletes pages in the order in which they were added
|
45
45
|
**Start to 0 !**
|
46
46
|
|
47
|
-
delete_pages(1,2,3,...)
|
47
|
+
delete_pages(0,1,2,3,...)
|
48
48
|
"""
|
49
49
|
nbr_pages = len(self.__pages)-1
|
50
50
|
for page_number in page_numbers:
|
@@ -54,7 +54,7 @@ class Pagination:
|
|
54
54
|
|
55
55
|
del self.__pages[page_number]
|
56
56
|
|
57
|
-
async def __turn_page(self, interaction: Interaction):
|
57
|
+
async def __turn_page(self, button, interaction: Interaction):
|
58
58
|
"""
|
59
59
|
Turn the page when button is pressed
|
60
60
|
"""
|
@@ -91,19 +91,18 @@ class Pagination:
|
|
91
91
|
# Acknowledge the interaction
|
92
92
|
await interaction.response.defer(invisible=True)
|
93
93
|
|
94
|
-
async def send(self,
|
94
|
+
async def send(self, target: Union[Member, TextChannel]) -> None:
|
95
95
|
"""
|
96
96
|
Send pagination without introduction message.
|
97
|
-
:param
|
97
|
+
:param target: The member or channel to send the pagination
|
98
98
|
"""
|
99
|
-
|
100
|
-
await send_to.send(*self.__pages[0][0], **self.__pages[0][1], view=self.get_view)
|
99
|
+
await self.__view.send(ctx=target, *self.__pages[0][0], **self.__pages[0][1], view=self.get_view)
|
101
100
|
|
102
101
|
async def respond(self, ctx: ApplicationContext) -> None:
|
103
102
|
"""
|
104
103
|
Respond to the command call
|
105
104
|
"""
|
106
|
-
await
|
105
|
+
await self.__view.respond(ctx=ctx, *self.__pages[0][0], **self.__pages[0][1], view=self.get_view)
|
107
106
|
|
108
107
|
@property
|
109
108
|
def get_view(self) -> EasyModifiedViews:
|
@@ -1,6 +1,6 @@
|
|
1
|
-
from discord import Interaction, ApplicationContext, Message
|
1
|
+
from discord import Interaction, ApplicationContext, Message, Member, TextChannel
|
2
2
|
from discord.ui import View, Item
|
3
|
-
from typing import Union, Callable,
|
3
|
+
from typing import Union, Callable, Iterable
|
4
4
|
|
5
5
|
from ..typeViews import T_views
|
6
6
|
from .errors import CustomIDNotFound
|
@@ -39,11 +39,16 @@ class EasyModifiedViews(View):
|
|
39
39
|
"""
|
40
40
|
self.__ctx = await ctx.respond(*args, **kwargs)
|
41
41
|
|
42
|
+
async def send(self, target: Union[Member, TextChannel], *args, **kwargs) -> None:
|
43
|
+
"""
|
44
|
+
Send at the target
|
45
|
+
"""
|
46
|
+
self.__ctx = await target.send(*args, **kwargs)
|
47
|
+
|
42
48
|
def add_items(self,
|
43
49
|
*items: T_views) -> "EasyModifiedViews":
|
44
50
|
"""
|
45
51
|
Add all items in the View.
|
46
|
-
custom_id REQUIRED !
|
47
52
|
"""
|
48
53
|
|
49
54
|
for ui in items:
|
@@ -75,7 +80,7 @@ class EasyModifiedViews(View):
|
|
75
80
|
|
76
81
|
def set_callable_decorator(self, custom_id: str):
|
77
82
|
"""
|
78
|
-
Decorator to set up a
|
83
|
+
Decorator to set up a callable for the item
|
79
84
|
|
80
85
|
**Interaction parameter is required in coroutine function !**
|
81
86
|
|
@@ -84,7 +89,7 @@ class EasyModifiedViews(View):
|
|
84
89
|
|
85
90
|
@view.set_callable_decorator(custom_id='test_ID')
|
86
91
|
|
87
|
-
async def rep(**interaction**):
|
92
|
+
async def rep(**UI**, **interaction**):
|
88
93
|
await interaction.response.send_message('coucou !!!')
|
89
94
|
|
90
95
|
await ctx.respond('coucou', view=view)
|
@@ -92,36 +97,36 @@ class EasyModifiedViews(View):
|
|
92
97
|
:param custom_id: item ID of the view
|
93
98
|
"""
|
94
99
|
|
95
|
-
def decorator(
|
100
|
+
def decorator(_callable: Callable):
|
96
101
|
self.__check_custom_id(custom_id)
|
97
102
|
|
98
|
-
self.__callback[custom_id]['func'] =
|
99
|
-
return
|
103
|
+
self.__callback[custom_id]['func'] = _callable
|
104
|
+
return _callable
|
100
105
|
|
101
106
|
return decorator
|
102
107
|
|
103
|
-
def set_callable(self, *custom_ids: str,
|
108
|
+
def set_callable(self, *custom_ids: str, _callable: Callable):
|
104
109
|
"""
|
105
|
-
set up a
|
110
|
+
set up a callable for items
|
106
111
|
:param custom_ids: items IDs of the view
|
107
|
-
:param
|
112
|
+
:param _callable: The callable linked
|
108
113
|
|
109
|
-
**Interaction parameter is required in
|
114
|
+
**UI and Interaction parameter is required in callable function !**
|
110
115
|
|
111
116
|
view = EasyModifiedViews(None)
|
112
117
|
|
113
118
|
view.add_view(discord.ui.Button(label='coucou', custom_id='test_ID'))
|
114
119
|
|
115
|
-
async def rep(**interaction**):
|
120
|
+
async def rep(**UI**, **interaction**):
|
116
121
|
await interaction.response.send_message('coucou !!!')
|
117
122
|
|
118
|
-
view.set_callable(custom_id='test_ID',
|
123
|
+
view.set_callable(custom_id='test_ID', callable=rep)
|
119
124
|
await ctx.respond('coucou', view=view)
|
120
125
|
"""
|
121
126
|
for custom_id in custom_ids:
|
122
127
|
self.__check_custom_id(custom_id)
|
123
128
|
|
124
|
-
self.__callback[custom_id]['func'] =
|
129
|
+
self.__callback[custom_id]['func'] = _callable
|
125
130
|
|
126
131
|
async def interaction_check(self, interaction: Interaction) -> bool:
|
127
132
|
"""
|
@@ -130,7 +135,7 @@ class EasyModifiedViews(View):
|
|
130
135
|
func = self.__callback[interaction.custom_id]['func']
|
131
136
|
|
132
137
|
if func is not None:
|
133
|
-
await func(interaction)
|
138
|
+
await func(self.__callback[interaction.custom_id]['ui'], interaction)
|
134
139
|
|
135
140
|
else:
|
136
141
|
await interaction.response.defer(invisible=True)
|
@@ -263,3 +268,6 @@ class EasyModifiedViews(View):
|
|
263
268
|
"""
|
264
269
|
self.__check_custom_id(custom_id)
|
265
270
|
return self.__callback[custom_id]['ui']
|
271
|
+
|
272
|
+
def __str__(self):
|
273
|
+
return str(self.__callback)
|
@@ -1,13 +0,0 @@
|
|
1
|
-
pycordViews/__init__.py,sha256=mK6mXFXlXBnvJpPjH9UI_iS54ICVh_0H3LEReQNJutU,135
|
2
|
-
pycordViews/typeViews.py,sha256=5q_-FTUGMg2QjA7bsjbb2ep41Y4sm2sBPTCOV6b5X1w,122
|
3
|
-
pycordViews/pagination/__init__.py,sha256=Z9BcdoTWyC1KXGwQ1_C0tu9rkZpdrrjEHwMmjXsckeE,81
|
4
|
-
pycordViews/pagination/errors.py,sha256=CYb5gBcXx0kYDUDkNpfUrqSxQAcJE_qfpomWtUFOsTk,316
|
5
|
-
pycordViews/pagination/pagination_view.py,sha256=ppcQ6e3RFlw9YXoRF_mRdVi4Pf4EomHWUMDtGxwTDbI,4267
|
6
|
-
pycordViews/views/__init__.py,sha256=yligptZmw-np8tjKLr76SVmi0807Nk6jCyKkKYLhbCY,89
|
7
|
-
pycordViews/views/easy_modified_view.py,sha256=7cLMKSx92xqT0c74gssgBfFUNBOsc7M4sSrrXwPmVtc,7835
|
8
|
-
pycordViews/views/errors.py,sha256=0NBjBDaSFZChJua1ho9qyfbNzwXy1U6Kcob5CCUxBK8,218
|
9
|
-
PycordViews-1.0.2.dist-info/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
|
10
|
-
PycordViews-1.0.2.dist-info/METADATA,sha256=0L5TlXIHwBlzsFq0FztkoSgimrTJPRCVxu7wppEQbBI,2077
|
11
|
-
PycordViews-1.0.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
12
|
-
PycordViews-1.0.2.dist-info/top_level.txt,sha256=oPtEDovMPk2PEh7P6fY3IAXvCbmwnG3sbcFIAyljb-Y,53
|
13
|
-
PycordViews-1.0.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|