dshellInterpreter 1.2.0.16__tar.gz → 1.2.0.17__tar.gz

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.
Files changed (54) hide show
  1. dshellinterpreter-1.2.0.17/Dshell/DISCORD_COMMANDS/dshell_ui.py +519 -0
  2. {dshellinterpreter-1.2.0.16/dshellInterpreter.egg-info → dshellinterpreter-1.2.0.17}/PKG-INFO +1 -1
  3. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17/dshellInterpreter.egg-info}/PKG-INFO +1 -1
  4. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/setup.py +1 -1
  5. dshellinterpreter-1.2.0.16/Dshell/DISCORD_COMMANDS/dshell_ui.py +0 -361
  6. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
  7. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
  8. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_embed.py +0 -0
  9. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_file.py +0 -0
  10. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +0 -0
  11. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
  12. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_message.py +0 -0
  13. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
  14. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
  15. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
  16. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py +0 -0
  17. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_file.py +0 -0
  18. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_global.py +0 -0
  19. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_list.py +0 -0
  20. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_member.py +0 -0
  21. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
  22. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_numbers.py +0 -0
  23. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +0 -0
  24. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_string.py +0 -0
  25. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
  26. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DISCORD_COMMANDS/utils/utils_type_validation.py +0 -0
  27. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/__init__.py +0 -0
  28. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/cached_messages.py +0 -0
  29. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/dshell_arguments.py +0 -0
  30. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/dshell_global_variables.py +0 -0
  31. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/dshell_interpreter.py +0 -0
  32. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/dshell_scope.py +0 -0
  33. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/errors.py +0 -0
  34. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellInterpreteur/utils_interpreter.py +0 -0
  35. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellParser/__init__.py +0 -0
  36. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellParser/ast_nodes.py +0 -0
  37. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellParser/dshell_parser.py +0 -0
  38. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellParser/errors.py +0 -0
  39. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellPreProcess/__init__.py +0 -0
  40. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellPreProcess/dshell_preprocess.py +0 -0
  41. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellTokenizer/__init__.py +0 -0
  42. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellTokenizer/dshell_keywords.py +0 -0
  43. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellTokenizer/dshell_token_type.py +0 -0
  44. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/DshellTokenizer/dshell_tokenizer.py +0 -0
  45. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/__init__.py +0 -0
  46. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/full_import.py +0 -0
  47. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/Dshell/regex_test.py +0 -0
  48. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/LICENSE +0 -0
  49. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/README.md +0 -0
  50. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
  51. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
  52. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/dshellInterpreter.egg-info/requires.txt +0 -0
  53. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/dshellInterpreter.egg-info/top_level.txt +0 -0
  54. {dshellinterpreter-1.2.0.16 → dshellinterpreter-1.2.0.17}/setup.cfg +0 -0
