PycordViews 1.1.3__py3-none-any.whl → 1.1.4__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/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
- from .typeViews import *
2
1
  from .views.easy_modified_view import EasyModifiedViews
3
2
  from .pagination.pagination_view import Pagination
4
3
  from .multibot.start_multibot import Multibot
5
4
  from .menu.selectMenu import SelectMenu
5
+ from .menu.menu import Menu, CustomSelect
@@ -1,3 +1,3 @@
1
1
  from .selectMenu import SelectMenu
2
- from .menu import Menu
2
+ from .menu import Menu, CustomSelect
3
3
  from .errors import *
pycordViews/menu/menu.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from discord.components import ComponentType
2
- from discord.ui import Select
3
- from discord import MISSING, Emoji, PartialEmoji
2
+ from discord.ui import Select, Item
3
+ from discord import MISSING, Emoji, PartialEmoji, Interaction
4
4
  from typing import Callable, Union
5
5
 
6
6
  from .errors import NotCoroutineError, ComponentTypeError
@@ -12,12 +12,14 @@ class Menu:
12
12
  """
13
13
  A basic menu from selectMenu class
14
14
  """
15
- self.__menu: Select = Select(select_type=menu_type, **kwargs)
15
+ self.__menu: CustomSelect = CustomSelect(menu=self, select_type=menu_type, **kwargs)
16
16
  self.__selectMenu = selectmenu
17
+ self.__menu_type: ComponentType = menu_type
17
18
 
18
- def set_callable(self, _callable: Callable) -> "Menu":
19
+ def set_callable(self, _callable: Union[Callable, None]) -> "Menu":
19
20
  """
20
- Add a coroutine to the menu
21
+ Add a coroutine to the menu (same function on SelectMenu class)
22
+ This coroutine can have 2 parameters (X, interaction)
21
23
  """
22
24
  if not isinstance(_callable, Callable):
23
25
  raise NotCoroutineError(_callable)
@@ -25,17 +27,60 @@ class Menu:
25
27
  self.__selectMenu.set_callable(self.__menu.custom_id, _callable=_callable)
26
28
  return self
27
29
 
30
+ @property
31
+ def callable(self) -> Callable:
32
+ """
33
+ Get the current callable menu
34
+ """
35
+ return self.__selectMenu.get_callable(self.__menu.custom_id)
36
+
28
37
  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
38
  """
30
39
  Add an option to choice.
31
40
  Only from string_select type !
32
41
  """
33
- if self.__menu.type != ComponentType.string_select:
34
- raise ComponentTypeError()
42
+ self.__is_string_select()
35
43
 
36
44
  self.__menu.add_option(label=label, value=value, description=description, emoji=emoji, default=default)
37
45
  return self
38
46
 
47
+ def remove_options(self, *labels: str) -> "Menu":
48
+ """
49
+ Remove an option to choice.
50
+ Only from string_select type !
51
+ :param labels: Label option name to delete
52
+ """
53
+ self.__is_string_select()
54
+
55
+ self.__menu.options = [i for i in self.__menu.options if i.label not in labels]
56
+ return self
57
+
58
+ def update_option(self, current_label: str, new_label: str = None, value: str = None, description: Union[str, None] = None, emoji: Union[str, Emoji, PartialEmoji, None] = None, default: Union[bool, None] = None) -> "Menu":
59
+ """
60
+ Update option. To find the option, write her actual label in "current_label" option.
61
+ Only from string_select type !
62
+ :param current_label: The current label option to edit
63
+ """
64
+ self.__is_string_select()
65
+
66
+ for option in self.__menu.options:
67
+ if option.label == current_label:
68
+ option.label = new_label if new_label is not None else option.label
69
+ option.value = value if value is not None else option.value
70
+ option.description = description if description is not None else option.description
71
+ option.default = default if default is not None else option.default
72
+ option.emoji = emoji if emoji is not None else option.emoji
73
+ break
74
+ return self
75
+
76
+ def __is_string_select(self) -> None:
77
+ """
78
+ Check if the menu is a string_select
79
+ :raise: ComponentTypeError
80
+ """
81
+ if self.__menu.type != ComponentType.string_select:
82
+ raise ComponentTypeError()
83
+
39
84
  @property
