dshellInterpreter 0.2.13__tar.gz → 0.2.13.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.

Potentially problematic release.


This version of dshellInterpreter might be problematic. Click here for more details.

Files changed (30) hide show
  1. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/dshell_message.py +11 -7
  2. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellInterpreteur/dshell_interpreter.py +60 -0
  3. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellParser/ast_nodes.py +83 -1
  4. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellParser/dshell_parser.py +30 -0
  5. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellTokenizer/dshell_keywords.py +1 -1
  6. {dshellinterpreter-0.2.13/dshellInterpreter.egg-info → dshellinterpreter-0.2.13.2}/PKG-INFO +2 -1
  7. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2/dshellInterpreter.egg-info}/PKG-INFO +2 -1
  8. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/dshellInterpreter.egg-info/requires.txt +1 -0
  9. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/setup.py +2 -2
  10. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
  11. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
  12. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
  13. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
  14. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
  15. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
  16. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
  17. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
  18. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellInterpreteur/__init__.py +0 -0
  19. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellParser/__init__.py +0 -0
  20. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellTokenizer/__init__.py +0 -0
  21. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellTokenizer/dshell_token_type.py +0 -0
  22. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_DshellTokenizer/dshell_tokenizer.py +0 -0
  23. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/__init__.py +0 -0
  24. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/Dshell/_utils.py +0 -0
  25. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/LICENSE +0 -0
  26. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/README.md +0 -0
  27. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
  28. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
  29. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/dshellInterpreter.egg-info/top_level.txt +0 -0
  30. {dshellinterpreter-0.2.13 → dshellinterpreter-0.2.13.2}/setup.cfg +0 -0
@@ -4,7 +4,10 @@ from discord import Embed, Message
4
4
  from discord.ext import commands
5
5
  from discord.abc import Messageable
6
6
 
7
+ from pycordViews import EasyModifiedViews
8
+
7
9
  from .utils.utils_message import utils_get_message
10
+ from .._utils import NoneType
8
11
 
9
12
  __all__ = [
10
13
  'dshell_send_message',
@@ -21,7 +24,7 @@ __all__ = [
21
24
  ]
22
25
 
23
26
 
24
- async def dshell_send_message(ctx: Message, message=None, delete=None, channel=None, embeds=None):
27
+ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=None, embeds=None, view=None) -> int:
25
28
  """
26
29
  Sends a message on Discord
27
30
  """
@@ -36,18 +39,19 @@ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=N
36
39
 
37
40
  from .._DshellParser.ast_nodes import ListNode
38
41
 
39
- if embeds is None:
40
- embeds = ListNode([])
42
+ if not isinstance(embeds, (ListNode, Embed, NoneType)):
43
+ raise Exception(f'Embeds must be a list of Embed objects or a single Embed object, not {type(embeds)} !')
41
44
 
42
- elif isinstance(embeds, Embed):
45
+ if isinstance(embeds, Embed):
43
46
  embeds = ListNode([embeds])
44
47
 
45
- else:
46
- raise Exception(f'Embeds must be a list of Embed objects or a single Embed object, not {type(embeds)} !')
48
+ if not isinstance(channel_to_send, (EasyModifiedViews, NoneType)):
49
+ raise Exception(f'Channel must be an UI or None, not {type(channel_to_send)} !')
47
50
 
48
51
  sended_message = await channel_to_send.send(message,
49
52
  delete_after=delete,
50
- embeds=embeds)
53
+ embeds=embeds,
54
+ view=view)
51
55
 
52
56
  return sended_message.id
53
57
 
@@ -1,9 +1,13 @@
1
1
  from asyncio import sleep
2
2
  from re import findall
3
3
  from typing import TypeVar, Union, Any, Optional, Callable
4
+ from random import choice
5
+ from string import ascii_letters, digits
4
6
  from copy import deepcopy
7
+ from pycordViews import SelectMenu, EasyModifiedViews
5
8
 
6
9
  from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role, Message
10
+ from discord.ui import Button
7
11
  from discord.abc import PrivateChannel
8
12
 
9
13
  from .._DshellParser.ast_nodes import *
@@ -120,6 +124,9 @@ class DshellInterpreteur:
120
124
  elif isinstance(first_node, PermissionNode):
121
125
  self.env[node.name.value] = build_permission(first_node.body, self)
122
126
 
127
+ elif isinstance(first_node, UiNode):
128
+ self.env[node.name.value] = build_ui(first_node, self)
129
+
123
130
  else:
124
131
  self.env[node.name.value] = eval_expression(node.body, self)
125
132
 
@@ -401,6 +408,59 @@ def build_colour(color: Union[int, ListNode]) -> Union[Colour, int]:
401
408
  raise TypeError(f"Color must be an integer or a ListNode, not {type(color)} !")
402
409
 
403
410
 