@@ -0,0 +1,519 @@
1
+ from Dshell.full_import import (ButtonStyle,
2
+ PrivateChannel,
3
+ Interaction,
4
+ ui,
5
+ MISSING,
6
+ EasyModifiedViews,
7
+ CustomIDNotFound,
8
+ SelectMenu,
9
+ ComponentType,
10
+ random)
11
+
12
+ from ..DshellParser.ast_nodes import UiSelectNode, UiButtonNode, OptionUiSelectNode, ListNode, StrNode, IntNode, BoolNode
13
+
14
+ from ..DshellInterpreteur.utils_interpreter import regroupe_commandes
15
+
16
+ from ..DshellInterpreteur.dshell_scope import new_scope
17
+
18
+ from Dshell.full_import import Any, TYPE_CHECKING, Union
19
+
20
+ from .utils.utils_type_validation import (_validate_optional_code_node,
21
+ _validate_optional_int,
22
+ _validate_optional_string)
23
+
24
+ from .utils.utils_global import utils_refactor_emoji
25
+
26
+ if TYPE_CHECKING:
27
+ from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
28
+
29
+
30
+ ButtonStyleValues: set = {i.name for i in ButtonStyle}
31
+ SelectSyleValues: dict = {'string': ComponentType.string_select,
32
+ 'role': ComponentType.role_select,
33
+ 'user': ComponentType.user_select,
34
+ 'mention': ComponentType.mentionable_select,
35
+ 'channel': ComponentType.channel_select}
36
+
37
+ async def build_ui_button_parameters(ui_button_node: UiButtonNode, interpreter: "DshellInterpreteur"):
38
+ """
39
+ Builds the parameters for a UI component from the UiNode.
40
+ Can accept buttons and select menus.
41
+ :param ui_node:
42
+ :param interpreter:
43
+ :return:
44
+ """
45
+ regrouped_parameters = await regroupe_commandes(ui_button_node.body, interpreter, normalise=True)
46
+ args_button: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
47
+
48
+ code = args_button.pop('code', None)
49
+ style = args_button.pop('style', 'primary').lower()
50
+ custom_id = args_button.pop('custom_id', 'ui_button_'+str(random()))
51
+ row = args_button.pop('row', 0)
52
+ emoji = utils_refactor_emoji(args_button.pop('emoji', None))
53
+
54
+ _validate_optional_code_node(code, "Button code", "build_ui_button")
55
+
56
+ if not isinstance(custom_id, str):
57
+ raise TypeError(f"Button custom_id must be a string, not {type(custom_id)} !")
58
+
59
+ if style not in ButtonStyleValues:
60
+ raise ValueError(f"Button style must be one of {', '.join(ButtonStyleValues)}, not '{style}' !")
61
+
62
+ args_button['custom_id'] = custom_id
63
+ args_button['row'] = row
64
+ args_button['style'] = ButtonStyle[style]
65
+ args_button['emoji'] = emoji
66
+ args = args_button.pop('*', ())
67
+ yield args, args_button, code
68
+
69
+
70
+ async def build_ui_select_parameters(ui_select_node: UiSelectNode, interpreter: "DshellInterpreteur"):
71
+ """
72
+ Builds the parameters for a UI select menu from the UiNode.
73
+ :param ui_select_node:
74
+ :param interpreter:
75
+ :return:
76
+ """
77
+ regrouped_parameters = await regroupe_commandes(ui_select_node.body, interpreter, normalise=True)
78
+ args_select: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
79
+
80
+ code = args_select.pop('code', None)
81
+ custom_id = args_select.pop('custom_id', 'ui_select_'+str(random()))
82
+ select_type = args_select.pop('type', 'string').lower()
83
+
84
+ disabled = args_select.get('disabled', False)
85
+ max_values = args_select.get('max', 1)
86
+ min_values = args_select.get('min', 1)
87
+ placeholder = args_select.get('placeholder', "")
88
+ row = args_select.pop('row', 0)
89
+
90
+ _validate_optional_code_node(code, "Select code", "build_ui_select")
91
+
92
+ if not isinstance(custom_id, str):
93
+ raise TypeError(f"Select custom_id must be a string, not {type(custom_id)} !")
94
+
95
+ if select_type is None or not isinstance(select_type, str) or select_type not in SelectSyleValues:
96
+ raise TypeError(f"Select type must be a string, not {type(select_type)} !")
97
+
98
+ if not isinstance(disabled, bool):
99
+ raise TypeError(f"Select disabled must be a bool, not {type(disabled)} !")
100
+
101
+ if not isinstance(max_values, int):
102
+ raise TypeError(f"Select max_values must be an int, not {type(max_values)} !")
103
+
104
+ if not isinstance(min_values, int):
105
+ raise TypeError(f"Select min_values must be an int, not {type(min_values)} !")
106
+
107
+ if not isinstance(placeholder, str):
108
+ raise TypeError(f"Select placeholder must be a string, not {type(placeholder)} !")
109
+
110
+ _validate_optional_int(row, "Select row", "build_ui_select")
111
+
112
+ args_select["disabled"] = disabled
113
+ args_select["max_values"] = max_values
114
+ args_select["min_values"] = min_values
115
+ args_select["options"] = await build_ui_select_options(ui_select_node.options, interpreter)
116
+ args_select["placeholder"] = placeholder
117
+ args_select["row"] = row
118
+ args_select["type"] = SelectSyleValues[select_type]
119
+ args_select['custom_id'] = custom_id
120
+ args = args_select.pop('*', ())
121
+
122
+ yield args, args_select, code
123
+
124
+ async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interpreter: "DshellInterpreteur"):
125
+ """
126
+ Builds the options for a UI select menu from the OptionUiSelectNode.
127
+ :param option_nodes:
128
+ :param interpreter:
129
+ :return:
130
+ """
131
+ option_results: list[dict[str, Any]] = []
132
+
133
+ for option_node in option_nodes:
134
+ regrouped_parameters = await regroupe_commandes(option_node.body, interpreter, normalise=True)
135
+ args_option: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
136
+
137
+ label = args_option.pop('label', None)
138
+ value = args_option.pop('value', MISSING)
139
+ description = args_option.pop('description', None)
140
+ emoji = utils_refactor_emoji(args_option.pop('emoji', None))
141
+ default = args_option.pop('default', False)
142
+
143
+ if label is None or not isinstance(label, str):
144
+ raise TypeError(f"Option label must be a string, not {type(label)} !")
145
+
146
+ if len(label) > 100:
147
+ raise ValueError("Option label must be less than 100 characters !")
148
+
149
+ if value and not isinstance(value, str):
150
+ raise TypeError(f"Option value must be a string, not {type(value)} !")
151
+
152
+ if value and len(value) > 100:
153
+ raise ValueError("Option value must be less than 100 characters !")
154
+
155
+ _validate_optional_string(description, "Option description", "build_ui_option")
156
+
157
+ if description is not None and len(description) > 100:
158
+ raise ValueError("Option description must be less than 100 characters !")
159
+
160
+ _validate_optional_string(emoji, "Option emoji", "build_ui_option")
161
+
162
+ if not isinstance(default, bool):
163
+ raise TypeError(f"Option default must be a bool, not {type(default)} !")
164
+
165
+ option_dict = {
166
+ 'label': label,
167
+ 'value': value,
168
+ 'description': description,
169
+ 'emoji': emoji,
170
+ 'default': default,
171
+ }
172
+ option_results.append(option_dict)
173
+
174
+ return option_results
175
+
176
+
177
+ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "DshellInterpreteur") -> EasyModifiedViews:
178
+ """
179
+ Builds a UI component from the UiNode.
180
+ Can accept buttons and select menus.
181
+ :param ui_node:
182
+ :param interpreter:
183
+ :return:
184
+ """
185
+ view = EasyModifiedViews()
186
+
187
+ if isinstance(ui_node, UiButtonNode):
188
+ async for _, args_button, code in build_ui_button_parameters(ui_node, interpreter):
189
+ print(args_button)
190
+ b = ui.Button(**args_button)
191
+ view.add_items(b)
192
+ view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, 'interpreter': interpreter})
193
+
194
+ elif isinstance(ui_node, UiSelectNode):
195
+ s = SelectMenu()
196
+ async for _, args_select, code in build_ui_select_parameters(ui_node, interpreter):
197
+
198
+ options = args_select.pop("options", [])
199
+ select_type = args_select.pop("type")
200
+
201
+ if select_type == ComponentType.string_select:
202
+ menu = s.add_string_select_menu(**args_select)
203
+
204
+ for option in options:
205
+ menu.add_option(**option)
206
+
207
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
208
+
209
+ elif select_type == ComponentType.role_select:
210
+ s.add_role_select_menu(**args_select)
211
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
212
+
213
+ elif select_type == ComponentType.user_select:
214
+ s.add_user_select_menu(**args_select)
215
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
216
+
217
+ elif select_type == ComponentType.mentionable_select:
218
+ s.add_mentionable_select_menu(**args_select)
219
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
220
+
221
+ elif select_type == ComponentType.channel_select:
222
+ s.add_channel_select_menu(**args_select)
223
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
224
+
225
+ view.add_items(s)
226
+
227
+ else:
228
+ raise TypeError(f"UI node must be UiButtonNode or UiSelectNode, not {type(ui_node)} !")
229
+
230
+ return view
231
+
232
+
233
+
234
+ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModifiedViews, interpreter: "DshellInterpreteur") -> EasyModifiedViews:
235
+ """
236
+ Rebuilds a UI component from an existing EasyModifiedViews.
237
+ :param view:
238
+ :param interpreter:
239
+ :return:
240
+ """
241
+ if isinstance(ui_node, UiButtonNode):
242
+
243
+ async for args, args_button, code in build_ui_button_parameters(ui_node, interpreter):
244
+ try:
245
+ ui: ui.Button = view.get_ui(args_button['custom_id'])
246
+ except CustomIDNotFound:
247
+ raise ValueError(f"Button with custom_id '{args_button['custom_id']}' not found in the view !")
248
+
249
+ ui.label = args_button.get('label', ui.label)
250
+ ui.style = args_button.get('style', ui.style)
251
+ ui.emoji = args_button.get('emoji', ui.emoji)
252
+ ui.disabled = args_button.get('disabled', ui.disabled)
253
+ ui.url = args_button.get('url', ui.url)
254
+ ui.row = args_button.get('row', ui.row)
255
+ new_code = code if code is not None else view.get_callable_data(args_button['custom_id'])['code']
256
+ view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code, 'interpreter': interpreter})
257
+
258
+ elif isinstance(ui_node, UiSelectNode):
259
+
260
+ async for args, args_select, code in build_ui_select_parameters(ui_select_node=ui_node, interpreter=interpreter):
261
+ try:
262
+ ui: ui.Select = view.get_ui(args_select['custom_id'])
263
+ except CustomIDNotFound:
264
+ raise ValueError(f"Select menu with custom_id '{args_select['custom_id']}' not found in the view !")
265
+
266
+ ui.placeholder = args_select.get('placeholder', ui.placeholder)
267
+ ui.min_values = args_select.get('min_values', ui.min_values)
268
+ ui.max_values = args_select.get('max_values', ui.max_values)
269
+ ui.disabled = args_select.get('disabled', ui.disabled)
270
+
271
+ ui.options.clear()
272
+ options = args_select.pop("options", [])
273
+ for option in options:
274
+ ui.add_option(**option)
275
+
276
+ new_code = code if code is not None else view.get_callable_data(args_select['custom_id'])['code']
277
+ view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code, 'interpreter': interpreter})
278
+
279
+ return view
280
+
281
+
282
+ async def ui_button_callback(button: ui.Button, interaction: Interaction, data: dict[str, Any]):
283
+ """
284
+ Callback for UI buttons.
285
+ Executes the code associated with the button.
286
+ :param button:
287
+ :param interaction:
288
+ :param data:
289
+ :return:
290
+ """
291
+ code = data.pop('code', None)
292
+ interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
293
+ if code is not None:
294
+ message = interaction
295
+ local_env = {
296
+ '__ret__': None, # environment variables, '__ret__' is used to store the return value of commands
297
+ '__loop__': None, # used to store the current loop variable in loop nodes if the loop identifier is not specified
298
+ '__break__': BoolNode(0), # used to break a loop
299
+
300
+ '__author__': IntNode(message.user.id),
301
+ '__author_name__': StrNode(message.user.name),
302
+ '__author_display_name__': StrNode(message.user.display_name),
303
+ '__author_avatar__': StrNode(message.user.display_avatar.url) if message.user.display_avatar else None,
304
+ '__author_discriminator__': StrNode(message.user.discriminator),
305
+ '__author_bot__': BoolNode(message.user.bot),
306
+ '__author_nick__': StrNode(message.user.nick) if hasattr(message.user, 'nick') else None,
307
+ '__author_id__': IntNode(message.user.id),
308
+ '__author_add_reaction__': None, # Can be overwritten by add vars_env parameter to get the author on message add event reaction
309
+ '__author_remove_reaction__': None, # Can be overwritten by add vars_env parameter to get the author on message remove event reaction
310
+
311
+ '__message__': StrNode(message.message.content),
312
+ '__message_content__': StrNode(message.message.content),
313
+ '__message_id__': IntNode(message.message.id),
314
+ '__message_author__': IntNode(message.message.author.id),
315
+ '__message_before__': StrNode(message.message.content), # same as __message__, but before edit. Can be overwritten by add vars_env parameter
316
+ '__message_created_at__': StrNode(message.message.created_at),
317
+ '__message_edited_at__': StrNode(message.message.edited_at),
318
+ '__message_reactions__': ListNode([StrNode(reaction.emoji) for reaction in message.message.reactions], bypass_limit_elt=True, editable=False),
319
+ '__message_add_reaction__': None, # Can be overwritten by add vars_env parameter to get the reaction added on message add event reaction
320
+ '__message_remove_reaction__': None, # Can be overwritten by add vars_env parameter to get the reaction removed on message remove event reaction
321
+ '__message_url__': StrNode(message.message.jump_url) if hasattr(message.message, 'jump_url') else None,
322
+ '__last_message__': IntNode(message.message.channel.last_message_id),
323
+
324
+ '__channel__': IntNode(message.message.channel.id),
325
+ '__channel_name__': StrNode(message.message.channel.name),
326
+ '__channel_type__': StrNode(message.message.channel.type.name) if hasattr(message.message.channel, 'type') else None,
327
+ '__channel_id__': IntNode(message.message.channel.id),
328
+ '__private_channel__': BoolNode(isinstance(message.message.channel, PrivateChannel)),
329
+ }
330
+
331
+ if message.guild is not None:
332
+ local_env.update(
333
+ {
334
+ '__guild__': IntNode(message.channel.guild.id),
335
+ '__guild_name__': StrNode(message.channel.guild.name),
336
+ '__guild_id__': IntNode(message.channel.guild.id),
337
+ '__guild_members__': ListNode([IntNode(member.id) for member in message.channel.guild.members], bypass_limit_elt=True, editable=False),
338
+ '__guild_member_count__': IntNode(message.channel.guild.member_count),
339
+ '__guild_icon__': StrNode(message.channel.guild.icon.url) if message.channel.guild.icon else None,
340
+ '__guild_owner_id__': IntNode(message.channel.guild.owner_id),
341
+ '__guild_description__': StrNode(message.channel.guild.description),
342
+ '__guild_roles__': ListNode([IntNode(role.id) for role in message.channel.guild.roles], bypass_limit_elt=True, editable=False),
343
+ '__guild_roles_count__': IntNode(len(message.channel.guild.roles)),
344
+ '__guild_emojis__': ListNode([IntNode(emoji.id) for emoji in message.channel.guild.emojis], bypass_limit_elt=True, editable=False),
345
+ '__guild_emojis_count__': IntNode(len(message.channel.guild.emojis)),
346
+ '__guild_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.channels], bypass_limit_elt=True, editable=False),
347
+ '__guild_text_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.text_channels], bypass_limit_elt=True, editable=False),
348
+ '__guild_voice_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.voice_channels], bypass_limit_elt=True, editable=False),
349
+ '__guild_categories__': ListNode([IntNode(channel.id) for channel in message.channel.guild.categories], bypass_limit_elt=True, editable=False),
350
+ '__guild_stage_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.stage_channels], bypass_limit_elt=True, editable=False),
351
+ '__guild_forum_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.forum_channels], bypass_limit_elt=True, editable=False),
352
+ '__guild_channels_count__': IntNode(len(message.channel.guild.channels)),
353
+ }
354
+ )
355
+ else:
356
+ local_env.update(
357
+ {
358
+ '__guild__': None,
359
+ '__guild_name__': None,
360
+ '__guild_id__': None,
361
+ '__guild_members__': None,
362
+ '__guild_member_count__': None,
363
+ '__guild_icon__': None,
364
+ '__guild_owner_id__': None,
365
+ '__guild_description__': None,
366
+ '__guild_roles__': None,
367
+ '__guild_roles_count__': None,
368
+ '__guild_emojis__': None,
369
+ '__guild_emojis_count__': None,
370
+ '__guild_channels__': None,
371
+ '__guild_text_channels__': None,
372
+ '__guild_voice_channels__': None,
373
+ '__guild_categories__': None,
374
+ '__guild_stage_channels__': None,
375
+ '__guild_forum_channels__': None,
376
+ '__guild_channels_count__': None,
377
+ }
378
+ )
379
+
380
+ local_env.update(data)
381
+ from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
382
+ with new_scope(interpreter, local_env):
383
+ await DshellInterpreteur(code, ctx=interaction, debug=False, vars_env=interpreter.env).execute()
384
+ else:
385
+ await interaction.response.defer(invisible=True)
386
+
387
+ data.update({'code': code, 'interpreter': interpreter})
388
+
389
+ async def ui_select_callback(select: ui.Select, interaction: Interaction, data: dict[str, Any]):
390
+ """
391
+ Callback for UI select menus.
392
+ Executes the code associated with the select menu.
393
+ :param select:
394
+ :param interaction:
395
+ :param data:
396
+ :return:
397
+ """
398
+ code = data.pop('code', None)
399
+ interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
400
+
401
+ message = interaction
402
+ if code is not None:
403
+ local_env = {
404
+ '__values__': ListNode([IntNode(i.id) for i in select.values]) if select.values and hasattr(
405
+ select.values[0], 'id') else ListNode(StrNode(i) for i in select.values),
406
+ '__ret__': None, # environment variables, '__ret__' is used to store the return value of commands
407
+ '__loop__': None,
408
+ # used to store the current loop variable in loop nodes if the loop identifier is not specified
409
+ '__break__': BoolNode(0), # used to break a loop
410
+
411
+ '__author__': IntNode(message.user.id),
412
+ '__author_name__': StrNode(message.user.name),
413
+ '__author_display_name__': StrNode(message.user.display_name),
414
+ '__author_avatar__': StrNode(message.user.display_avatar.url) if message.user.display_avatar else None,
415
+ '__author_discriminator__': StrNode(message.user.discriminator),
416
+ '__author_bot__': BoolNode(message.user.bot),
417
+ '__author_nick__': StrNode(message.user.nick) if hasattr(message.user, 'nick') else None,
418
+ '__author_id__': IntNode(message.user.id),
419
+ '__author_add_reaction__': None,
420
+ # Can be overwritten by add vars_env parameter to get the author on message add event reaction
421
+ '__author_remove_reaction__': None,
422
+ # Can be overwritten by add vars_env parameter to get the author on message remove event reaction
423
+
424
+ '__message__': StrNode(message.message.content),
425
+ '__message_content__': StrNode(message.message.content),
426
+ '__message_id__': IntNode(message.message.id),
427
+ '__message_author__': IntNode(message.message.author.id),
428
+ '__message_before__': StrNode(message.message.content),
429
+ # same as __message__, but before edit. Can be overwritten by add vars_env parameter
430
+ '__message_created_at__': StrNode(message.message.created_at),
431
+ '__message_edited_at__': StrNode(message.message.edited_at),
432
+ '__message_reactions__': ListNode([StrNode(reaction.emoji) for reaction in message.message.reactions],
433
+ bypass_limit_elt=True, editable=False),
434
+ '__message_add_reaction__': None,
435
+ # Can be overwritten by add vars_env parameter to get the reaction added on message add event reaction
436
+ '__message_remove_reaction__': None,
437
+ # Can be overwritten by add vars_env parameter to get the reaction removed on message remove event reaction
438
+ '__message_url__': StrNode(message.message.jump_url) if hasattr(message.message, 'jump_url') else None,
439
+ '__last_message__': IntNode(message.message.channel.last_message_id),
440
+
441
+ '__channel__': IntNode(message.message.channel.id),
442
+ '__channel_name__': StrNode(message.message.channel.name),
443
+ '__channel_type__': StrNode(message.message.channel.type.name) if hasattr(message.message.channel,
444
+ 'type') else None,
445
+ '__channel_id__': IntNode(message.message.channel.id),
446
+ '__private_channel__': BoolNode(isinstance(message.message.channel, PrivateChannel)),
447
+ }
448
+
449
+ if message.guild is not None:
450
+ local_env.update(
451
+ {
452
+ '__guild__': IntNode(message.channel.guild.id),
453
+ '__guild_name__': StrNode(message.channel.guild.name),
454
+ '__guild_id__': IntNode(message.channel.guild.id),
455
+ '__guild_members__': ListNode([IntNode(member.id) for member in message.channel.guild.members],
456
+ bypass_limit_elt=True, editable=False),
457
+ '__guild_member_count__': IntNode(message.channel.guild.member_count),
458
+ '__guild_icon__': StrNode(message.channel.guild.icon.url) if message.channel.guild.icon else None,
459
+ '__guild_owner_id__': IntNode(message.channel.guild.owner_id),
460
+ '__guild_description__': StrNode(message.channel.guild.description),
461
+ '__guild_roles__': ListNode([IntNode(role.id) for role in message.channel.guild.roles],
462
+ bypass_limit_elt=True, editable=False),
463
+ '__guild_roles_count__': IntNode(len(message.channel.guild.roles)),
464
+ '__guild_emojis__': ListNode([IntNode(emoji.id) for emoji in message.channel.guild.emojis],
465
+ bypass_limit_elt=True, editable=False),
466
+ '__guild_emojis_count__': IntNode(len(message.channel.guild.emojis)),
467
+ '__guild_channels__': ListNode([IntNode(channel.id) for channel in message.channel.guild.channels],
468
+ bypass_limit_elt=True, editable=False),
469
+ '__guild_text_channels__': ListNode(
470
+ [IntNode(channel.id) for channel in message.channel.guild.text_channels], bypass_limit_elt=True,
471
+ editable=False),
472
+ '__guild_voice_channels__': ListNode(
473
+ [IntNode(channel.id) for channel in message.channel.guild.voice_channels],
474
+ bypass_limit_elt=True, editable=False),
475
+ '__guild_categories__': ListNode(
476
+ [IntNode(channel.id) for channel in message.channel.guild.categories], bypass_limit_elt=True,
477
+ editable=False),
478
+ '__guild_stage_channels__': ListNode(
479
+ [IntNode(channel.id) for channel in message.channel.guild.stage_channels],
480
+ bypass_limit_elt=True, editable=False),
481
+ '__guild_forum_channels__': ListNode(
482
+ [IntNode(channel.id) for channel in message.channel.guild.forum_channels],
483
+ bypass_limit_elt=True, editable=False),
484
+ '__guild_channels_count__': IntNode(len(message.channel.guild.channels)),
485
+ }
486
+ )
487
+ else:
488
+ local_env.update(
489
+ {
490
+ '__guild__': None,
491
+ '__guild_name__': None,
492
+ '__guild_id__': None,
493
+ '__guild_members__': None,
494
+ '__guild_member_count__': None,
495
+ '__guild_icon__': None,
496
+ '__guild_owner_id__': None,
497
+ '__guild_description__': None,
498
+ '__guild_roles__': None,
499
+ '__guild_roles_count__': None,
500
+ '__guild_emojis__': None,
501
+ '__guild_emojis_count__': None,
502
+ '__guild_channels__': None,
503
+ '__guild_text_channels__': None,
504
+ '__guild_voice_channels__': None,
505
+ '__guild_categories__': None,
506
+ '__guild_stage_channels__': None,
507
+ '__guild_forum_channels__': None,
508
+ '__guild_channels_count__': None,
509
+ }
510
+ )
511
+
512
+ local_env.update(data)
513
+ from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
514
+ with new_scope(interpreter, local_env):
515
+ await DshellInterpreteur(code, ctx=interaction, debug=False, vars_env=interpreter.env).execute()
516
+ else:
517
+ await interaction.response.defer(invisible=True)
518
+
519
+ data.update({'code': code, 'interpreter': interpreter})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 1.2.0.16
3
+ Version: 1.2.0.17
4
4
  Summary: A Discord bot interpreter for creating custom commands and automations.
