dshellInterpreter 0.1.10__py3-none-any.whl → 0.1.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

@@ -1,2 +1,3 @@
1
1
  from .dshell_channel import *
2
2
  from .dshell_message import *
3
+ from .dshell_member import *
@@ -2,24 +2,29 @@ from asyncio import sleep
2
2
  from re import search
3
3
  from typing import Union
4
4
 
5
- from discord import MISSING, PermissionOverwrite, Member, Role
6
- from discord.abc import GuildChannel
5
+ from discord import MISSING, PermissionOverwrite, Member, Role, Message
7
6
 
8
7
  __all__ = [
9
8
  'dshell_create_text_channel',
10
9
  'dshell_delete_channel',
11
- 'dshell_delete_channels'
10
+ 'dshell_delete_channels',
11
+ 'dshell_create_voice_channel'
12
12
  ]
13
13
 
14
14
 
15
- async def dshell_create_text_channel(ctx: GuildChannel, name, category=None, position=MISSING, slowmode=MISSING,
15
+ async def dshell_create_text_channel(ctx: Message,
16
+ name,
17
+ category=None,
18
+ position=MISSING,
19
+ slowmode=MISSING,
16
20
  topic=MISSING, nsfw=MISSING,
17
- permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING):
21
+ permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
22
+ reason=None):
18
23
  """
19
- Crée un salon textuel sur le serveur
24
+ Creates a text channel on the server
20
25
  """
21
26
 
22
- channel_category = ctx.guild.get_channel(category)
27
+ channel_category = ctx.channel.guild.get_channel(category)
23
28
 
24
29
  created_channel = await ctx.guild.create_text_channel(name,
25
30
  category=channel_category,
@@ -27,18 +32,41 @@ async def dshell_create_text_channel(ctx: GuildChannel, name, category=None, pos
27
32
  slowmode_delay=slowmode,
28
33
  topic=topic,
29
34
  nsfw=nsfw,
30
- overwrites=permission)
35
+ overwrites=permission,
36
+ reason=reason)
37
+
38
+ return created_channel.id
39
+
40
+ async def dshell_create_voice_channel(ctx: Message,
41
+ name,
42
+ category=None,
43
+ position=MISSING,
44
+ bitrate=MISSING,
45
+ permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
46
+ reason=None):
47
+ """
48
+ Creates a voice channel on the server
49
+ """
50
+
51
+ channel_category = ctx.channel.guild.get_channel(category)
52
+
53
+ created_channel = await ctx.guild.create_voice_channel(name,
54
+ category=channel_category,
55
+ position=position,
56
+ bitrate=bitrate,
57
+ overwrites=permission,
58
+ reason=reason)
31
59
 
32
60
  return created_channel.id
33
61
 
34
62
 
35
- async def dshell_delete_channel(ctx: GuildChannel, channel=None, reason=None, timeout=0):
63
+ async def dshell_delete_channel(ctx: Message, channel=None, reason=None, timeout=0):
36
64
  """
37
- Supprime un salon.
38
- Possibilité de lui rajouter un temps d'attente avant qu'il ne le supprime (en seconde)
65
+ Deletes a channel.
66
+ You can add a waiting time before it is deleted (in seconds)
39
67
  """
40
68
 
41
- channel_to_delete = ctx if channel is None else ctx.guild.get_channel(channel)
69
+ channel_to_delete = ctx.channel if channel is None else ctx.channel.guild.get_channel(channel)
42
70
 
43
71
  if channel_to_delete is None:
44
72
  raise Exception(f"Le channel {channel} n'existe pas !")
@@ -50,12 +78,12 @@ async def dshell_delete_channel(ctx: GuildChannel, channel=None, reason=None, ti
50
78
  return channel_to_delete.id
51
79
 
52
80
 
53
- async def dshell_delete_channels(ctx: GuildChannel, name=None, regex=None, reason=None):
81
+ async def dshell_delete_channels(ctx: Message, name=None, regex=None, reason=None):
54
82
  """
55
- Supprime tous les salons ayant le même nom et/ou le même regex.
56
- Si aucun des deux n'est mis, il supprimera tous les salons comportant le même nom que celui ou a été fait la commande
83
+ Deletes all channels with the same name and/or matching the same regex.
84
+ If neither is set, it will delete all channels with the same name as the one where the command was executed.
57
85
  """
58
- for channel in ctx.guild.channels:
86
+ for channel in ctx.channel.guild.channels:
59
87
 
60
88
  if name is not None and channel.name == str(name):
61
89
  await channel.delete(reason=reason)
@@ -0,0 +1,67 @@
1
+ from discord import MISSING, Message
2
+
3
+
4
+ __all__ = [
5
+ "dshell_ban_member",
6
+ "dshell_unban_member",
7
+ "dshell_kick_member",
8
+ "dshell_rename_member"
9
+ ]
10
+
11
+ async def dshell_ban_member(ctx: Message, member: int, reason: str = MISSING):
12
+ """
13
+ Bans a member from the server.
14
+ """
15
+ banned_member = ctx.channel.guild.get_member(member)
16
+
17
+ if not banned_member:
18
+ return 1 # Member not found in the server
19
+
20
+ await ctx.channel.guild.ban(banned_member, reason=reason)
21
+
22
+ return banned_member.id
23
+
24
+ async def dshell_unban_member(ctx: Message, user: int, reason: str = MISSING):
25
+ """
26
+ Unbans a user from the server.
27
+ """
28
+ banned_users = ctx.channel.guild.bans()
29
+ user_to_unban = None
30
+
31
+ async for ban_entry in banned_users:
32
+ if ban_entry.user.id == user:
33
+ user_to_unban = ban_entry.user
34
+ break
35
+
36
+ if not user_to_unban:
37
+ return 1 # User not found in the banned list
38
+
39
+ await ctx.channel.guild.unban(user_to_unban, reason=reason)
40
+
41
+ return user_to_unban.id
42
+
43
+ async def dshell_kick_member(ctx: Message, member: int, reason: str = MISSING):
44
+ """
45
+ Kicks a member from the server.
46
+ """
47
+ kicked_member = ctx.channel.guild.get_member(member)
48
+
49
+ if not kicked_member:
50
+ return 1 # Member not found in the server
51
+
52
+ await ctx.channel.guild.kick(kicked_member, reason=reason)
53
+
54
+ return kicked_member.id
55
+
56
+ async def dshell_rename_member(ctx: Message, new_name, member=None):
57
+ """
58
+ Renames a member in the server.
59
+ """
60
+ renamed_member = ctx.channel.guild.get_member(member)
61
+
62
+ if not renamed_member:
63
+ return 1 # Member not found in the server
64
+
65
+ await renamed_member.edit(nick=new_name)
66
+
67
+ return renamed_member.id
@@ -1,22 +1,27 @@
1
- from discord import Embed
2
- from discord.abc import GuildChannel
1
+ from discord import Embed, Message
2
+ from discord.ext import commands
3
+ from .._DshellParser.ast_nodes import ListNode
4
+ from re import search
3
5
 
4
6
  __all__ = [
5
7
  'dshell_send_message',
6
8
  'dshell_delete_message',
7
- 'dshell_purge_message'
9
+ 'dshell_purge_message',
10
+ 'dshell_edit_message',
11
+ 'dshell_research_regex_message',
12
+ 'dshell_research_regex_in_content'
8
13
  ]
9
14
 
10
15
 
11
- async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, channel=None, embeds=None, embed=None):
16
+ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=None, embeds=None, embed=None):
12
17
  from .._DshellParser.ast_nodes import ListNode