40
85
  def component(self) -> Select:
41
86
  """
@@ -44,14 +89,30 @@ class Menu:
44
89
  return self.__menu
45
90
 
46
91
  @property
47
- def callable(self) -> Callable:
92
+ def selectmenu(self) -> "SelectMenu":
93
+ """
94
+ Get the selectMenu
95
+ """
96
+ return self.__selectMenu
97
+
98
+ class CustomSelect(Select):
99
+ """
100
+ Subclass of Select discord Class to use some SelectMenu functions
101
+ """
102
+
103
+ def __init__(self, menu: Menu, select_type: ComponentType, *items: Item, **kwargs):
104
+ super().__init__(select_type=select_type, *items, **kwargs)
105
+ self.__menu: Menu = menu
106
+
107
+ async def update(self):
48
108
  """
49
- Get the callable link to the menu
109
+ Bridge to SelectMenu update function
50
110
  """
51
- return self.__callable
111
+ return await self.__menu.selectmenu.update()
52
112
 
53
- @callable.setter
54
- def callable(self, _callable: Callable):
113
+ @property
114
+ def get_view(self) -> "EasyModifiedViews":
115
+ """
116
+ Bridge to SelectMenu get_view property
55
117
  """
56
- Set the callable link to menu
57
- """
118
+ return self.__menu.selectmenu.get_view
@@ -1,3 +1,4 @@
1
+
1
2
  from ..views.easy_modified_view import EasyModifiedViews
2
3
  from .menu import Menu
3
4
 
@@ -89,7 +90,7 @@ class SelectMenu:
89
90
  global function to add a Select component
90
91
  """
91
92
  menu = Menu(component_type,
92
- self.__select_menu,
93
+ self,
93
94
  **{'custom_id': custom_id, 'placeholder': placeholder, 'min_values': min_values,
94
95
  'max_values': max_values, 'disabled': disabled, 'row': row, 'channel_types': channel_types})
95
96
 
@@ -97,10 +98,11 @@ class SelectMenu:
97
98
 
98
99
  return menu
99
100
 
100
- def set_callable(self, *custom_ids: str, _callable : Callable) -> "SelectMenu":
101
+ def set_callable(self, *custom_ids: str, _callable: Union[Callable, None]) -> "SelectMenu":
101
102
  """
102
- Set a callable for the menu associated with the custom_id
103
+ Set a callable for the menu associated with custom_ids
103
104
  :param custom_ids: IDs to menus
105
+ :param _callable: The coroutine to set for all menus
104
106
  """
105
107
  self.__select_menu.set_callable(*custom_ids, _callable=_callable)
106
108
  return self
@@ -117,9 +119,25 @@ class SelectMenu:
117
119
  """
118
120
  return await self.__select_menu.send(target=target, *args, view=self.__select_menu, **kwargs)
119
121
 
122
+ async def update(self):
123
+ """
124
+ Update the message.
125
+ If the command doesn't have been respond, nothing happened.
126
+ """
127
+ if self.get_view.message is None:
128
+ return
129
+ await self.__select_menu.update_items(*self.get_view.items)
130
+
120
131
  @property
121
132
  def get_view(self) -> EasyModifiedViews:
122
133
  """
123
134
  Get the current view
124
135
  """
125
136
  return self.__select_menu
137
+
138
+ def get_callable(self, custom_id: str) -> Union[Callable, None]:
139
+ """
140
+ Get the callable UI
141
+ :param custom_id: UI ID
142
+ """
143
+ return self.__select_menu.get_callable(custom_id)
@@ -23,6 +23,7 @@ class Pagination:
23
23
 
24
24
  self.__view.add_items(Button(label='⏮', row=0, custom_id='back+', style=ButtonStyle.blurple))
25
25
  self.__view.add_items(Button(label='◀', row=0, custom_id='back', style=ButtonStyle.blurple))
26
+ self.__view.add_items(Button(label='None', row=0, custom_id='counter', style=ButtonStyle.gray, disabled=True))
26
27
  self.__view.add_items(Button(label='▶', row=0, custom_id='forward', style=ButtonStyle.blurple))
