dshellInterpreter 1.2.1.0__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.
Files changed (54) hide show
  1. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_ui.py +91 -73
  2. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_interpreter.py +12 -5
  3. dshellinterpreter-1.2.1.2/Dshell/DshellInterpreteur/dshell_scope.py +159 -0
  4. {dshellinterpreter-1.2.1.0/dshellInterpreter.egg-info → dshellinterpreter-1.2.1.2}/PKG-INFO +1 -1
  5. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2/dshellInterpreter.egg-info}/PKG-INFO +1 -1
  6. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/setup.py +1 -1
  7. dshellinterpreter-1.2.1.0/Dshell/DshellInterpreteur/dshell_scope.py +0 -81
  8. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
  9. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
  10. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_embed.py +0 -0
  11. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_file.py +0 -0
  12. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +0 -0
  13. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
  14. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_message.py +0 -0
  15. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
  16. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
  17. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
  18. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py +0 -0
  19. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_file.py +0 -0
  20. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_global.py +0 -0
  21. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_list.py +0 -0
  22. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_member.py +0 -0
  23. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
  24. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_numbers.py +0 -0
  25. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +0 -0
  26. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_string.py +0 -0
  27. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
  28. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DISCORD_COMMANDS/utils/utils_type_validation.py +0 -0
  29. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/__init__.py +0 -0
  30. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/cached_messages.py +0 -0
  31. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_arguments.py +0 -0
  32. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/dshell_global_variables.py +0 -0
  33. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/errors.py +0 -0
  34. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellInterpreteur/utils_interpreter.py +0 -0
  35. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/__init__.py +0 -0
  36. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/ast_nodes.py +0 -0
  37. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/dshell_parser.py +0 -0
  38. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellParser/errors.py +0 -0
  39. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellPreProcess/__init__.py +0 -0
  40. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellPreProcess/dshell_preprocess.py +0 -0
  41. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/__init__.py +0 -0
  42. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_keywords.py +0 -0
  43. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_token_type.py +0 -0
  44. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/DshellTokenizer/dshell_tokenizer.py +0 -0
  45. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/__init__.py +0 -0
  46. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/full_import.py +0 -0
  47. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/Dshell/regex_test.py +0 -0
  48. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/LICENSE +0 -0
  49. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/README.md +0 -0
  50. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
  51. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
  52. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/requires.txt +0 -0
  53. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/dshellInterpreter.egg-info/top_level.txt +0 -0
  54. {dshellinterpreter-1.2.1.0 → dshellinterpreter-1.2.1.2}/setup.cfg +0 -0
@@ -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,19 +47,22 @@ 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()
50
- custom_id = args_button.pop('custom_id', 'ui_button_'+str(random()))
51
- row = args_button.pop('row', 0)
56
+ style = args_button.pop('style', StrNode('primary')).lower()
57
+ custom_id = args_button.pop('custom_id', StrNode('ui_button_'+str(random())))
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, "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)} !")
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}' !")
@@ -74,40 +82,32 @@ async def build_ui_select_parameters(ui_select_node: UiSelectNode, interpreter:
74
82
  :param interpreter:
75
83
  :return:
76
84
  """
85
+ _CMD = "select"
86
+
77
87
  regrouped_parameters = await regroupe_commandes(ui_select_node.body, interpreter, normalise=True)
78
88
  args_select: dict[str, list[Any]] = regrouped_parameters.get_dict_parameters()
79
89
 
80
90
  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")
91
+ custom_id = args_select.pop('custom_id', StrNode('ui_select_'+str(random())))
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}' !")
111
111
 
112
112
  args_select["disabled"] = disabled
113
113
  args_select["max_values"] = max_values
@@ -128,6 +128,8 @@ async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interp
128
128
  :param interpreter:
129
129
  :return:
130
130
  """
131
+ _CMD = "option"
132
+
131
133
  option_results: list[dict[str, Any]] = []
132
134
 
133
135
  for option_node in option_nodes:
@@ -140,28 +142,21 @@ async def build_ui_select_options(option_nodes: list[OptionUiSelectNode], interp
140
142
  emoji = utils_refactor_emoji(args_option.pop('emoji', None))
141
143
  default = args_option.pop('default', False)
142
144
 
143
- if label is None or not isinstance(label, str):
144
- raise TypeError(f"Option label must be a string, not {type(label)} !")
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)
145
150
 
146
151
  if len(label) > 100:
147
152
  raise ValueError("Option label must be less than 100 characters !")
148
153
 
149
- if value and not isinstance(value, str):
150
- raise TypeError(f"Option value must be a string, not {type(value)} !")
151
-
152
154
  if value and len(value) > 100:
153
155
  raise ValueError("Option value must be less than 100 characters !")
154
156
 
155
- _validate_optional_string(description, "Option description", "build_ui_option")
156
-
157
157
  if description is not None and len(description) > 100:
158
158
  raise ValueError("Option description must be less than 100 characters !")
159
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
160
  option_dict = {
166
161
  'label': label,
167
162
  'value': value,
@@ -186,10 +181,9 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
186
181
 
187
182
  if isinstance(ui_node, UiButtonNode):
188
183
  async for _, args_button, code in build_ui_button_parameters(ui_node, interpreter):
189
- print(args_button)
190
184
  b = ui.Button(**args_button)
191
185
  view.add_items(b)
192
- view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, 'interpreter': interpreter})
186
+ view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, scope_id: interpreter.scope_id})
193
187
 