13
18
  """
14
- Envoie un message sur Discord
19
+ Sends a message on Discord
15
20
  """
16
- channel_to_send = ctx if channel is None else ctx.guild.get_channel(channel)
21
+ channel_to_send = ctx.channel if channel is None else ctx.channel.guild.get_channel(channel)
17
22
 
18
23
  if channel_to_send is None:
19
- raise Exception(f'Le channel {channel} est introuvable !')
24
+ raise Exception(f'Channel {channel} not found!')
20
25
 
21
26
  if embeds is None:
22
27
  embeds = ListNode([])
@@ -34,27 +39,75 @@ async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, chan
34
39
  return sended_message.id
35
40
 
36
41
 
37
- async def dshell_delete_message(ctx: GuildChannel, message, reason=None, delay=0):
42
+ async def dshell_delete_message(ctx: Message, message, reason=None, delay=0):
38
43
  """
39
- Supprime un message
44
+ Deletes a message
40
45
  """
41
46
 
42
- delete_message = ctx.get_partial_message(message) # construit une référence au message (même s'il n'existe pas)
47
+ delete_message = ctx.channel.get_partial_message(message) # builds a reference to the message (even if it doesn't exist)
43
48
 
44
49
  if delay > 3600:
45
- raise Exception(f'Le délait de suppression du message est trop grand ! ({delay} secondes)')
50
+ raise Exception(f'The message deletion delay is too long! ({delay} seconds)')
46
51
 
47
52
  await delete_message.delete(delay=delay, reason=reason)
48
53
 
49
54
 
50
- async def dshell_purge_message(ctx: GuildChannel, message_number, channel=None, reason=None):
55
+ async def dshell_purge_message(ctx: Message, message_number, channel=None, reason=None):
51
56
  """
52
- Purge les messages d'un salon
57
+ Purges messages from a channel
53
58
  """
54
59
 
55
- purge_channel = ctx if channel is None else ctx.guild.get_channel(channel)
60
+ purge_channel = ctx.channel if channel is None else ctx.channel.guild.get_channel(channel)
56
61
 
57
62
  if purge_channel is None:
58
- raise Exception(f"Le salon {channel} à purgé est introuvable !")
63
+ raise Exception(f"Channel {channel} to purge not found!")
59
64
 
60
65
  await purge_channel.purge(limit=message_number, reason=reason)
66
+
67
+
68
+ async def dshell_edit_message(ctx: Message, message, new_content=None, embeds=None):
69
+ """
70
+ Edits a message
71
+ """
72
+ edit_message = ctx.channel.get_partial_message(message) # builds a reference to the message (even if it doesn't exist)
73
+
74
+ if embeds is None:
75
+ embeds = []
76
+
77
+ elif isinstance(embeds, Embed):
78
+ embeds = [embeds]
79
+
80
+ await edit_message.edit(content=new_content, embeds=embeds)
81
+
82
+ return edit_message.id
83
+
84
+ async def dshell_research_regex_message(ctx: Message, regex, channel=None):
85
+ """
86
+ Searches for messages matching a regex in a channel
87
+ """
88
+
89
+ search_channel = ctx.channel if channel is None else ctx.channel.guild.get_channel(channel)
90
+
91
+ if search_channel is None:
92
+ raise Exception(f"Channel {channel} to search not found!")
93
+
94
+ messages = ListNode([])
95
+ async for message in search_channel.history(limit=100):
96
+ if search(regex, message.content):
97
+ messages.add(message)
98
+
99
+ if not messages:
100
+ raise commands.CommandError(f"No messages found matching the regex '{regex}'.")
101
+
102
+ return messages
103
+
104
+ async def dshell_research_regex_in_content(ctx: Message, regex, content):
105
+ """
106
+ Searches for a regex in a specific message content
107
+ """
108
+
109
+ if not search(regex, content):
110
+ return True
111
+
112
+ return False
113
+
@@ -1,10 +1,9 @@
1
1
  from asyncio import sleep
2
2
  from re import findall
3
3
  from typing import TypeVar, Union, Any, Optional, Callable
4
- from logging import Logger
5
4
 
6
5
 
7
- from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role
6
+ from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role, Message
8
7
  from discord.abc import GuildChannel, PrivateChannel
9
8
 
10
9
  from .._DshellParser.ast_nodes import *
@@ -16,16 +15,21 @@ from .._DshellTokenizer.dshell_token_type import Token
16
15
  from .._DshellTokenizer.dshell_tokenizer import DshellTokenizer
17
16
 
18
17
  All_nodes = TypeVar('All_nodes', IfNode, LoopNode, ElseNode, ElifNode, ArgsCommandNode, VarNode, IdentOperationNode)
19
- context = TypeVar('context', AutoShardedBot, GuildChannel, PrivateChannel)
18
+ context = TypeVar('context', AutoShardedBot, Message, PrivateChannel)
20
19
 
21
20
 
22
21
  class DshellInterpreteur:
22
+ """
23
+ Discord Dshell interpreter.
24
+ Make what you want with Dshell code to interact with Discord !
25
+ """
23
26
 
24
- def __init__(self, ast_or_code: Union[list[All_nodes], str], ctx: context, debug: bool = False):
27
+ def __init__(self, code: str, ctx: context, debug: bool = False):
25
28
  """
26
- Interpreter Dshell code or AST.
29
+ Interpreter Dshell code
30
+ :param code: The code to interpret. Each line must end with a newline character, except SEPARATOR and SUB_SEPARATOR tokens.
27
31
  """