411
+ def build_ui(ui_node: UiNode, interpreter: DshellInterpreteur) -> EasyModifiedViews:
412
+ """
413
+ Builds a UI component from the UiNode.
414
+ Can accept buttons and select menus.
415
+ :param ui_node:
416
+ :param interpreter:
417
+ :return:
418
+ """
419
+ view = EasyModifiedViews()
420
+
421
+ for component in ui_node.buttons:
422
+ b = Button
423
+ args_button: dict[str, list[Any]] = regroupe_commandes(component.body, interpreter)[0]
424
+ args_button.pop('--*', ())
425
+ code = args_button.pop('code', None)
426
+ args = args_button.pop('*', ())
427
+ b(*args, **args_button)
428
+
429
+ custom_id = ''.join(choice(ascii_letters + digits) for _ in range(20))
430
+ b.custom_id = custom_id
431
+
432
+ view.add_items(b)
433
+ view.set_callable(custom_id, _callable=ui_button_callback, data={'code': code})
434
+
435
+ return view
436
+
437
+ async def ui_button_callback(button, interaction, data):
438
+ code = data.pop('code', None)
439
+ local_env = {}
440
+ if code is not None:
441
+ local_env = {
442
+ '__ret__': None,
443
+ '__guild__': interaction.guild.name if interaction.guild else None,
444
+ '__channel__': interaction.channel.name if interaction.channel else None,
445
+ '__author__': interaction.user.name,
446
+ '__author_display_name__': interaction.user.display_name,
447
+ '__author_avatar__': interaction.user.display_avatar.url if interaction.user.display_avatar else None,
448
+ '__author_discriminator__': interaction.user.discriminator,
449
+ '__author_bot__': interaction.user.bot,
450
+ '__author_nick__': interaction.user.nick if hasattr(interaction.user, 'nick') else None,
451
+ '__author_id__': interaction.user.id,
452
+ '__message__': interaction.message.content if hasattr(interaction.message, 'content') else None,
453
+ '__message_id__': interaction.message.id if hasattr(interaction.message, 'id') else None,
454
+ '__channel_name__': interaction.channel.name if interaction.channel else None,
455
+ '__channel_type__': interaction.channel.type.name if hasattr(interaction.channel, 'type') else None,
456
+ '__channel_id__': interaction.channel.id if interaction.channel else None,
457
+ '__private_channel__': isinstance(interaction.channel, PrivateChannel),
458
+ }
459
+ local_env.update(data)
460
+ x = DshellInterpreteur(code, interaction, debug=False)
461
+ x.env.update(local_env)
462
+ await x.execute()
463
+
404
464
  def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict[
405
465
  Union[Member, Role], PermissionOverwrite]:
406
466
  """
@@ -20,7 +20,10 @@ __all__ = [
20
20
  'IdentOperationNode',
21
21
  'ListNode',
22
22
  'PermissionNode',
23
- 'ParamNode'
23
+ 'ParamNode',
24
+ 'UiNode',
25
+ 'UiButtonNode',
26
+ 'UiSelectNode'
24
27
  ]
25
28
 
26
29
 
@@ -439,6 +442,85 @@ class ParamNode(ASTNode):
439
442
  }
440
443
 
441
444
 
445
+ class UiButtonNode(ASTNode):
446
+ """
447
+ Node representing a UI button component in the AST.
448
+ This is used to define button elements for commands in Dshell.
449
+ """
450
+
451
+ def __init__(self, body: list[Token]):
452
+ """
453
+ :param body: list of tokens representing the button component
454
+ """
455
+ self.body = body
456
+
457
+ def __repr__(self):
458
+ return f"<UI BUTTON> - {self.body}"
459
+
460
+ def to_dict(self):
461
+ """
462
+ Convert the UiButtonNode to a dictionary representation.
463
+ :return: Dictionary representation of the UiButtonNode.
464
+ """
465
+ return {
466
+ "type": "UiButtonNode",
467
+ "body": [token.to_dict() for token in self.body]
468
+ }
469
+
470
+ class UiSelectNode(ASTNode):
471
+ """
472
+ Node representing a UI select component in the AST.
473
+ This is used to define select elements for commands in Dshell.
474
+ """
475
+
476
+ def __init__(self, body: list[Token]):
477
+ """
478
+ :param body: list of tokens representing the select component
479
+ """
480
+ self.body = body
481
+
482
+ def __repr__(self):
483
+ return f"<UI SELECT> - {self.body}"
484
+
485
+ def to_dict(self):
486
+ """
487
+ Convert the UiSelectNode to a dictionary representation.
488
+ :return: Dictionary representation of the UiSelectNode.
489
+ """
490
+ return {
491
+ "type": "UiSelectNode",
492
+ "body": [token.to_dict() for token in self.body]
493
+ }
494
+
495
+ class UiNode(ASTNode):
496
+ """
497
+ Node representing a UI component in the AST.
498
+ This is used to define UI elements for commands in Dshell.
499
+ """
500
+
501
+ def __init__(self, body, buttons: Optional[list[UiButtonNode]] = None,
502
+ selects: Optional[list[UiSelectNode]] = None):
503
+ """
504
+ :param body: list of tokens representing the UI component
505
+ """
506
+ self.body = body
507
+ self.buttons = buttons or []
508
+ self.selects = selects or []
509
+
510
+ def __repr__(self):
511
+ return f"<UI> - {self.buttons}\n\n - {self.selects}"
512
+
513
+ def to_dict(self):
514
+ """
515
+ Convert the UiNode to a dictionary representation.
516
+ :return: Dictionary representation of the UiNode.
517
+ """
518
+ return {
519
+ "type": "UiNode",
520
+ "buttons": [token.to_dict() for token in self.buttons],
521
+ "selects": [token.to_dict() for token in self.selects],
522
+ }
523
+
442
524
  class ListNode(ASTNode):
443
525
  """