27
28
  self.__view.add_items(Button(label='⏭', row=0, custom_id='forward+', style=ButtonStyle.blurple))
28
29
  self.__view.set_callable('back+', 'back', 'forward', 'forward+', _callable=self.__turn_page)
@@ -38,6 +39,7 @@ class Pagination:
38
39
  add_page(content="my message", embeds=[embed1, embed2], ...)
39
40
  """
40
41
  self.__pages.append((args, kwargs))
42
+ self.__view.get_ui('counter').label = f"{self.__current_page+1}/{len(self.__pages)}"
41
43
  return self
42
44
 
43
45
  def delete_pages(self, *page_numbers: Union[str, int]) -> "Pagination":
@@ -54,6 +56,7 @@ class Pagination:
54
56
  raise PageNumberNotFound(page_number)
55
57
 
56
58
  del self.__pages[page_number]
59
+ self.__view.get_ui('counter').label = f"{self.__current_page+1}/{len(self.__pages)}"
57
60
  return self
58
61
 
59
62
  async def __turn_page(self, button, interaction: Interaction):
@@ -81,11 +84,14 @@ class Pagination:
81
84
  elif interaction.custom_id == 'forward+': # Go to the last page
82
85
  self.__current_page = page_count-1
83
86
 
87
+ self.__view.get_ui('counter').label = f"{self.__current_page + 1}/{len(self.__pages)}"
84
88
 
85
89
  await interaction.message.edit(
86
90
 
87
91
  *self.__pages[self.__current_page][0],
88
92
 
93
+ view=self.get_view,
94
+
89
95
  **self.__pages[self.__current_page][1]
90
96
 
91
97
  )
@@ -117,5 +123,6 @@ class Pagination:
117
123
  def get_page(self) -> int:
118
124
  """
119
125
  Get the number of showed page
126
+ (start to 0)
120
127
  """
121
128
  return self.__current_page
@@ -1,10 +1,14 @@
1
+ from __future__ import annotations
1
2
  from discord import Interaction, ApplicationContext, Message, Member, TextChannel
2
3
  from discord.ui import View, Item
3
- from typing import Union, Callable, Iterable
4
+ from typing import Union, Callable, TYPE_CHECKING
4
5
 
5
- from ..typeViews import T_views
6
6
  from .errors import CustomIDNotFound
7
7
 
8
+ if TYPE_CHECKING:
9
+ from ..menu.selectMenu import SelectMenu
10
+ from ..pagination.pagination_view import Pagination
11
+
8
12
 
9
13
  class EasyModifiedViews(View):
10
14
  """
@@ -21,7 +25,7 @@ class EasyModifiedViews(View):
21
25
  super().__init__(*items, timeout=timeout)
22
26
  self.__timeout: Union[float, None] = timeout
23
27
  self.__disabled_on_timeout: bool = disabled_on_timeout
24
- self.__callback: dict[str, dict[str, Union[Callable[[Interaction], None], T_views]]] = {}
28
+ self.__callback: dict[str, dict[str, Union[Callable[[Interaction], None], Item]]] = {}
25
29
  self.__ctx: Union[Message, Interaction] = None
26
30
 
27
31
  def __check_custom_id(self, custom_id: str) -> None:
@@ -46,19 +50,25 @@ class EasyModifiedViews(View):
46
50
  self.__ctx = await target.send(*args, **kwargs)
47
51
 
48
52
  def add_items(self,
49
- *items: T_views) -> "EasyModifiedViews":
53
+ *items: Union[Item, SelectMenu, Pagination]) -> "EasyModifiedViews":
50
54
  """
51
55
  Add all items in the View.
52
56
  """
53
57
 
54
58
  for ui in items:
55
59
 
56
- self.__callback[ui.custom_id] = {'ui': ui, 'func': None}
57
- self.add_item(ui)
60
+ if type(ui).__name__ in ('SelectMenu', 'Pagination'):
61
+ for item in ui.get_view.items:
62
+ self.add_items(item)
63
+ self.set_callable(item.custom_id, _callable=ui.get_callable(item.custom_id))
64
+
65
+ else:
66
+ self.__callback[ui.custom_id] = {'ui': ui, 'func': None}
67
+ self.add_item(ui)
58
68
 