28
- self.ast: list[ASTNode] = parse(DshellTokenizer(ast_or_code).start(), StartNode([]))[0]
32
+ self.ast: list[ASTNode] = parse(DshellTokenizer(code).start(), StartNode([]))[0]
29
33
  self.env: dict[str, Any] = {}
30
34
  self.ctx: context = ctx
31
35
  if debug:
@@ -33,7 +37,16 @@ class DshellInterpreteur:
33
37
 
34
38
  async def execute(self, ast: Optional[list[All_nodes]] = None):
35
39
  """
36
- Execute l'arbre syntaxique.
40
+ Executes the abstract syntax tree (AST) generated from the Dshell code.
41
+
42
+ This asynchronous method traverses and interprets each node in the AST, executing commands,
43
+ handling control flow structures (such as if, elif, else, and loops), managing variables,
44
+ and interacting with Discord through the provided context. It supports command execution,
45
+ variable assignment, sleep operations, and permission handling, among other features.
46
+
47
+ :param ast: Optional list of AST nodes to execute. If None, uses the interpreter's main AST.
48
+ :raises RuntimeError: If an EndNode is encountered, indicating execution should be stopped.
49
+ :raises Exception: If sleep duration is out of allowed bounds.
37
50
  """
38
51
  if ast is None:
39
52
  ast = self.ast
@@ -92,19 +105,20 @@ class DshellInterpreteur:
92
105
  elif isinstance(node, SleepNode):
93
106
  sleep_time = eval_expression(node.body, self)
94
107
  if sleep_time > 3600:
95
- raise Exception(f'Le temps maximal de sommeil est de 3600 secondes !')
108
+ raise Exception(f"Sleep time is too long! ({sleep_time} seconds) - maximum is 3600 seconds)")
96
109
  elif sleep_time < 1:
97
- raise Exception(f'Le temps minimal de sommeil est de 1 seconde !')
110
+ raise Exception(f"Sleep time is too short! ({sleep_time} seconds) - minimum is 1 second)")
98
111
 
99
112
  await sleep(sleep_time)
100
113
 
101
114
 
102
115
  elif isinstance(node, EndNode):
103
- raise RuntimeError(f"Execution interromput -> #end atteint")
116
+ raise RuntimeError("Execution stopped - EndNode encountered")
104
117
 
105
118
  def eval_data_token(self, token: Token):
106
119
  """
107
- Evalue les tokens de data
120
+ Eval a data token and returns its value in Python.
121
+ :param token: The token to evaluate.
108
122
  """
109
123
 
110
124
  if not hasattr(token, 'type'):
@@ -137,7 +151,9 @@ class DshellInterpreteur:
137
151
 
138
152
  def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) -> Token:
139
153
  """
140
- Evalue une expression en ligne des variables
154
+ Eval a conditional expression inline.
155
+ :param if_node: The IfNode to evaluate.
156
+ :param interpreter: The Dshell interpreter instance.
141
157
  """
142
158
  if eval_expression(if_node.condition, interpreter):
143
159
  return eval_expression(if_node.body, interpreter)
@@ -147,7 +163,9 @@ def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) ->
147
163
 
148
164
  def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any:
149
165
  """
150
- Evalue une expressions arithmétique et logique et renvoie son résultat. Cela peut-être un booléen, un entier, un flottant, une chaîne de caractère ou une liste
166
+ Evaluates an arithmetic and logical expression.
167
+ :param tokens: A list of tokens representing the expression.
168
+ :param interpreter: The Dshell interpreter instance.
151
169
  """
152
170
  postfix = to_postfix(tokens)
153
171
  stack = []
@@ -172,24 +190,28 @@ def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any
172
190
  stack.append(result)
173
191
 
174
192
  else:
175
- raise SyntaxError(f"Token inattendu en condition: {token}")
193
+ raise SyntaxError(f"Unexpected token type: {token.type} - {token.value}")
176
194
 
177
195
  if len(stack) != 1:
178
- raise SyntaxError("Condition mal formée")
196
+ raise SyntaxError("Invalid expression: stack should contain exactly one element after evaluation.")
179
197
 
180
198
  return stack[0]
181
199
 
182
200
 
183
201
  async def call_function(function: Callable, args: ArgsCommandNode, interpreter: DshellInterpreteur):
184
202
  """
185
- Appelle une fonction avec évaluation des arguments Dshell en valeurs Python
203
+ Call the function with the given arguments.
204
+ It can be an async function !
205
+ :param function: The function to call.
206
+ :param args: The arguments to pass to the function.
207
+ :param interpreter: The Dshell interpreter instance.
186
208
  """
187
209
  reformatted = regroupe_commandes(args.body, interpreter)[0]
188
210
 
189
211
  # conversion des args en valeurs Python
190
212
  absolute_args = reformatted.pop('*', list())
191
213
 
192
- reformatted: dict[str, Token] # ne sert à rien, juste à indiquer ce qu'il contient dorénanvant
214
+ reformatted: dict[str, Token]
193
215
 
194
216
  absolute_args.insert(0, interpreter.ctx)
