dshellInterpreter 1.2.1.1__tar.gz → 1.2.1.2__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.
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_ui.py +82 -69
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_interpreter.py +12 -5
- dshellinterpreter-1.2.1.2/Dshell/DshellInterpreteur/dshell_scope.py +159 -0
- {dshellinterpreter-1.2.1.1/dshellInterpreter.egg-info → dshellinterpreter-1.2.1.2}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2/dshellInterpreter.egg-info}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/setup.py +1 -1
- dshellinterpreter-1.2.1.1/Dshell/DshellInterpreteur/dshell_scope.py +0 -81
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_embed.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_file.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_message.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_file.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_global.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_list.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_member.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_numbers.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_string.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_type_validation.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/cached_messages.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_arguments.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_global_variables.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/errors.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/utils_interpreter.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/ast_nodes.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/dshell_parser.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/errors.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellPreProcess/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellPreProcess/dshell_preprocess.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_keywords.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_token_type.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_tokenizer.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/__init__.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/full_import.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/regex_test.py +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/LICENSE +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/README.md +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/requires.txt +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/top_level.txt +0 -0
- {dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/setup.cfg +0 -0
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_ui.py
RENAMED
|
@@ -13,19 +13,24 @@ from ..DshellParser.ast_nodes import UiSelectNode, UiButtonNode, OptionUiSelectN
|
|
|
13
13
|
|
|
14
14
|
from ..DshellInterpreteur.utils_interpreter import regroupe_commandes
|
|
15
15
|
|
|
16
|
-
from ..DshellInterpreteur.dshell_scope import new_scope
|
|
16
|
+
from ..DshellInterpreteur.dshell_scope import new_scope, get_scope, update_nbr_usage_scope, get_usage_scope
|
|
17
17
|
|
|
18
|
-
from Dshell.full_import import Any, TYPE_CHECKING, Union
|
|
18
|
+
from Dshell.full_import import Any, TYPE_CHECKING, Union, Optional
|
|
19
19
|
|
|
20
20
|
from .utils.utils_type_validation import (_validate_optional_code_node,
|
|
21
|
+
_validate_required_int,
|
|
21
22
|
_validate_optional_int,
|
|
22
|
-
_validate_optional_string
|
|
23
|
+
_validate_optional_string,
|
|
24
|
+
_validate_required_string,
|
|
25
|
+
_validate_required_bool,
|
|
26
|
+
_validate_missing_or_type)
|
|
23
27
|
|
|
24
28
|
from .utils.utils_global import utils_refactor_emoji
|
|
25
29
|
|
|
26
30
|
if TYPE_CHECKING:
|
|
27
31
|
from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
|
|
28
32
|
|
|
33
|
+
scope_id = "scope_id"
|
|
29
34
|
|
|
30
35
|
ButtonStyleValues: set = {i.name for i in ButtonStyle}
|
|
31
36
|
SelectSyleValues: dict = {'string': ComponentType.string_select,
|
|
@@ -42,29 +47,26 @@ async def build_ui_button_parameters(ui_button_node: UiButtonNode, interpreter:
|
|
|
42
47
|
:param interpreter:
|
|
43
48
|
:return:
|
|
44
49
|
"""
|
|
50
|
+
_CMD = "button"
|
|
51
|
+
|
|
45
52
|
regrouped_parameters = await regroupe_commandes(ui_button_node.body, interpreter, normalise=True)
|
|
46
53
|
args_button: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
|
|
47
54
|
|
|
48
55
|
code = args_button.pop('code', None)
|
|
49
|
-
style = args_button.pop('style', 'primary').lower()
|
|
56
|
+
style = args_button.pop('style', StrNode('primary')).lower()
|
|
50
57
|
custom_id = args_button.pop('custom_id', StrNode('ui_button_'+str(random())))
|
|
51
58
|
row = args_button.pop('row', IntNode(0))
|
|
52
59
|
emoji = utils_refactor_emoji(args_button.pop('emoji', None))
|
|
53
60
|
|
|
54
|
-
_validate_optional_code_node(code, "
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
_validate_optional_code_node(code, "code", _CMD)
|
|
62
|
+
_validate_required_string(style, "style", _CMD)
|
|
63
|
+
_validate_required_string(custom_id, "custom_id", _CMD)
|
|
64
|
+
_validate_required_int(row, "row", _CMD)
|
|
65
|
+
_validate_optional_string(emoji, "emoji", _CMD)
|
|
58
66
|
|
|
59
67
|
if style not in ButtonStyleValues:
|
|
60
68
|
raise ValueError(f"Button style must be one of {', '.join(ButtonStyleValues)}, not '{style}' !")
|
|
61
69
|
|
|
62
|
-
if not isinstance(row, IntNode):
|
|
63
|
-
raise TypeError(f"Buttton row must be a int, not {type(row)} !")
|
|
64
|
-
|
|
65
|
-
if not isinstance(emoji, StrNode):
|
|
66
|
-
raise TypeError(f"Button emoji must be a str, not {type(emoji)} !")
|
|
67
|
-
|
|
68
70
|
args_button['custom_id'] = custom_id
|
|
69
71
|
args_button['row'] = row
|
|
70
72
|
args_button['style'] = ButtonStyle[style]
|
|
@@ -80,40 +82,32 @@ async def build_ui_select_parameters(ui_select_node: UiSelectNode, interpreter:
|
|
|
80
82
|
:param interpreter:
|
|
81
83
|
:return:
|
|
82
84
|
"""
|
|
85
|
+
_CMD = "select"
|
|
86
|
+
|
|
83
87
|
regrouped_parameters = await regroupe_commandes(ui_select_node.body, interpreter, normalise=True)
|
|
84
88
|
args_select: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
|
|
85
89
|
|
|
86
90
|
code = args_select.pop('code', None)
|
|
87
91
|
custom_id = args_select.pop('custom_id', StrNode('ui_select_'+str(random())))
|
|
88
|
-
select_type = args_select.pop('type', 'string').lower()
|
|
89
|
-
|
|
90
|
-
disabled = args_select.get('disabled',
|
|
91
|
-
max_values = args_select.get('max', 1)
|
|
92
|
-
min_values = args_select.get('min', 1)
|
|
93
|
-
placeholder = args_select.get('placeholder', "")
|
|
94
|
-
row = args_select.pop('row', 0)
|
|
95
|
-
|
|
96
|
-
_validate_optional_code_node(code, "Select code",
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if not isinstance(max_values, IntNode):
|
|
108
|
-
raise TypeError(f"Select max_values must be an int, not {type(max_values)} !")
|
|
109
|
-
|
|
110
|
-
if not isinstance(min_values, IntNode):
|
|
111
|
-
raise TypeError(f"Select min_values must be an int, not {type(min_values)} !")
|
|
112
|
-
|
|
113
|
-
if not isinstance(placeholder, StrNode):
|
|
114
|
-
raise TypeError(f"Select placeholder must be a string, not {type(placeholder)} !")
|
|
115
|
-
|
|
116
|
-
_validate_optional_int(row, "Select row", "build_ui_select")
|
|
92
|
+
select_type = args_select.pop('type', StrNode('string')).lower()
|
|
93
|
+
|
|
94
|
+
disabled = args_select.get('disabled', BoolNode(0))
|
|
95
|
+
max_values = args_select.get('max', IntNode(1))
|
|
96
|
+
min_values = args_select.get('min', IntNode(1))
|
|
97
|
+
placeholder = args_select.get('placeholder', StrNode(""))
|
|
98
|
+
row = args_select.pop('row', IntNode(0))
|
|
99
|
+
|
|
100
|
+
_validate_optional_code_node(code, "Select code", _CMD)
|
|
101
|
+
_validate_required_string(custom_id, "custom_id", _CMD)
|
|
102
|
+
_validate_required_string(select_type, "type", _CMD)
|
|
103
|
+
_validate_required_bool(disabled, "disabled", _CMD)
|
|
104
|
+
_validate_required_int(max_values, "max", _CMD)
|
|
105
|
+
_validate_required_int(max_values, "min", _CMD)
|
|
106
|
+
_validate_required_string(placeholder, "placeholder", _CMD)
|
|
107
|
+
_validate_optional_int(row, "row", _CMD)
|
|
108
|
+
|
|
109
|
+
if select_type not in SelectSyleValues:
|
|
110
|
+
raise TypeError(f"Select style must be one of {', '.join(SelectSyleValues.keys())}, not '{select_type}' !")
|
|
117
111
|
|
|
118
112
|
args_select["disabled"] = disabled
|
|
119
113
|
args_select["max_values"] = max_values
|
|
@@ -134,6 +128,8 @@ async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interp
|
|
|
134
128
|
:param interpreter:
|
|
135
129
|
:return:
|
|
136
130
|
"""
|
|
131
|
+
_CMD = "option"
|
|
132
|
+
|
|
137
133
|
option_results: list[dict[str, Any]] = []
|
|
138
134
|
|
|
139
135
|
for option_node in option_nodes:
|
|
@@ -146,28 +142,21 @@ async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interp
|
|
|
146
142
|
emoji = utils_refactor_emoji(args_option.pop('emoji', None))
|
|
147
143
|
default = args_option.pop('default', False)
|
|
148
144
|
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
_validate_required_string(label, "label", _CMD)
|
|
146
|
+
_validate_missing_or_type(value, "value", StrNode, _CMD)
|
|
147
|
+
_validate_optional_string(description, "description", _CMD)
|
|
148
|
+
_validate_optional_string(emoji, "emoji", _CMD)
|
|
149
|
+
_validate_required_bool(default, "default", _CMD)
|
|
151
150
|
|
|
152
151
|
if len(label) > 100:
|
|
153
152
|
raise ValueError("Option label must be less than 100 characters !")
|
|
154
153
|
|
|
155
|
-
if value and not isinstance(value, str):
|
|
156
|
-
raise TypeError(f"Option value must be a string, not {type(value)} !")
|
|
157
|
-
|
|
158
154
|
if value and len(value) > 100:
|
|
159
155
|
raise ValueError("Option value must be less than 100 characters !")
|
|
160
156
|
|
|
161
|
-
_validate_optional_string(description, "Option description", "build_ui_option")
|
|
162
|
-
|
|
163
157
|
if description is not None and len(description) > 100:
|
|
164
158
|
raise ValueError("Option description must be less than 100 characters !")
|
|
165
159
|
|
|
166
|
-
_validate_optional_string(emoji, "Option emoji", "build_ui_option")
|
|
167
|
-
|
|
168
|
-
if not isinstance(default, bool):
|
|
169
|
-
raise TypeError(f"Option default must be a bool, not {type(default)} !")
|
|
170
|
-
|
|
171
160
|
option_dict = {
|
|
172
161
|
'label': label,
|
|
173
162
|
'value': value,
|
|
@@ -194,7 +183,7 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
|
|
|
194
183
|
async for _, args_button, code in build_ui_button_parameters(ui_node, interpreter):
|
|
195
184
|
b = ui.Button(**args_button)
|
|
196
185
|
view.add_items(b)
|
|
197
|
-
view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code,
|
|
186
|
+
view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
198
187
|
|
|
199
188
|
elif isinstance(ui_node, UiSelectNode):
|
|
200
189
|
s = SelectMenu()
|
|
@@ -209,23 +198,23 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
|
|
|
209
198
|
for option in options:
|
|
210
199
|
menu.add_option(**option)
|
|
211
200
|
|
|
212
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
201
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
213
202
|
|
|
214
203
|
elif select_type == ComponentType.role_select:
|
|
215
204
|
s.add_role_select_menu(**args_select)
|
|
216
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
205
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
217
206
|
|
|
218
207
|
elif select_type == ComponentType.user_select:
|
|
219
208
|
s.add_user_select_menu(**args_select)
|
|
220
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
209
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
221
210
|
|
|
222
211
|
elif select_type == ComponentType.mentionable_select:
|
|
223
212
|
s.add_mentionable_select_menu(**args_select)
|
|
224
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
213
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
225
214
|
|
|
226
215
|
elif select_type == ComponentType.channel_select:
|
|
227
216
|
s.add_channel_select_menu(**args_select)
|
|
228
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
217
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
|
|
229
218
|
|
|
230
219
|
view.add_items(s)
|
|
231
220
|
|
|
@@ -258,7 +247,7 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
|
|
|
258
247
|
ui.url = args_button.get('url', ui.url)
|
|
259
248
|
ui.row = args_button.get('row', ui.row)
|
|
260
249
|
new_code = code if code is not None else view.get_callable_data(args_button['custom_id'])['code']
|
|
261
|
-
view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code,
|
|
250
|
+
view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code, scope_id: interpreter.scope_id})
|
|
262
251
|
|
|
263
252
|
elif isinstance(ui_node, UiSelectNode):
|
|
264
253
|
|
|
@@ -279,7 +268,7 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
|
|
|
279
268
|
ui.add_option(**option)
|
|
280
269
|
|
|
281
270
|
new_code = code if code is not None else view.get_callable_data(args_select['custom_id'])['code']
|
|
282
|
-
view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code,
|
|
271
|
+
view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code, scope_id: interpreter.scope_id})
|
|
283
272
|
|
|
284
273
|
return view
|
|
285
274
|
|
|
@@ -294,7 +283,8 @@ async def ui_button_callback(button: ui.Button, interaction: Interaction, data:
|
|
|
294
283
|
:return:
|
|
295
284
|
"""
|
|
296
285
|
code = data.get('code', None)
|
|
297
|
-
|
|
286
|
+
scope: Optional[str] = data.get(scope_id, None)
|
|
287
|
+
|
|
298
288
|
if code is not None:
|
|
299
289
|
message = interaction
|
|
300
290
|
local_env = {
|
|
@@ -382,13 +372,23 @@ async def ui_button_callback(button: ui.Button, interaction: Interaction, data:
|
|
|
382
372
|
}
|
|
383
373
|
)
|
|
384
374
|
|
|
385
|
-
#local_env.update(data)
|
|
386
375
|
from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
|
|
387
376
|
|
|
388
|
-
new_interpreter = DshellInterpreteur(
|
|
377
|
+
new_interpreter = DshellInterpreteur(
|
|
378
|
+
code,
|
|
379
|
+
ctx=interaction,
|
|
380
|
+
debug=False,
|
|
381
|
+
vars_env=get_scope(scope))
|
|
382
|
+
|
|
383
|
+
if scope is not None:
|
|
384
|
+
update_nbr_usage_scope(scope, 1)
|
|
385
|
+
|
|
389
386
|
with new_scope(new_interpreter, local_env):
|
|
390
387
|
await new_interpreter.execute()
|
|
391
388
|
|
|
389
|
+
if scope is not None:
|
|
390
|
+
update_nbr_usage_scope(scope, -1)
|
|
391
|
+
|
|
392
392
|
else:
|
|
393
393
|
await interaction.response.defer(invisible=True)
|
|
394
394
|
|
|
@@ -403,7 +403,7 @@ async def ui_select_callback(select: ui.Select, interaction: Interaction, data:
|
|
|
403
403
|
:return:
|
|
404
404
|
"""
|
|
405
405
|
code = data.get('code', None)
|
|
406
|
-
|
|
406
|
+
scope: Optional[str] = data.get(scope_id, None)
|
|
407
407
|
|
|
408
408
|
message = interaction
|
|
409
409
|
if code is not None:
|
|
@@ -518,7 +518,20 @@ async def ui_select_callback(select: ui.Select, interaction: Interaction, data:
|
|
|
518
518
|
|
|
519
519
|
local_env.update(data)
|
|
520
520
|
from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
|
|
521
|
-
|
|
522
|
-
|
|
521
|
+
new_interpreter = DshellInterpreteur(
|
|
522
|
+
code,
|
|
523
|
+
ctx=interaction,
|
|
524
|
+
debug=False,
|
|
525
|
+
vars_env=get_scope(scope))
|
|
526
|
+
|
|
527
|
+
if scope is not None:
|
|
528
|
+
update_nbr_usage_scope(scope, 1)
|
|
529
|
+
|
|
530
|
+
with new_scope(new_interpreter, local_env):
|
|
531
|
+
await new_interpreter.execute()
|
|
532
|
+
|
|
533
|
+
if scope is not None:
|
|
534
|
+
update_nbr_usage_scope(scope, -1)
|
|
535
|
+
|
|
523
536
|
else:
|
|
524
537
|
await interaction.response.defer(invisible=True)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from ..DshellTokenizer.dshell_token_type import Token
|
|
2
2
|
from ..DshellTokenizer.dshell_token_type import DshellTokenType as DTT
|
|
3
|
-
from ..
|
|
4
|
-
from Dshell.full_import import TypeVar, Union, Optional, Any, Callable, sleep, findall
|
|
3
|
+
from ..full_import import TypeVar, Union, Optional, Any, Callable, sleep, findall
|
|
5
4
|
from ..DshellParser.ast_nodes import *
|
|
6
|
-
from
|
|
5
|
+
from ..full_import import AutoShardedBot, Interaction, Message, PrivateChannel, random
|
|
7
6
|
from ..DshellParser.dshell_parser import parse, print_ast
|
|
8
7
|
from ..DshellTokenizer.dshell_tokenizer import DshellTokenizer
|
|
9
8
|
from .cached_messages import dshell_cached_messages
|
|
@@ -12,7 +11,7 @@ from .utils_interpreter import get_params, eval_expression, eval_expression_inli
|
|
|
12
11
|
from ..DISCORD_COMMANDS.dshell_embed import build_embed, rebuild_embed
|
|
13
12
|
from ..DISCORD_COMMANDS.dshell_ui import build_ui
|
|
14
13
|
from ..DISCORD_COMMANDS.utils.utils_permissions import build_permission
|
|
15
|
-
from .dshell_scope import Scope, new_scope
|
|
14
|
+
from .dshell_scope import Scope, new_scope, get_scope, create_scope, update_nbr_usage_scope, get_usage_scope
|
|
16
15
|
from .dshell_global_variables import MAX_SLEEP_TIME_SECONDS, MIN_SLEEP_TIME_SECONDS
|
|
17
16
|
|
|
18
17
|
|
|
@@ -48,7 +47,14 @@ class DshellInterpreteur:
|
|
|
48
47
|
self.ast: list[ASTNode] = code.body
|
|
49
48
|
|
|
50
49
|
message = ctx.message if isinstance(ctx, Interaction) else ctx
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
# scope creation
|
|
52
|
+
self.scope_id: str = create_scope()
|
|
53
|
+
self.env: Optional[Scope] = get_scope(self.scope_id)
|
|
54
|
+
|
|
55
|
+
if self.env is None:
|
|
56
|
+
raise Exception(f"Scope {self.scope_id} not found in interpreter creation !")
|
|
57
|
+
|
|
52
58
|
self.env.update({
|
|
53
59
|
'__ret__': None, # environment variables, '__ret__' is used to store the return value of commands
|
|
54
60
|
'__loop__': None, # used to store the current loop variable in loop nodes if the loop identifier is not specified
|
|
@@ -329,6 +335,7 @@ class DshellInterpreteur:
|
|
|
329
335
|
"""
|
|
330
336
|
self.env.clear()
|
|
331
337
|
self.ast.clear()
|
|
338
|
+
update_nbr_usage_scope(self.scope_id, -1)
|
|
332
339
|
|
|
333
340
|
|
|
334
341
|
async def call_function(function: Callable, args: ArgsCommandNode, interpreter: DshellInterpreteur):
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from typing import Any, Optional, Dict, Set, Union
|
|
3
|
+
from random import random
|
|
4
|
+
|
|
5
|
+
# manage all scope with one unique ID by scope to separate the interpreter and scopes
|
|
6
|
+
context_scope: dict[str, tuple[int, "Scope"]] = {}
|
|
7
|
+
|
|
8
|
+
def generate_scope_id() -> str:
|
|
9
|
+
"""
|
|
10
|
+
generate a new scope code unused
|
|
11
|
+
:return:
|
|
12
|
+
"""
|
|
13
|
+
while (_id := (str(random()) + str(random()))) in context_scope: pass
|
|
14
|
+
return _id
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_scope(_id: str) -> Union["Scope", None]:
|
|
18
|
+
"""
|
|
19
|
+
Get the current scope linked with an ID
|
|
20
|
+
:param _id:
|
|
21
|
+
:return: the scope link with the id, or None if the scope id is not found
|
|
22
|
+
"""
|
|
23
|
+
x = context_scope.get(_id, None)
|
|
24
|
+
return x[1] if x is not None else x
|
|
25
|
+
|
|
26
|
+
def get_usage_scope(_id: str) -> Union[int, None]:
|
|
27
|
+
"""
|
|
28
|
+
Get the usage number for a scope
|
|
29
|
+
:param _id: An integer, or None if the scope id is not found
|
|
30
|
+
:return:
|
|
31
|
+
"""
|
|
32
|
+
x = context_scope.get(_id, None)
|
|
33
|
+
return x[0] if x is not None else x
|
|
34
|
+
|
|
35
|
+
class Scope:
|
|
36
|
+
"""
|
|
37
|
+
Represents a variable scope with optional parent scope for nested scoping.
|
|
38
|
+
"""
|
|
39
|
+
def __init__(self, parent: Optional[str] = None):
|
|
40
|
+
self.parent: Optional[str] = parent
|
|
41
|
+
self.vars: Dict[str, Any] = {}
|
|
42
|
+
|
|
43
|
+
def get(self, name: str) -> Any:
|
|
44
|
+
"""
|
|
45
|
+
Get a variable value from this scope or parent scopes.
|
|
46
|
+
:param name: Variable name
|
|
47
|
+
:return: Variable value
|
|
48
|
+
:raises KeyError: If variable not found in any scope
|
|
49
|
+
"""
|
|
50
|
+
if name in self.vars:
|
|
51
|
+
return self.vars[name]
|
|
52
|
+
if self.parent:
|
|
53
|
+
if self.parent in context_scope:
|
|
54
|
+
return context_scope[self.parent][1].get(name)
|
|
55
|
+
raise Exception(f"Scope {self.parent} not found [get] !")
|
|
56
|
+
raise KeyError(name)
|
|
57
|
+
|
|
58
|
+
def set(self, name: str, value: Any) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Set a variable in this scope.
|
|
61
|
+
:param name: Variable name
|
|
62
|
+
:param value: Variable value
|
|
63
|
+
"""
|
|
64
|
+
self.vars[name] = value
|
|
65
|
+
|
|
66
|
+
def update(self, mapping: Dict[str, Any]) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Update multiple variables in this scope.
|
|
69
|
+
:param mapping: Dictionary of variable names and values
|
|
70
|
+
"""
|
|
71
|
+
self.vars.update(mapping)
|
|
72
|
+
|
|
73
|
+
def contains(self, name: str) -> bool:
|
|
74
|
+
"""
|
|
75
|
+
Check if a variable exists in this scope or parent scopes.
|
|
76
|
+
:param name: Variable name
|
|
77
|
+
:return: True if variable exists, False otherwise
|
|
78
|
+
"""
|
|
79
|
+
if name in self.vars:
|
|
80
|
+
return True
|
|
81
|
+
if self.parent:
|
|
82
|
+
if self.parent in context_scope:
|
|
83
|
+
return context_scope[self.parent][1].contains(name)
|
|
84
|
+
Exception(f"Scope {self.parent} not found [contains] !")
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
def keys(self) -> Set[str]:
|
|
88
|
+
"""
|
|
89
|
+
Get all variable names from this scope and parent scopes.
|
|
90
|
+
:return: Set of variable names
|
|
91
|
+
"""
|
|
92
|
+
keys = set(self.vars.keys())
|
|
93
|
+
if self.parent:
|
|
94
|
+
if self.parent in context_scope:
|
|
95
|
+
keys.update(context_scope[self.parent][1].keys())
|
|
96
|
+
else:
|
|
97
|
+
Exception(f"Scope {self.parent} not found [keys] !")
|
|
98
|
+
return keys
|
|
99
|
+
|
|
100
|
+
def clear(self) -> None:
|
|
101
|
+
"""Clear all variables in this scope (does not affect parent)."""
|
|
102
|
+
self.vars.clear()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def create_scope() -> str:
|
|
106
|
+
"""
|
|
107
|
+
Create a new scope and return the scope code
|
|
108
|
+
:return:
|
|
109
|
+
"""
|
|
110
|
+
_id = generate_scope_id()
|
|
111
|
+
scope = Scope()
|
|
112
|
+
context_scope[_id] = (1, scope)
|
|
113
|
+
return _id
|
|
114
|
+
|
|
115
|
+
def update_nbr_usage_scope(scope_id: str, nbr_usage: int):
|
|
116
|
+
"""
|
|
117
|
+
Update the usage number for a scope
|
|
118
|
+
:param nbr_usage:
|
|
119
|
+
:return:
|
|
120
|
+
"""
|
|
121
|
+
if scope_id not in context_scope:
|
|
122
|
+
raise Exception(f"Scope {scope_id} not found [update nbr usage scope] !")
|
|
123
|
+
|
|
124
|
+
new_usage = get_usage_scope(scope_id)+nbr_usage
|
|
125
|
+
|
|
126
|
+
if new_usage <= 0:
|
|
127
|
+
del context_scope[scope_id]
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
new = (new_usage, context_scope[scope_id][1])
|
|
131
|
+
|
|
132
|
+
del context_scope[scope_id]
|
|
133
|
+
context_scope[scope_id] = new
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@contextmanager
|
|
137
|
+
def new_scope(interpreter, initial_vars: Optional[Dict[str, Any]] = None):
|
|
138
|
+
"""
|
|
139
|
+
Context manager for creating a new scope temporarily.
|
|
140
|
+
:param interpreter: The interpreter instance
|
|
141
|
+
:param initial_vars: Optional initial variables for the new scope
|
|
142
|
+
"""
|
|
143
|
+
parent = interpreter.scope_id
|
|
144
|
+
|
|
145
|
+
new_scope_id: str = generate_scope_id()
|
|
146
|
+
context_scope[new_scope_id] = (1, Scope(parent))
|
|
147
|
+
|
|
148
|
+
interpreter.scope_id = new_scope_id
|
|
149
|
+
interpreter.env = get_scope(new_scope_id)
|
|
150
|
+
|
|
151
|
+
if initial_vars:
|
|
152
|
+
interpreter.env.update(initial_vars)
|
|
153
|
+
try:
|
|
154
|
+
yield
|
|
155
|
+
finally:
|
|
156
|
+
interpreter.clear()
|
|
157
|
+
interpreter.env = get_scope(parent)
|
|
158
|
+
interpreter.scope_id = parent
|
|
159
|
+
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="dshellInterpreter",
|
|
8
|
-
version="1.2.1.
|
|
8
|
+
version="1.2.1.2",
|
|
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,81 +0,0 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
from typing import Any, Optional, Dict, Set
|
|
3
|
-
|
|
4
|
-
class Scope:
|
|
5
|
-
"""
|
|
6
|
-
Represents a variable scope with optional parent scope for nested scoping.
|
|
7
|
-
"""
|
|
8
|
-
def __init__(self, parent: Optional['Scope'] = None):
|
|
9
|
-
self.parent: Optional['Scope'] = parent
|
|
10
|
-
self.vars: Dict[str, Any] = {}
|
|
11
|
-
|
|
12
|
-
def get(self, name: str) -> Any:
|
|
13
|
-
"""
|
|
14
|
-
Get a variable value from this scope or parent scopes.
|
|
15
|
-
:param name: Variable name
|
|
16
|
-
:return: Variable value
|
|
17
|
-
:raises KeyError: If variable not found in any scope
|
|
18
|
-
"""
|
|
19
|
-
if name in self.vars:
|
|
20
|
-
return self.vars[name]
|
|
21
|
-
if self.parent:
|
|
22
|
-
return self.parent.get(name)
|
|
23
|
-
raise KeyError(name)
|
|
24
|
-
|
|
25
|
-
def set(self, name: str, value: Any) -> None:
|
|
26
|
-
"""
|
|
27
|
-
Set a variable in this scope.
|
|
28
|
-
:param name: Variable name
|
|
29
|
-
:param value: Variable value
|
|
30
|
-
"""
|
|
31
|
-
self.vars[name] = value
|
|
32
|
-
|
|
33
|
-
def update(self, mapping: Dict[str, Any]) -> None:
|
|
34
|
-
"""
|
|
35
|
-
Update multiple variables in this scope.
|
|
36
|
-
:param mapping: Dictionary of variable names and values
|
|
37
|
-
"""
|
|
38
|
-
self.vars.update(mapping)
|
|
39
|
-
|
|
40
|
-
def contains(self, name: str) -> bool:
|
|
41
|
-
"""
|
|
42
|
-
Check if a variable exists in this scope or parent scopes.
|
|
43
|
-
:param name: Variable name
|
|
44
|
-
:return: True if variable exists, False otherwise
|
|
45
|
-
"""
|
|
46
|
-
if name in self.vars:
|
|
47
|
-
return True
|
|
48
|
-
if self.parent:
|
|
49
|
-
return self.parent.contains(name)
|
|
50
|
-
return False
|
|
51
|
-
|
|
52
|
-
def keys(self) -> Set[str]:
|
|
53
|
-
"""
|
|
54
|
-
Get all variable names from this scope and parent scopes.
|
|
55
|
-
:return: Set of variable names
|
|
56
|
-
"""
|
|
57
|
-
keys = set(self.vars.keys())
|
|
58
|
-
if self.parent:
|
|
59
|
-
keys.update(self.parent.keys())
|
|
60
|
-
return keys
|
|
61
|
-
|
|
62
|
-
def clear(self) -> None:
|
|
63
|
-
"""Clear all variables in this scope (does not affect parent)."""
|
|
64
|
-
self.vars.clear()
|
|
65
|
-
|
|
66
|
-
@contextmanager
|
|
67
|
-
def new_scope(interpreter, initial_vars: Optional[Dict[str, Any]] = None):
|
|
68
|
-
"""
|
|
69
|
-
Context manager for creating a new scope temporarily.
|
|
70
|
-
:param interpreter: The interpreter instance
|
|
71
|
-
:param initial_vars: Optional initial variables for the new scope
|
|
72
|
-
"""
|
|
73
|
-
parent = interpreter.env
|
|
74
|
-
interpreter.env = Scope(parent)
|
|
75
|
-
if initial_vars:
|
|
76
|
-
interpreter.env.update(initial_vars)
|
|
77
|
-
try:
|
|
78
|
-
yield
|
|
79
|
-
finally:
|
|
80
|
-
interpreter.env.clear()
|
|
81
|
-
interpreter.env = parent
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_channel.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_embed.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_member.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_message.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_role.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_list.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/cached_messages.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/dshell_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellPreProcess/dshell_preprocess.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_keywords.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_token_type.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/requires.txt
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.1.1 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|