59
69
  return self
60
70
 
61
- async def update_items(self, *items: T_views) -> "EasyModifiedViews":
71
+ async def update_items(self, *items: Item) -> "EasyModifiedViews":
62
72
  """
63
73
  Update all views.
64
74
  Append items if custom_ids not in the view
@@ -67,7 +77,6 @@ class EasyModifiedViews(View):
67
77
  """
68
78
 
69
79
  for item in items:
70
-
71
80
  try:
72
81
  self.__check_custom_id(item.custom_id)
73
82
  self.__callback[item.custom_id]['ui'] = item
@@ -128,6 +137,14 @@ class EasyModifiedViews(View):
128
137
 
129
138
  self.__callback[custom_id]['func'] = _callable
130
139
 
140
+ def get_callable(self, custom_id: str) -> Union[Callable, None]:
141
+ """
142
+ Get the callable UI
143
+ :param custom_id: UI ID
144
+ """
145
+ self.__check_custom_id(custom_id)
146
+ return self.__callback[custom_id]['func']
147
+
131
148
  async def interaction_check(self, interaction: Interaction) -> bool:
132
149
  """
133
150
  Func to apply items
@@ -243,25 +260,26 @@ class EasyModifiedViews(View):
243
260
  """
244
261
  Update the View on the attached message.
245
262
  """
246
- try:
263
+ if self.is_finished():
264
+ return
247
265
 
248
- if self.message:
249
- await self.message.edit(view=self)
266
+ if self.message:
267
+ await self.message.edit(view=self)
250
268
 
251
- else:
252
- await self.__ctx.edit(view=self)
269
+ elif self.__ctx:
270
+ await self.__ctx.edit(view=self)
253
271
 
254
- except:
255
- pass
272
+ else:
273
+ return
256
274
 
257
275
  @property
258
- def get_uis(self) -> list[T_views]:
276
+ def get_uis(self) -> list[Item]:
259
277
  """
260
278
  Get all uis in the view
261
279
  """
262
280
  return [i['ui'] for i in self.__callback.values()]
263
281
 
264
- def get_ui(self, custom_id: str) -> T_views:
282
+ def get_ui(self, custom_id: str) -> Item:
265
283
  """
266
284
  Get an ui in the view
267
285
  :raise: CustomIDNotFound
@@ -270,4 +288,8 @@ class EasyModifiedViews(View):
270
288
  return self.__callback[custom_id]['ui']
271
289
 
272
290
  def __str__(self):
273
- return str(self.__callback)
291
+ return str(self.__callback)
292
+
293
+ @property
294
+ def items(self) -> tuple[Item]:
295
+ return tuple([i['ui'] for i in self.__callback.values()])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PycordViews
3
- Version: 1.1.3
3
+ Version: 1.1.4
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)
@@ -1,9 +1,8 @@
1
- pycordViews/__init__.py,sha256=SihgmXFTu75CxGmvRhVRHsRm4aDjMy8ZgiXfPuE3suE,223
2
- pycordViews/typeViews.py,sha256=5q_-FTUGMg2QjA7bsjbb2ep41Y4sm2sBPTCOV6b5X1w,122
3
- pycordViews/menu/__init__.py,sha256=SoAHnpJXxwTYDX5esYkgvSqpPqkuF1hDx22a-_U7ieU,83
1
+ pycordViews/__init__.py,sha256=g2OUxHZYfJf5E6F5ytwYm6bcL88NjHU1-79SWW5XHPw,240
2
+ pycordViews/menu/__init__.py,sha256=QUXA9ezyeTScvS1kxMNFgKEbZMsPq5yUnWWgbXCytCk,97
4
3
  pycordViews/menu/errors.py,sha256=0Um-oH5qMdWSZB_bGlqILsf9WSDtC4n_HwkheekiMV4,480