195
217
  keyword_args = {
@@ -200,64 +222,69 @@ async def call_function(function: Callable, args: ArgsCommandNode, interpreter:
200
222
 
201
223
  def regroupe_commandes(body: list[Token], interpreter: DshellInterpreteur) -> list[dict[str, list[Any]]]:
202
224
  """
203
- Regroupe les arguments de la commande sous la forme d'un dictionnaire python.
204
- Sachant que l'on peut spécifier le paramètre que l'on souhaite passer via -- suivit du nom du paramètre. Mais ce n'est pas obligatoire !
205
- Les paramètres non obligatoire seront stocké dans une liste sous la forme de tokens avec comme clé '*'.
206
- Les autres ayant été spécifié via un séparateur, ils seront sous la forme d'une liste de tokens avec comme clé le token IDENT qui suivra le séparateur pour chaque argument.
225
+ Groups the command arguments in the form of a python dictionary.
226
+ Note that you can specify the parameter you wish to pass via -- followed by the parameter name. But this is not mandatory!
227
+ Non-mandatory parameters will be stored in a list in the form of tokens with the key ‘*’.
228
+ The others, having been specified via a separator, will be in the form of a list of tokens with the IDENT token as key, following the separator for each argument.
229
+ If two parameters have the same name, the last one will overwrite the previous one.
230
+ To accept duplicates, use the SUB_SEPARATOR (~~) to create a sub-dictionary for parameters with the same name.
231
+
232
+ :param body: The list of tokens to group.
233
+ :param interpreter: The Dshell interpreter instance.
207
234
  """
208
- tokens = {'*': []} # les tokens à renvoyer
209
- current_arg = '*' # les clés des arguments sont les types auquels ils appartiennent. L'* sert à tous les arguments non explicité par un séparateur et un IDENT
235
+ tokens = {'*': []} # tokens to return
236
+ current_arg = '*' # the argument keys are the types they belong to. '*' is for all arguments not explicitly specified by a separator and an IDENT
210
237
  n = len(body)
211
238
  list_tokens: list[dict] = [tokens]
212
239
 
213
240
  i = 0
214
241
  while i < n:
215
242
  if body[i].type == DTT.SEPARATOR and body[
216
- i + 1].type == DTT.IDENT: # On regarde si c'est un séparateur et si le token suivant est un IDENT
217
- current_arg = body[i + 1].value # on change l'argument actuel. Il sera donc impossible de revenir à l'*
218
- tokens[current_arg] = '' # on lui crée une paire clé/valeur
219
- i += 2 # on skip l'IDENT qu'il y a après le séparateur car on vient de le traiter
243
+ i + 1].type == DTT.IDENT: # Check if it's a separator and if the next token is an IDENT
244
+ current_arg = body[i + 1].value # change the current argument. It will be impossible to return to '*'
245
+ tokens[current_arg] = '' # create a key/value pair for it
246
+ i += 2 # skip the IDENT after the separator since it has just been processed
220
247
 
221
248
  elif body[
222
- i].type == DTT.SUB_SEPARATOR: # permet de délimiter les paramètres et de pouvoir en mettre plusieurs ayant le même nom
249
+ i].type == DTT.SUB_SEPARATOR: # allows to delimit parameters and to have several with the same name
223
250
  list_tokens += regroupe_commandes(
224
251
  [Token(
225
252
  type_=DTT.SEPARATOR, value=body[i].value, position=body[i].position)
226
253
  ] + body[i + 1:], interpreter
227
- ) # on ajoute un sous-dictionnaire pour les sous-commandes
254
+ ) # add a sub-dictionary for sub-commands
228
255
  return list_tokens
229
256
 
230
257
  else:
231
258
  if current_arg == '*':
232
259
  tokens[current_arg].append(interpreter.eval_data_token(body[i]))
233
260
  else:
234
- tokens[current_arg] = interpreter.eval_data_token(body[i]) # on ajoute le token à l'argument actuel
261
+ tokens[current_arg] = interpreter.eval_data_token(body[i]) # add the token to the current argument
235
262
  i += 1
236
263
  return list_tokens
237
264
 
238
265
 
239
266
  def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: DshellInterpreteur) -> Embed:
240
267
  """
241
- Construit un embed à partir des informations de la commande.
268
+ Builds an embed from the command information.
242
269
  """
243
270
  args_main_embed: dict[str, list[Any]] = regroupe_commandes(body, interpreter)[0]
244
- args_main_embed.pop('*') # on enlève les paramètres non spécifié pour l'embed
245
- args_main_embed: dict[str, Token] # on précise se qu'il contient dorénavant
271
+ args_main_embed.pop('*') # remove unspecified parameters for the embed
272
+ args_main_embed: dict[str, Token] # specify what it contains from now on
246
273
 
247
274
  args_fields: list[dict[str, Token]] = []
248
- for field in fields: # on fait la même chose pour tous les fields
275
+ for field in fields: # do the same for the fields
249
276
  a = regroupe_commandes(field.body, interpreter)[0]
250
277
  a.pop('*')
251
278
  a: dict[str, Token]
252
279
  args_fields.append(a)
253
280
 
254
281
  if 'color' in args_main_embed and isinstance(args_main_embed['color'],
255
- ListNode): # si on passe l'argument de la couleur sous la forme d'une liste RGB
282
+ ListNode): # if color is a ListNode, convert it to Colour
256
283
  args_main_embed['color'] = Colour.from_rgb(*args_main_embed['color'])
257
284
 
258
- embed = Embed(**args_main_embed) # on construit l'embed principal
285
+ embed = Embed(**args_main_embed) # build the main embed
259
286
  for field in args_fields:
260
- embed.add_field(**field) # on joute tous les fields
287
+ embed.add_field(**field) # add all fields
261
288
 
262
289
  return embed
263
290
 
@@ -265,21 +292,21 @@ def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: Ds
265
292
  def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict[
266
293
  Union[Member, Role], PermissionOverwrite]:
267
294
  """
268
- Construit un dictionnaire de permissions à partir des informations de la commande.
295
+ Builds a dictionary of PermissionOverwrite objects from the command information.
269
296
  """
270
297
  args_permissions: list[dict[str, list[Any]]] = regroupe_commandes(body, interpreter)
271
298
  permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
272
299
 
273
300
  for i in args_permissions:
274
301
  i.pop('*')
275
- permissions.update(DshellPermissions(i).get_permission_overwrite(interpreter.ctx.guild))
302
+ permissions.update(DshellPermissions(i).get_permission_overwrite(interpreter.ctx.channel.guild))
276
303
 
277
304
  return permissions
278
305
 
279
306
 
280
307
  class DshellIterator:
281
308
  """
282
- Utilisé pour transformer n'importe quoi en un iterable
309
+ Used to transform anything into an iterable
283
310
  """
284
311
 
285
312
  def __init__(self, data):
@@ -303,20 +330,20 @@ class DshellPermissions:
303
330
 
304
331
  def __init__(self, target: dict[str, list[int]]):
305
332
  """
306
- Permet de créer un objet de permissions Dshell.
307
- :param target: Un dictionnaire contenant les paramètres et leurs valeurs.
308
- Paramètres attendus : "allow", "deny", "members", "roles".
309
- Pour "members" et "roles", les valeurs doivent être des ListNode d'IDs.
333
+ Creates a Dshell permissions object.
334
+ :param target: A dictionary containing parameters and their values.
335
+ Expected parameters: allow”, deny”, members’, roles”.
336
+ For members and roles”, values must be ID ListNodes.
310
337
  """
311
338
  self.target: dict[str, Union[ListNode, int]] = target
312
339
 
313
340
  @staticmethod
314
341
  def get_instance(guild: Guild, target_id: int) -> Union[Member, Role]:
315
342
  """
316
- Retourne l'instance correspondante à l'id donné. Uniquement un Member ou un Role.
317
- :param guild: Le serveur Discord dans lequel chercher
318
- :param target_id: L'ID du membre ou du rôle
319
- :return: Une instance de Member ou Role
343
+ Returns the instance corresponding to the given id. Only a Member or Role.
344
+ :param guild: The Discord server in which to search
345
+ :param target_id: The ID of the member or role
346
+ :return: An instance of Member or Role
320
347
  """
321
348
  try:
322
349
  member = DshellPermissions.get_member(guild, target_id)
@@ -334,48 +361,46 @@ class DshellPermissions:
334
361
  if role is not None:
335
362
  return role
336
363
 
337
- raise ValueError(f"Aucun membre ou rôle trouvé avec l'ID {target_id} dans le serveur {guild.name}.")
338
-
339
364
  @staticmethod
340
365
  def get_member(guild: Guild, target_id: int) -> Member:
341
366
  """
342
- Retourne l'instance de Member correspondante à l'id donné.
343
- :param guild: Le serveur Discord dans lequel chercher
344
- :param target_id: L'ID du membre
345
- :return: Une instance de Member
367
+ Returns the Member instance corresponding to the given id.
368
+ :param guild: The Discord server to search
369
+ :param target_id: The member ID
370
+ :return: A Member instance
346
371
  """
347
372
  member = guild.get_member(target_id)
348
373
  if member is not None:
349
374
  return member
350
375
 
351
- raise ValueError(f"Aucun membre trouvé avec l'ID {target_id} dans le serveur {guild.name}.")
376
+ raise ValueError(f"No member found with ID {target_id} in guild {guild.name}.")
352
377
 
353
378
  @staticmethod
354
379
  def get_role(guild: Guild, target_id: int) -> Role:
355
380
  """
356
- Retourne l'instance de Role correspondante à l'id donné.
357
- :param guild: Le serveur Discord dans lequel chercher
358
- :param target_id: L'ID du rôle
359
- :return: Une instance de Role
381
+ Returns the Role instance corresponding to the given id.
382
+ :param guild: The Discord server to search
383
+ :param target_id: The role ID
384
+ :return: A Role instance
360
385
  """
361
386
  role = guild.get_role(target_id)
362
387
  if role is not None:
363
388
  return role
364
389
 
365
- raise ValueError(f"Aucun rôle trouvé avec l'ID {target_id} dans le serveur {guild.name}.")
390
+ raise ValueError(f"No role found with ID {target_id} in guild {guild.name}.")
366
391
 
367
392
  def get_permission_overwrite(self, guild: Guild) -> dict[Union[Member, Role], PermissionOverwrite]:
368
393
  """
369
- Retourne un objet PermissionOverwrite avec les permissions des membres et rôles.
370
- :param guild: Le serveur Discord
371
- :return: Un objet PermissionOverwrite
394
+ Returns a PermissionOverwrite object with member and role permissions.
395
+ :param guild: The Discord server
396
+ :return: A dictionary of PermissionOverwrite objects with members and roles as keys
372
397
  """
373
398
  permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
374
399
  target_keys = self.target.keys()
375
400
 
376
401
  if 'members' in target_keys:
377
402
  for member_id in (
378
- self.target['members'] if isinstance(self.target['members'], ListNode) else [self.target['members']]): # accepte un seul ID
403
+ self.target['members'] if isinstance(self.target['members'], ListNode) else [self.target['members']]): # allow a single ID
379
404
  member = self.get_member(guild, member_id)
380
405
  permissions[member] = PermissionOverwrite.from_pair(
381
406
  allow=Permissions(permissions=self.target.get('allow', 0)),
@@ -384,13 +409,13 @@ class DshellPermissions:
384
409
 
385
410
  elif 'roles' in target_keys:
386
411
  for role_id in (
387
- self.target['roles'] if isinstance(self.target['roles'], ListNode) else [self.target['roles']]): ## accepte un seul ID
412
+ self.target['roles'] if isinstance(self.target['roles'], ListNode) else [self.target['roles']]): # allow a single ID
388
413
  role = self.get_role(guild, role_id)
389
414
  permissions[role] = PermissionOverwrite.from_pair(
390
415
  allow=Permissions(permissions=self.target.get('allow', 0)),
391
416
  deny=Permissions(permissions=self.target.get('deny', 0))
392
417
  )
393
418
  else:
394
- raise ValueError("Aucun membre ou rôle spécifié dans les permissions.")
419
+ raise ValueError("No members or roles specified in the permissions target.")
395
420
 
396
421
  return permissions