5
5
  Home-page: https://github.com/BOXERRMD/Dshell_Interpreter
6
6
  Author: Chronos
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 1.2.0.16
3
+ Version: 1.2.0.17
4
4
  Summary: A Discord bot interpreter for creating custom commands and automations.
5
5
  Home-page: https://github.com/BOXERRMD/Dshell_Interpreter
6
6
  Author: Chronos
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setup(
7
7
  name="dshellInterpreter",
8
- version="1.2.0.16",
8
+ version="1.2.0.17",
9
9
  author="Chronos",
10
10
  author_email="vagabonwalybi@gmail.com",
11
11
  description="A Discord bot interpreter for creating custom commands and automations.",
@@ -1,361 +0,0 @@
1
- from Dshell.full_import import (ButtonStyle,
2
- PrivateChannel,
3
- Interaction,
4
- Button,
5
- MISSING,
6
- EasyModifiedViews,
7
- CustomIDNotFound,
8
- SelectMenu,
9
- ComponentType,
10
- Select,
11
- random)
12
-
13
- from ..DshellParser.ast_nodes import UiSelectNode, UiButtonNode, CodeNode, OptionUiSelectNode, ListNode
14
-
15
- from ..DshellInterpreteur.utils_interpreter import regroupe_commandes
16
-
17
- from ..DshellInterpreteur.dshell_scope import new_scope
18
-
19
- from Dshell.full_import import Any, TYPE_CHECKING, Union
20
-
21
- from .utils.utils_type_validation import (_validate_optional_code_node,
22
- _validate_optional_int,
23
- _validate_optional_string)
24
-
25
- from .utils.utils_global import utils_refactor_emoji
26
-
27
- if TYPE_CHECKING:
28
- from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
29
-
30
-
31
- ButtonStyleValues: set = {i.name for i in ButtonStyle}
32
- SelectSyleValues: dict = {'string': ComponentType.string_select,
33
- 'role': ComponentType.role_select,
34
- 'user': ComponentType.user_select,
35
- 'mention': ComponentType.mentionable_select,
36
- 'channel': ComponentType.channel_select}
37
-
38
- async def build_ui_button_parameters(ui_button_node: UiButtonNode, interpreter: "DshellInterpreteur"):
39
- """
40
- Builds the parameters for a UI component from the UiNode.
41
- Can accept buttons and select menus.
42
- :param ui_node:
43
- :param interpreter:
44
- :return:
45
- """
46
- regrouped_parameters = await regroupe_commandes(ui_button_node.body, interpreter, normalise=True)
47
- args_button: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
48
-
49
- code = args_button.pop('code', None)
50
- style = args_button.pop('style', 'primary').lower()
51
- custom_id = args_button.pop('custom_id', 'ui_button_'+str(random()))
52
- row = args_button.pop('row', 0)
53
- emoji = utils_refactor_emoji(args_button.pop('emoji', None))
54
-
55
- _validate_optional_code_node(code, "Button code", "build_ui_button")
56
-
57
- if not isinstance(custom_id, str):
58
- raise TypeError(f"Button custom_id must be a string, not {type(custom_id)} !")
59
-
60
- if style not in ButtonStyleValues:
61
- raise ValueError(f"Button style must be one of {', '.join(ButtonStyleValues)}, not '{style}' !")
62
-
63
- args_button['custom_id'] = custom_id
64
- args_button['row'] = row
65
- args_button['style'] = ButtonStyle[style]
66
- args_button['emoji'] = emoji
67
- args = args_button.pop('*', ())
68
- yield args, args_button, code
69
-
70
-
71
- async def build_ui_select_parameters(ui_select_node: UiSelectNode, interpreter: "DshellInterpreteur"):
72
- """
73
- Builds the parameters for a UI select menu from the UiNode.
74
- :param ui_select_node:
75
- :param interpreter:
76
- :return:
77
- """
78
- regrouped_parameters = await regroupe_commandes(ui_select_node.body, interpreter, normalise=True)
79
- args_select: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
80
-
81
- code = args_select.pop('code', None)
82
- custom_id = args_select.pop('custom_id', 'ui_select_'+str(random()))
83
- select_type = args_select.pop('type', 'string').lower()
84
-
85
- disabled = args_select.get('disabled', False)
86
- max_values = args_select.get('max', 1)
87
- min_values = args_select.get('min', 1)
88
- placeholder = args_select.get('placeholder', "")
89
- row = args_select.pop('row', 0)
90
-
91
- _validate_optional_code_node(code, "Select code", "build_ui_select")
92
-
93
- if not isinstance(custom_id, str):
94
- raise TypeError(f"Select custom_id must be a string, not {type(custom_id)} !")
95
-
96
- if select_type is None or not isinstance(select_type, str) or select_type not in SelectSyleValues:
97
- raise TypeError(f"Select type must be a string, not {type(select_type)} !")
98
-
99
- if not isinstance(disabled, bool):
100
- raise TypeError(f"Select disabled must be a bool, not {type(disabled)} !")
101
-
102
- if not isinstance(max_values, int):
103
- raise TypeError(f"Select max_values must be an int, not {type(max_values)} !")
104
-
105
- if not isinstance(min_values, int):
106
- raise TypeError(f"Select min_values must be an int, not {type(min_values)} !")
107
-
108
- if not isinstance(placeholder, str):
109
- raise TypeError(f"Select placeholder must be a string, not {type(placeholder)} !")
110
-
111
- _validate_optional_int(row, "Select row", "build_ui_select")
112
-
113
- args_select["disabled"] = disabled
114
- args_select["max_values"] = max_values
115
- args_select["min_values"] = min_values
116
- args_select["options"] = await build_ui_select_options(ui_select_node.options, interpreter)
117
- args_select["placeholder"] = placeholder
118
- args_select["row"] = row
119
- args_select["type"] = SelectSyleValues[select_type]
120
- args_select['custom_id'] = custom_id
121
- args = args_select.pop('*', ())
122
-
123
- yield args, args_select, code
124
-
125
- async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interpreter: "DshellInterpreteur"):
126
- """
127
- Builds the options for a UI select menu from the OptionUiSelectNode.
128
- :param option_nodes:
129
- :param interpreter:
130
- :return:
131
- """
132
- option_results: list[dict[str, Any]] = []
133
-
134
- for option_node in option_nodes:
135
- regrouped_parameters = await regroupe_commandes(option_node.body, interpreter, normalise=True)
136
- args_option: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
137
-
138
- label = args_option.pop('label', None)
139
- value = args_option.pop('value', MISSING)
140
- description = args_option.pop('description', None)
141
- emoji = utils_refactor_emoji(args_option.pop('emoji', None))
142
- default = args_option.pop('default', False)
143
-
144
- if label is None or not isinstance(label, str):
145
- raise TypeError(f"Option label must be a string, not {type(label)} !")
146
-
147
- if len(label) > 100:
148
- raise ValueError("Option label must be less than 100 characters !")
149
-
150
- if value and not isinstance(value, str):
151
- raise TypeError(f"Option value must be a string, not {type(value)} !")
152
-
153
- if value and len(value) > 100:
154
- raise ValueError("Option value must be less than 100 characters !")
155
-
156
- _validate_optional_string(description, "Option description", "build_ui_option")
157
-
158
- if description is not None and len(description) > 100:
159
- raise ValueError("Option description must be less than 100 characters !")
160
-
161
- _validate_optional_string(emoji, "Option emoji", "build_ui_option")
162
-
163
- if not isinstance(default, bool):
164
- raise TypeError(f"Option default must be a bool, not {type(default)} !")
165
-
166
- option_dict = {
167
- 'label': label,
168
- 'value': value,
169
- 'description': description,
170
- 'emoji': emoji,
171
- 'default': default,
172
- }
173
- option_results.append(option_dict)
174
-
175
- return option_results
176
-
177
-
178
- async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "DshellInterpreteur") -> EasyModifiedViews:
179
- """
180
- Builds a UI component from the UiNode.
181
- Can accept buttons and select menus.
182
- :param ui_node:
183
- :param interpreter:
184
- :return:
185
- """
186
- view = EasyModifiedViews()
187
-
188
- if isinstance(ui_node, UiButtonNode):
189
- async for _, args_button, code in build_ui_button_parameters(ui_node, interpreter):
190
- b = Button(**args_button)
191
- view.add_items(b)
192
- view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, 'interpreter': interpreter})
193
-
194
- elif isinstance(ui_node, UiSelectNode):
195
- s = SelectMenu()
196
- async for _, args_select, code in build_ui_select_parameters(ui_node, interpreter):
197
-
198
- options = args_select.pop("options", [])
199
- select_type = args_select.pop("type")
200
-
201
- if select_type == ComponentType.string_select:
202
- menu = s.add_string_select_menu(**args_select)
203
-
204
- for option in options:
205
- menu.add_option(**option)
206
-
207
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
208
-
209
- elif select_type == ComponentType.role_select:
210
- s.add_role_select_menu(**args_select)
211
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
212
-
213
- elif select_type == ComponentType.user_select:
214
- s.add_user_select_menu(**args_select)
215
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
216
-
217
- elif select_type == ComponentType.mentionable_select:
218
- s.add_mentionable_select_menu(**args_select)
219
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
220
-
221
- elif select_type == ComponentType.channel_select:
222
- s.add_channel_select_menu(**args_select)
223
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
224
-
225
- view.add_items(s)
226
-
227
- else:
228
- raise TypeError(f"UI node must be UiButtonNode or UiSelectNode, not {type(ui_node)} !")
229
-
230
- return view
231
-
232
-
233
-
234
- async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModifiedViews, interpreter: "DshellInterpreteur") -> EasyModifiedViews:
235
- """
236
- Rebuilds a UI component from an existing EasyModifiedViews.
237
- :param view:
238
- :param interpreter:
239
- :return:
240
- """
241
- if isinstance(ui_node, UiButtonNode):
242
-
243
- async for args, args_button, code in build_ui_button_parameters(ui_node, interpreter):
244
- try:
245
- ui: Button = view.get_ui(args_button['custom_id'])
246
- except CustomIDNotFound:
247
- raise ValueError(f"Button with custom_id '{args_button['custom_id']}' not found in the view !")
248
-
249
- ui.label = args_button.get('label', ui.label)
250
- ui.style = args_button.get('style', ui.style)
251
- ui.emoji = args_button.get('emoji', ui.emoji)
252
- ui.disabled = args_button.get('disabled', ui.disabled)
253
- ui.url = args_button.get('url', ui.url)
254
- ui.row = args_button.get('row', ui.row)
255
- new_code = code if code is not None else view.get_callable_data(args_button['custom_id'])['code']
256
- view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code, 'interpreter': interpreter})
257
-
258
- elif isinstance(ui_node, UiSelectNode):
259
-
260
- async for args, args_select, code in build_ui_select_parameters(ui_select_node=ui_node, interpreter=interpreter):
261
- try:
262
- ui: Select = view.get_ui(args_select['custom_id'])
263
- except CustomIDNotFound:
264
- raise ValueError(f"Select menu with custom_id '{args_select['custom_id']}' not found in the view !")
265
-
266
- ui.placeholder = args_select.get('placeholder', ui.placeholder)
267
- ui.min_values = args_select.get('min_values', ui.min_values)
268
- ui.max_values = args_select.get('max_values', ui.max_values)
269
- ui.disabled = args_select.get('disabled', ui.disabled)
270
-
271
- ui.options.clear()
272
- options = args_select.pop("options", [])
273
- for option in options:
274
- ui.add_option(**option)
275
-
276
- new_code = code if code is not None else view.get_callable_data(args_select['custom_id'])['code']
277
- view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code, 'interpreter': interpreter})
278
-
279
- return view
280
-
281
-
282
- async def ui_button_callback(button: Button, interaction: Interaction, data: dict[str, Any]):
283
- """
284
- Callback for UI buttons.
285
- Executes the code associated with the button.
286
- :param button:
287
- :param interaction:
288
- :param data:
289
- :return:
290
- """
291
- code = data.pop('code', None)
292
- interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
293
- if code is not None:
294
- local_env = {
295
- '__ret__': None,
296
- '__guild__': interaction.guild.name if interaction.guild else None,
297
- '__channel__': interaction.channel.name if interaction.channel else None,
298
- '__author__': interaction.user.id,
299
- '__author_name__': interaction.user.name,
300
- '__author_display_name__': interaction.user.display_name,
301
- '__author_avatar__': interaction.user.display_avatar.url if interaction.user.display_avatar else None,
302
- '__author_discriminator__': interaction.user.discriminator,
303
- '__author_bot__': interaction.user.bot,
304
- '__author_nick__': interaction.user.nick if hasattr(interaction.user, 'nick') else None,
305
- '__author_id__': interaction.user.id,
306
- '__message__': interaction.message.content if hasattr(interaction.message, 'content') else None,
307
- '__message_id__': interaction.message.id if hasattr(interaction.message, 'id') else None,
308
- '__channel_name__': interaction.channel.name if interaction.channel else None,
309
- '__channel_type__': interaction.channel.type.name if hasattr(interaction.channel, 'type') else None,
310
- '__channel_id__': interaction.channel.id if interaction.channel else None,
311
- '__private_channel__': isinstance(interaction.channel, PrivateChannel),
312
- }
313
- local_env.update(data)
314
- from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
315
- with new_scope(interpreter, local_env):
316
- await DshellInterpreteur(code, ctx=interaction, debug=False, vars_env=interpreter.env).execute()
317
- else:
318
- await interaction.response.defer(invisible=True)
319
-
320
- data.update({'code': code, 'interpreter': interpreter})
321
-
322
- async def ui_select_callback(select: Select, interaction: Interaction, data: dict[str, Any]):
323
- """
324
- Callback for UI select menus.
325
- Executes the code associated with the select menu.
326
- :param select:
327
- :param interaction:
328
- :param data:
329
- :return:
330
- """
331
- code = data.pop('code', None)
332
- interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
333
- if code is not None:
334
- local_env = {
335
- '__ret__': None,
336
- '__guild__': interaction.guild.name if interaction.guild else None,
337
- '__channel__': interaction.channel.name if interaction.channel else None,
338
- '__author__': interaction.user.id,
339
- '__author_name__': interaction.user.name,
340
- '__author_display_name__': interaction.user.display_name,
341
- '__author_avatar__': interaction.user.display_avatar.url if interaction.user.display_avatar else None,
342
- '__author_discriminator__': interaction.user.discriminator,
343
- '__author_bot__': interaction.user.bot,
344
- '__author_nick__': interaction.user.nick if hasattr(interaction.user, 'nick') else None,
345
- '__author_id__': interaction.user.id,
346
- '__message__': interaction.message.content if hasattr(interaction.message, 'content') else None,
347
- '__message_id__': interaction.message.id if hasattr(interaction.message, 'id') else None,
348
- '__channel_name__': interaction.channel.name if interaction.channel else None,
349
- '__channel_type__': interaction.channel.type.name if hasattr(interaction.channel, 'type') else None,
350
- '__channel_id__': interaction.channel.id if interaction.channel else None,
351
- '__private_channel__': isinstance(interaction.channel, PrivateChannel),
352
- '__values__': ListNode([i.id for i in select.values]) if select.values and hasattr(select.values[0], 'id') else ListNode(select.values)
353
- }
354
- local_env.update(data)
355
- from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
356
- with new_scope(interpreter, local_env):
357
- await DshellInterpreteur(code, ctx=interaction, debug=False, vars_env=interpreter.env).execute()
358
- else:
359
- await interaction.response.defer(invisible=True)
360
-
361
- data.update({'code': code, 'interpreter': interpreter})