5
- pycordViews/menu/menu.py,sha256=piouHpZLhHSo8MtJjx3eUp0zLzZoxj0n05pwdy0EJl4,1786
6
- pycordViews/menu/selectMenu.py,sha256=8U1TNnfmTQTPCB1MtXGxrrs60qzL8L3JSDEw_PWfci0,9863
4
+ pycordViews/menu/menu.py,sha256=JrPH2YE93JphB71w9lSHrAtlInn8PSUW3bYM1dRBbaM,4298
5
+ pycordViews/menu/selectMenu.py,sha256=-eun3-EywSjiF_tzGTIQtuG99mkcAX0mMIKKBywvFtE,10428
7
6
  pycordViews/multibot/__init__.py,sha256=fP7jipm2AfsNyMLGgh4TEhvASA7NrPSLhSl2hU_xkw4,175
8
7
  pycordViews/multibot/errors.py,sha256=8C6jRRCOs3Y_tY_cvZIsGvz7XSreCkvWQ5ikj2hOf2s,238
9
8
  pycordViews/multibot/process_for_bots.py,sha256=O7Drpyy_A4y1zQq2D3SXLySWLJPnz6WVdynvTPk8gKM,3920
@@ -12,12 +11,12 @@ pycordViews/multibot/runner.py,sha256=ZyHTDu-wdZFbnoyEC00qe8MTf-STqFvrXytUE8Hr-E
12
11
  pycordViews/multibot/start_multibot.py,sha256=mHDBhiy7-Z3rvLbr8Ibqe9J9RXe_BusbZxq0aO3a16w,2598
13
12
  pycordViews/pagination/__init__.py,sha256=Z9BcdoTWyC1KXGwQ1_C0tu9rkZpdrrjEHwMmjXsckeE,81
14
13
  pycordViews/pagination/errors.py,sha256=CYb5gBcXx0kYDUDkNpfUrqSxQAcJE_qfpomWtUFOsTk,316
15
- pycordViews/pagination/pagination_view.py,sha256=DDtKOKFiSuxeMtb-bzBbwARFdpdBXk8vaD96pd0VW7g,4385
14
+ pycordViews/pagination/pagination_view.py,sha256=sJHDkmiTGwJzxfAUQijF2ry6NPVwepJvbdkAvA6j0es,4846
16
15
  pycordViews/views/__init__.py,sha256=yligptZmw-np8tjKLr76SVmi0807Nk6jCyKkKYLhbCY,89
17
- pycordViews/views/easy_modified_view.py,sha256=19YYvV7b-Ej0MZnjg10cl9s7MkRkyUZlyKt0AeHGF2I,8146
16
+ pycordViews/views/easy_modified_view.py,sha256=QuS8AnkTLHrdKl7Tya0_gjuwhWHLIvMAEK3DsyE1ALg,8986
18
17
  pycordViews/views/errors.py,sha256=0NBjBDaSFZChJua1ho9qyfbNzwXy1U6Kcob5CCUxBK8,218
19
- PycordViews-1.1.3.dist-info/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
20
- PycordViews-1.1.3.dist-info/METADATA,sha256=X-FyiPYkSemLVNroGOi6Eiwxmd1aESuYS80M5PNJCIU,2897
21
- PycordViews-1.1.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
- PycordViews-1.1.3.dist-info/top_level.txt,sha256=nqBU40KmnSCjtry8kmv97-RvZC-8xQrhrrloOJX2ROs,91
23
- PycordViews-1.1.3.dist-info/RECORD,,
18
+ pycordviews-1.1.4.dist-info/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
19
+ pycordviews-1.1.4.dist-info/METADATA,sha256=d1TMei7H42T-uSiZXentxHkNblnWMudJf6PQ4M31wO4,2897
20
+ pycordviews-1.1.4.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
21
+ pycordviews-1.1.4.dist-info/top_level.txt,sha256=nqBU40KmnSCjtry8kmv97-RvZC-8xQrhrrloOJX2ROs,91
22
+ pycordviews-1.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
pycordViews/typeViews.py DELETED
@@ -1,4 +0,0 @@
1
- from typing import TypeVar
2
- from discord.ui import Button, Select, Modal
3
-
4
- T_views = TypeVar('T_views', Button, Select)