@@ -23,10 +23,16 @@ __all__ = [
23
23
 
24
24
 
25
25
  class ASTNode:
26
+ """
27
+ Base class for all AST nodes.
28
+ """
26
29
  pass
27
30
 
28
31
 
29
32
  class StartNode(ASTNode):
33
+ """
34
+ Node representing the start of the AST.
35
+ """
30
36
  def __init__(self, body: list):
31
37
  self.body = body
32
38
 
@@ -35,7 +41,13 @@ class StartNode(ASTNode):
35
41
 
36
42
 
37
43
  class ElseNode(ASTNode):
44
+ """
45
+ Node representing the 'else' part of an if statement.
46
+ """
38
47
  def __init__(self, body: list[Token]):
48
+ """
49
+ :param body: list of tokens representing the body of the else statement
50
+ """
39
51
  self.body = body
40
52
 
41
53
  def __repr__(self):
@@ -43,7 +55,15 @@ class ElseNode(ASTNode):
43
55
 
44
56
 
45
57
  class ElifNode(ASTNode):
58
+ """
59
+ Node representing an 'elif' part of an if statement.
60
+ """
46
61
  def __init__(self, condition: list[Token], body: list[Token], parent: "IfNode"):
62
+ """
63
+ :param condition: list of tokens representing the condition for the elif
64
+ :param body: list of tokens representing the body of the elif
65
+ :param parent: the if node that this elif belongs to
66
+ """
47
67
  self.condition = condition
48
68
  self.body = body
49
69
  self.parent = parent
@@ -53,8 +73,17 @@ class ElifNode(ASTNode):
53
73
 
54
74
 
55
75
  class IfNode(ASTNode):
76
+ """
77
+ Node representing an 'if' statement, which can contain 'elif' and 'else' parts.
78
+ """
56
79
  def __init__(self, condition: list[Token], body: list[Token], elif_nodes: Optional[list[ElifNode]] = None,
57
80
  else_body: Optional[ElseNode] = None):
81
+ """
82
+ :param condition: list of tokens representing the condition for the if statement
83
+ :param body: list of tokens representing the body of the if statement
84
+ :param elif_nodes: optional list of ElifNode instances representing 'elif' parts
85
+ :param else_body: optional ElseNode instance representing the 'else' part
86
+ """
58
87
  self.condition = condition
59
88
  self.body = body
60
89
  self.elif_nodes = elif_nodes
@@ -65,8 +94,15 @@ class IfNode(ASTNode):
65
94
 
66
95
 
67
96
  class LoopNode(ASTNode):
97
+ """
98
+ Node representing a loop structure in the AST.
99
+ """
68
100
  def __init__(self, variable: "VarNode", body: list):
69
- self.variable = variable # content l'itérable dans son body
101
+ """
102
+ :param variable: VarNode representing the loop variable. This variable will be used to iterate over the body. Can contain a ListNode, string or integer.
103
+ :param body: list of tokens representing the body of the loop
104
+ """
105
+ self.variable = variable
70
106
  self.body = body
71
107
 
72
108
  def __repr__(self):
@@ -74,7 +110,13 @@ class LoopNode(ASTNode):
74
110
 
75
111
 
76
112
  class ArgsCommandNode(ASTNode):
113
+ """
114
+ Node representing the arguments of a command in the AST.
115
+ """
77
116
  def __init__(self, body: list[Token]):
117
+ """
118
+ :param body: list of tokens representing the arguments of the command
119
+ """
78
120
  self.body: list[Token] = body
79
121
 
80
122
  def __repr__(self):
@@ -82,7 +124,14 @@ class ArgsCommandNode(ASTNode):
82
124
 
83
125
 
84
126
  class CommandNode(ASTNode):
127
+ """
128
+ Node representing a command in the AST.
129
+ """
85
130
  def __init__(self, name: str, body: ArgsCommandNode):
131
+ """
132
+ :param name: The command name (e.g., "sm", "cc")
133
+ :param body: ArgsCommandNode containing the arguments of the command
134
+ """
86
135
  self.name = name
87
136
  self.body = body
88
137
 
@@ -91,7 +140,14 @@ class CommandNode(ASTNode):
91
140
 
92
141
 
93
142
  class VarNode(ASTNode):
143
+ """
144
+ Node representing a variable declaration in the AST.
145
+ """
94
146
  def __init__(self, name: Token, body: list[Token]):
147
+ """
148
+ :param name: Token representing the variable name
149
+ :param body: list of tokens representing the body of the variable
150
+ """
95
151
  self.name = name
96
152
  self.body = body
97
153
 
@@ -100,6 +156,9 @@ class VarNode(ASTNode):
100
156
 
101
157
 
102
158
  class EndNode(ASTNode):
159
+ """
160
+ Node representing the end of the AST.
161
+ """
103
162
  def __init__(self):
104
163
  pass
105
164
 
@@ -108,7 +167,13 @@ class EndNode(ASTNode):
108
167
 
109
168
 
110
169
  class FieldEmbedNode(ASTNode):
170
+ """
171
+ Node representing a field in an embed structure.
172
+ """
111
173
  def __init__(self, body: list[Token]):
174
+ """
175
+ :param body: list of tokens representing the field content
176
+ """
112
177
  self.body: list[Token] = body
113
178
 
114
179
  def __repr__(self):
@@ -116,7 +181,14 @@ class FieldEmbedNode(ASTNode):
116
181
 
117
182
 
118
183
  class EmbedNode(ASTNode):
184
+ """
185
+ Node representing an embed structure in the AST.
186
+ """
119
187
  def __init__(self, body: list[Token], fields: list[FieldEmbedNode]):
188
+ """
189
+ :param body: list of tokens representing the embed content
190
+ :param fields: list of FieldEmbedNode instances representing the fields of the embed
191
+ """
120
192
  self.body = body
121
193
  self.fields = fields
122
194
 
@@ -125,7 +197,13 @@ class EmbedNode(ASTNode):
125
197
 
126
198
 
127
199
  class PermissionNode(ASTNode):
200
+ """
201
+ Node representing a permission structure in the AST.
202
+ """
128
203
  def __init__(self, body: list[Token]):
204
+ """
205
+ :param body: list of tokens representing the permission content
206
+ """
129
207
  self.body = body
130
208
 
131
209
  def __repr__(self):
@@ -133,7 +211,13 @@ class PermissionNode(ASTNode):
133
211
 
134
212
 
135
213
  class SleepNode(ASTNode):
214
+ """
215
+ Node representing a sleep command in the AST.
216
+ """
136
217
  def __init__(self, body: list[Token]):
218
+ """
219
+ :param body: list of tokens representing the sleep duration
220
+ """
137
221
  self.body = body
138
222
 
139
223
  def __repr__(self):
@@ -142,14 +226,20 @@ class SleepNode(ASTNode):
142
226
 
143
227
  class IdentOperationNode(ASTNode):
144
228
  """
145
- Gère les opération sur les idendificateur (appel de fonctions)
146
- Faire en sorte que l'appel de la fonction renvoie la class associé pour permettre les imbrications. Pas obligatoire en soit si elle renvoie quelque chose
229
+ Node representing an operation on an identifier in the AST.
230
+ Manages operations on idendifiers (function calls)
231
+ Ensure that the function call returns the associated class to allow nesting. Not mandatory in itself if it returns something
147
232
  """
148
233
 
149
234
  def __init__(self, ident: Token, function: Token, args: Token):
150
- self.ident = ident # content la "class"
151
- self.function = function # contient la méthode appelé
152
- self.args = args # contient une liste de tokens des arguments passé en paramètre
235
+ """
236
+ :param ident: Token representing the identifier (e.g., a class or object)
237
+ :param function: Token representing the function to be called on the identifier
238
+ :param args: Token representing the arguments passed to the function
239
+ """
240
+ self.ident = ident
241
+ self.function = function
242
+ self.args = args
153
243
 
154
244
  def __repr__(self):
155
245
  return f"<IDENT OPERATION> - {self.ident}.{self.function}({self.args})"
@@ -157,33 +247,42 @@ class IdentOperationNode(ASTNode):
157
247
 
158
248
  class ListNode(ASTNode):
159
249
  """
160
- Class iterable permettant de parcourir les listes créé à partir du code Dshell.
161
- Cette class permet aussi d'intéragir avec la liste via des méthodes spécifique non built-in par python.
250
+ Node representing a list structure in the AST.
251
+ Iterable class for browsing lists created from Dshell code.
252
+ This class also lets you interact with the list via specific methods not built in by python.
162
253
  """
163
254
 
164
255
  def __init__(self, body: list[Any]):
256
+ """
257
+ :param body: list of elements to initialize the ListNode with
258
+ """
165
259
  self.iterable: list[Any] = body
166
260
  self.len_iterable: int = len(body)
167
261
  self.iterateur_count: int = 0
168
262
 
169
263
  def add(self, value: Any):
170
264
  """
171
- Ajoute un token à la liste
265
+ Add a value to the list.
172
266
  """
173
267
  if self.len_iterable > 10000:
174
- raise PermissionError('Une liste ne peut dépasser les 10.000 éléments !')
268
+ raise PermissionError('The list is too long, it must not exceed 10,000 elements !')
175
269
 
176
270
  self.iterable.append(value)
177
271
  self.len_iterable += 1
178
272
 
179
273
  def remove(self, value: Any, number: int = 1):
180
274
  """
181
- Enlève un ou plusieurs token de la liste
275
+ Remove a value from the list.
182
276
  """
183
277
  if number < 1:
184
- raise Exception(f"Le nombre d'élément à retirer doit-être égale ou supperieur à 1 !")
278
+ raise Exception(f"The number of elements to remove must be at least 1, not {number} !")
185
279
 
186
280
  def __add__(self, other: "ListNode"):
281
+ """
282
+ Add another ListNode to this one.
283
+ :param other: Another ListNode to add to this one.
284
+ :return: Instance of ListNode with combined elements.
285
+ """
187
286
  for i in other:
188
287
  self.add(i)
189
288
  return self
@@ -192,6 +291,10 @@ class ListNode(ASTNode):
192
291
  return self
193
292
 
194
293
  def __next__(self):
294
+ """
295
+ Iterate over the elements of the list.
296
+ :return: an element from the list.
297
+ """
195
298
 
196
299
  if self.iterateur_count >= self.len_iterable:
197
300
  self.iterateur_count = 0
@@ -32,7 +32,9 @@ if TYPE_CHECKING:
32
32
 
33
33
  def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[ASTNode], int]:
34
34
  """
35
- Commande de base pour parser les tokens
35
+ Parse the list of tokens and return a list of AST nodes.
36
+ :param token_lines: table of tokens
37
+ :param start_node: the node where to start the parsing
36
38
  """
37
39
  pointeur = 0 # pointeur sur les listes de tokens pour savoir ou parser
38
40
  blocks: list[Union[ASTNode, EndNode]] = [start_node] # liste d'imbrication des blocks pour gérer l'imbrication
@@ -11,6 +11,7 @@ from typing import Callable
11
11
 
12
12
  from ..DISCORD_COMMANDS.dshell_channel import *
13
13
  from ..DISCORD_COMMANDS.dshell_message import *
14
+ from ..DISCORD_COMMANDS.dshell_member import *
14
15
 
15
16
  dshell_keyword: set[str] = {
16
17
  'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep'
@@ -24,11 +25,15 @@ dshell_commands: dict[str, Callable] = {
24
25
  "dm": dshell_delete_message,
25
26
  "pm": dshell_purge_message,
26
27
  "cc": dshell_create_text_channel, # create channel
28
+ "cvc": dshell_create_voice_channel, # create voice channel
27
29
  "dc": dshell_delete_channel, # delete channel
28
- "dcs": dshell_delete_channels,
29
- "uc": dshell_send_message,
30
- # update channel (aura toutes les modifications possible -> servira à ne faire qu'une commande pour modifier plusieurs chose sur le salon)
31
- "rc": dshell_send_message # rename channel
30
+ "dcs": dshell_delete_channels, # delete several channels by name or regex
31
+ "bm": dshell_ban_member, # ban member
32
+ "um": dshell_unban_member, # unban member
33
+ "km": dshell_kick_member, # kick member
34
+ "em": dshell_edit_message, # edit message
35
+ "srm": dshell_research_regex_message, # research regex in message
36
+ "src": dshell_research_regex_in_content, # research regex in content
32
37
  }
33
38
 
34
39
  dshell_mathematical_operators: dict[str, tuple[Callable, int]] = {
@@ -43,11 +48,11 @@ dshell_mathematical_operators: dict[str, tuple[Callable, int]] = {
43
48
  r"=>": (lambda a, b: a >= b, 4),
44
49
 
45
50
  r".": (lambda a, b: a.b, 9),
46
- r"->": (lambda a: a.at, 10), # équivalent à l'appel .at(key)
51
+ r"->": (lambda a: a.at, 10), # equivalent to calling .at(key)
47
52
 
48
53
  r"+": (lambda a, b: a + b, 6),
49
54
  r"-": (lambda a, b=None: -a if b is None else a - b, 6),
50
- # attention : ambiguïté entre unaire et binaire à traiter dans ton parseur
55
+ # warning: ambiguity between unary and binary to be handled in your parser
51
56
  r"**": (lambda a, b: a ** b, 8),
52
57
  r"*": (lambda a, b: a * b, 7),
53
58
  r"%": (lambda a, b: a % b, 7),
@@ -71,7 +76,7 @@ dshell_operators.update(dshell_mathematical_operators)
71
76
 
72
77
  '''
73
78
  C_create_var = "var"
74
- C_obligate_var = "ovar" # rend obligatoire les variables
79
+ C_obligate_var = "ovar" # makes variables mandatory
75
80
 
76
81
  # guild
77
82
  C_create_channel = "cc"
@@ -120,5 +125,5 @@ C_create_var = "var"
120
125
  C_clear_emoji = "ce"
121
126
  C_remove_reaction = "rre"
122
127
 
123
- # bouton
128
+ # button
124
129
  C_create_button = "b"'''
@@ -32,7 +32,7 @@ class DshellTokenType(Enum):
32
32
 
33
33
 
34
34
  class Token:
35
- def __init__(self, type_: "DTT", value: Union[str, list], position: int):
35
+ def __init__(self, type_: "DTT", value: Union[str, list], position: tuple[int, int]):
36
36
  self.type = type_
37
37
  self.value = value
38
38
  self.position = position
@@ -59,6 +59,7 @@ class DshellTokenizer:
59
59
  """
60
60
  tokens: list[list[Token]] = []
61
61
 
62
+ line_number = 1
62
63
  for ligne in commandes_lines: # iter chaque ligne du code
63
64
  tokens_par_ligne: list[Token] = []
64
65
 
@@ -66,7 +67,7 @@ class DshellTokenizer:
66
67
 
67
68
  for match in finditer(pattern, ligne): # iter les résultat du match pour avoir leur position
68
69
  if token_type != DTT.COMMENT: # si ce n'est pas un commentaire
69
- token = Token(token_type, match.group(1), match.start()) # on enregistre son token
70
+ token = Token(token_type, match.group(1), (line_number, match.start())) # on enregistre son token
70
71
  tokens_par_ligne.append(token)
71
72
 
72
73
  len_match = len(match.group(0))
@@ -81,7 +82,7 @@ class DshellTokenizer:
81
82
  result) > 0 else result # gère si la structure de donnée est vide ou non
82
83
 
83
84
  tokens_par_ligne.sort(key=lambda
84
- token: token.position) # trie la position par rapport aux positions de match des tokens pour les avoir dans l'ordre du code
85
+ token: token.position[1]) # trie la position par rapport aux positions de match des tokens pour les avoir dans l'ordre du code
85
86
  if tokens_par_ligne:
86
87
  tokens.append(tokens_par_ligne)
87
88
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dshellInterpreter
3
- Version: 0.1.10
3
+ Version: 0.1.12
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
@@ -0,0 +1,19 @@
1
+ Dshell/__init__.py,sha256=UPvXnewe_8FX9aoevMA78UN1k8AY-u8LTY3vEVxaDxw,72
2
+ Dshell/DISCORD_COMMANDS/__init__.py,sha256=unbZE4sxFCbUQ4Qptr1BhWu-nwhvI2oRzcDLtRmX6Ug,92
3
+ Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=pKN-jzPSk2UI0LgUt31LsOYs5bWLys6LcQclQ-AwbXE,3713
4
+ Dshell/DISCORD_COMMANDS/dshell_member.py,sha256=hV_8tFUa_RLwh-UaoLcHQr4yp0ln2vjvzFW5IJwDGVM,1792
5
+ Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=12Alhl_7qgPcs1NCEWDgUVPSsaKmULHkrbGuGH2LWu8,3406
6
+ Dshell/_DshellInterpreteur/__init__.py,sha256=xy5-J-R3YmY99JF3NBHTRRLsComFxpjnCA5xacISctU,35
7
+ Dshell/_DshellInterpreteur/dshell_interpreter.py,sha256=x1_t-9twq2IaB5aQUJN9XFvXbujMCN1KRX_1uYr9IGA,17289
8
+ Dshell/_DshellParser/__init__.py,sha256=ONDfhZMvClqP_6tE8SLjp-cf3pXL-auQYnfYRrHZxC4,56
9
+ Dshell/_DshellParser/ast_nodes.py,sha256=ZPZAA6yqR62mLAMGVO94wTUVmpYM91qAwSKFiWNAt74,9125
10
+ Dshell/_DshellParser/dshell_parser.py,sha256=SqZRG7i8_vdIFhaQwLi-Q8LWIwyw5FaPFEGMX5vsWwU,14074
11
+ Dshell/_DshellTokenizer/__init__.py,sha256=LIQSRhDx2B9pmPx5ADMwwD0Xr9ybneVLhHH8qrJWw_s,172
12
+ Dshell/_DshellTokenizer/dshell_keywords.py,sha256=Mf48FtTWZN-bgNwFVijFbcQK1bZEEdyutQvu_DXJEVo,3915
13
+ Dshell/_DshellTokenizer/dshell_token_type.py,sha256=p0cR4sxhmq03AqBjd0h_sg2eDzgBmd3dhrrchYkL1Pk,1011
14
+ Dshell/_DshellTokenizer/dshell_tokenizer.py,sha256=DSGiSHj9jLqP7RkC-8WFRqFvitJ7P4b7p0CJn4ek7hE,5831
15
+ dshellinterpreter-0.1.12.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
16
+ dshellinterpreter-0.1.12.dist-info/METADATA,sha256=CpdSKbxC4rMdof6AvL_mt_Ae0ZGRmAg8hLb807-uz4w,1096
17
+ dshellinterpreter-0.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
+ dshellinterpreter-0.1.12.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
19
+ dshellinterpreter-0.1.12.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- Dshell/__init__.py,sha256=UPvXnewe_8FX9aoevMA78UN1k8AY-u8LTY3vEVxaDxw,72
2
- Dshell/DISCORD_COMMANDS/__init__.py,sha256=s58iMazDXNPDLZ3Hvymh__C5w7lcgEvaYfX0-SHocRo,62
3
- Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=RmzqXiuwWTbIUV37KtutFsw2uuXNY7HJFtbJCut5rgg,2388
4
- Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=cOZzPbm4wkgObuIL42CH1R3qDhPP8ONiP4BA-XTfAMc,1880
5
- Dshell/_DshellInterpreteur/__init__.py,sha256=xy5-J-R3YmY99JF3NBHTRRLsComFxpjnCA5xacISctU,35
6
- Dshell/_DshellInterpreteur/dshell_interpreter.py,sha256=V9sF_2k7JU25yS7n2Ms95fMsjV-pCQy6eCCMu74ilVA,16113
7
- Dshell/_DshellParser/__init__.py,sha256=ONDfhZMvClqP_6tE8SLjp-cf3pXL-auQYnfYRrHZxC4,56
8
- Dshell/_DshellParser/ast_nodes.py,sha256=dRAYD7ZgNB6q5RGwqgWrM68PtUzSFGMBb6xEwvzaDxo,5687
9
- Dshell/_DshellParser/dshell_parser.py,sha256=mA8uA-xBhKcfnSKfLfePwI_fD0GrHbj0VBVeJPbcGas,13956
10
- Dshell/_DshellTokenizer/__init__.py,sha256=LIQSRhDx2B9pmPx5ADMwwD0Xr9ybneVLhHH8qrJWw_s,172
11
- Dshell/_DshellTokenizer/dshell_keywords.py,sha256=wTV89px9bUY4uf0KCnDr356H_dBIVgcPr55L_6-AWdg,3661
12
- Dshell/_DshellTokenizer/dshell_token_type.py,sha256=NE-sVloBYtioZpWKnWuO5p0YcObGJZPNaKwc8lWDonQ,999
13
- Dshell/_DshellTokenizer/dshell_tokenizer.py,sha256=2tto_gXYj94fLFx99p6nBbtplALT3Ysz9oBwatX9tIA,5788
14
- dshellinterpreter-0.1.10.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
15
- dshellinterpreter-0.1.10.dist-info/METADATA,sha256=1DKZzK2v6ED7iMaKg7H3CLNG4qf62niR3wfBT8_-xbU,1096
16
- dshellinterpreter-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- dshellinterpreter-0.1.10.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
18
- dshellinterpreter-0.1.10.dist-info/RECORD,,