444
526
  Node representing a list structure in the AST.
@@ -24,6 +24,9 @@ from .ast_nodes import (ASTNode,
24
24
  FieldEmbedNode,
25
25
  PermissionNode,
26
26
  ParamNode,
27
+ UiNode,
28
+ UiButtonNode,
29
+ UiSelectNode,
27
30
  StartNode)
28
31
  from .._DshellTokenizer import dshell_operators
29
32
  from .._DshellTokenizer.dshell_token_type import DshellTokenType as DTT
@@ -185,6 +188,33 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
185
188
  blocks.pop()
186
189
  return blocks, pointeur
187
190
 
191
+ elif first_token_line.value == 'ui':
192
+ ui_node = UiNode([])
193
+ var_node = VarNode(tokens_by_line[1], body=[ui_node])
194
+ last_block.body.append(var_node)
195
+ _, p = parse(token_lines[pointeur + 1:], ui_node)
196
+ pointeur += p + 1
197
+
198
+ elif first_token_line.value == '#ui':
199
+ if not isinstance(last_block, UiNode):
200
+ raise SyntaxError(f'[#UI] No UI open on line {first_token_line.position} !')
201
+ blocks.pop()
202
+ return blocks, pointeur
203
+
204
+ elif first_token_line.value == 'button':
205
+ if not isinstance(last_block, UiNode):
206
+ raise SyntaxError(f'[BUTTON] No UI open on line {first_token_line.position} !')
207
+ button_node = UiButtonNode(tokens_by_line[1:])
208
+ last_block.body.append(button_node)
209
+ pointeur += 1
210
+
211
+ elif first_token_line.value == 'select':
212
+ if not isinstance(last_block, UiNode):
213
+ raise SyntaxError(f'[SELECT] No UI open on line {first_token_line.position} !')
214
+ select_node = UiSelectNode(tokens_by_line[1:])
215
+ last_block.body.append(select_node)
216
+ pointeur += 1
217
+
188
218
  ############################## AUTRE ##############################
189
219
 
190
220
  elif first_token_line.type == DTT.IDENT:
@@ -21,7 +21,7 @@ dshell_keyword: set[str] = {
21
21
  }
22
22
 
23
23
  dshell_discord_keyword: set[str] = {
24
- 'embed', '#embed', 'field', 'perm', 'permission', '#perm', '#permission'
24
+ 'embed', '#embed', 'field', 'perm', 'permission', '#perm', '#permission', 'ui', '#ui', 'button', 'select'
25
25
  }
26
26
  dshell_commands: dict[str, Callable] = {
27
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 0.2.13
3
+ Version: 0.2.13.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
@@ -17,6 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: py-cord==2.6.1
19
19
  Requires-Dist: requests
20
+ Requires-Dist: pycordviews
20
21
  Dynamic: author
21
22
  Dynamic: author-email
22
23
  Dynamic: classifier
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 0.2.13
3
+ Version: 0.2.13.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
@@ -17,6 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: py-cord==2.6.1
19
19
  Requires-Dist: requests
20
+ Requires-Dist: pycordviews
20
21
  Dynamic: author
21
22
  Dynamic: author-email
22
23
  Dynamic: classifier
@@ -1,2 +1,3 @@
1
1
  py-cord==2.6.1
2
2
  requests
3
+ pycordviews
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setup(
7
7
  name="dshellInterpreter",
8
- version="0.2.13",
8
+ version="0.2.13.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.",
@@ -18,7 +18,7 @@ setup(
18
18
  "Dshell._DshellParser",
19
19
  "Dshell.DISCORD_COMMANDS",
20
20
  "Dshell.DISCORD_COMMANDS.utils"],
21
- install_requires=["py-cord==2.6.1", "requests"],
21
+ install_requires=["py-cord==2.6.1", "requests", "pycordviews"],
22
22
  classifiers=[
23
23
  "Programming Language :: Python :: 3",
24
24
  "License :: OSI Approved :: MIT License",