194
188
  elif isinstance(ui_node, UiSelectNode):
195
189
  s = SelectMenu()
@@ -204,23 +198,23 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
204
198
  for option in options:
205
199
  menu.add_option(**option)
206
200
 
207
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
201
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
208
202
 
209
203
  elif select_type == ComponentType.role_select:
210
204
  s.add_role_select_menu(**args_select)
211
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
205
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
212
206
 
213
207
  elif select_type == ComponentType.user_select:
214
208
  s.add_user_select_menu(**args_select)
215
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
209
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
216
210
 
217
211
  elif select_type == ComponentType.mentionable_select:
218
212
  s.add_mentionable_select_menu(**args_select)
219
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
213
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
220
214
 
221
215
  elif select_type == ComponentType.channel_select:
222
216
  s.add_channel_select_menu(**args_select)
223
- s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, 'interpreter': interpreter})
217
+ s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, scope_id: interpreter.scope_id})
224
218
 
225
219
  view.add_items(s)
226
220
 
@@ -253,7 +247,7 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
253
247
  ui.url = args_button.get('url', ui.url)
254
248
  ui.row = args_button.get('row', ui.row)
255
249
  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})
250
+ view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code, scope_id: interpreter.scope_id})
257
251
 
258
252
  elif isinstance(ui_node, UiSelectNode):
259
253
 
@@ -274,7 +268,7 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
274
268
  ui.add_option(**option)
275
269
 
276
270
  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})
271
+ view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code, scope_id: interpreter.scope_id})
278
272
 
279
273
  return view
280
274
 
@@ -288,8 +282,9 @@ async def ui_button_callback(button: ui.Button, interaction: Interaction, data:
288
282
  :param data:
289
283
  :return:
290
284
  """
291
- code = data.pop('code', None)
292
- interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
285
+ code = data.get('code', None)
286
+ scope: Optional[str] = data.get(scope_id, None)
287
+
293
288
  if code is not None:
294
289
  message = interaction
295
290
  local_env = {
@@ -377,14 +372,26 @@ async def ui_button_callback(button: ui.Button, interaction: Interaction, data:
377
372
  }
378
373
  )
379
374
 
380
- local_env.update(data)
381
375
  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()
376
+
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
+
386
+ with new_scope(new_interpreter, local_env):
387
+ await new_interpreter.execute()
388
+
389
+ if scope is not None:
390
+ update_nbr_usage_scope(scope, -1)
391
+
384
392
  else:
385
393
  await interaction.response.defer(invisible=True)
386
394
 
387
- data.update({'code': code, 'interpreter': interpreter})
388
395
 
389
396
  async def ui_select_callback(select: ui.Select, interaction: Interaction, data: dict[str, Any]):
390
397
  """
@@ -395,8 +402,8 @@ async def ui_select_callback(select: ui.Select, interaction: Interaction, data:
395
402
  :param data:
396
403
  :return:
397
404
  """
398
- code = data.pop('code', None)
399
- interpreter: "DshellInterpreteur" = data.pop('interpreter', None)
405
+ code = data.get('code', None)
406
+ scope: Optional[str] = data.get(scope_id, None)
400
407
 
401
408
  message = interaction
402
409
  if code is not None:
@@ -511,9 +518,20 @@ async def ui_select_callback(select: ui.Select, interaction: Interaction, data:
511
518
 
512
519
  local_env.update(data)
513
520
  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()
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
+
516
536
  else:
517
537
  await interaction.response.defer(invisible=True)
518
-
519
- data.update({'code': code, 'interpreter': interpreter})
@@ -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 ..DshellInterpreteur.errors import DshellInterpreterStopExecution, DshellInterpreterError
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 Dshell.full_import import AutoShardedBot, Interaction, Message, PrivateChannel
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
- self.env: Scope = Scope()
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
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 1.2.1.0
3
+ Version: 1.2.1.2
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.1.0
3
+ Version: 1.2.1.2
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.1.0",
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