dshellInterpreter 0.1.9__tar.gz → 0.1.11__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 (26) hide show
  1. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/DISCORD_COMMANDS/__init__.py +1 -0
  2. dshellinterpreter-0.1.11/Dshell/DISCORD_COMMANDS/dshell_channel.py +93 -0
  3. dshellinterpreter-0.1.11/Dshell/DISCORD_COMMANDS/dshell_member.py +54 -0
  4. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/DISCORD_COMMANDS/dshell_message.py +7 -7
  5. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellInterpreteur/dshell_interpreter.py +90 -63
  6. dshellinterpreter-0.1.11/Dshell/_DshellParser/ast_nodes.py +317 -0
  7. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellParser/dshell_parser.py +3 -1
  8. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_keywords.py +10 -8
  9. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_token_type.py +1 -1
  10. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_tokenizer.py +3 -2
  11. {dshellinterpreter-0.1.9/dshellInterpreter.egg-info → dshellinterpreter-0.1.11}/PKG-INFO +1 -1
  12. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11/dshellInterpreter.egg-info}/PKG-INFO +1 -1
  13. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/SOURCES.txt +1 -0
  14. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/setup.py +1 -1
  15. dshellinterpreter-0.1.9/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -64
  16. dshellinterpreter-0.1.9/Dshell/_DshellParser/ast_nodes.py +0 -214
  17. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellInterpreteur/__init__.py +0 -0
  18. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellParser/__init__.py +0 -0
  19. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/__init__.py +0 -0
  20. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/Dshell/__init__.py +0 -0
  21. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/LICENSE +0 -0
  22. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/README.md +0 -0
  23. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
  24. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/requires.txt +0 -0
  25. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/top_level.txt +0 -0
  26. {dshellinterpreter-0.1.9 → dshellinterpreter-0.1.11}/setup.cfg +0 -0
@@ -1,2 +1,3 @@
1
1
  from .dshell_channel import *
2
2
  from .dshell_message import *
3
+ from .dshell_member import *
@@ -0,0 +1,93 @@
1
+ from asyncio import sleep
2
+ from re import search
3
+ from typing import Union
4
+
5
+ from discord import MISSING, PermissionOverwrite, Member, Role
6
+ from discord.abc import GuildChannel
7
+
8
+ __all__ = [
9
+ 'dshell_create_text_channel',
10
+ 'dshell_delete_channel',
11
+ 'dshell_delete_channels',
12
+ 'dshell_create_voice_channel'
13
+ ]
14
+
15
+
16
+ async def dshell_create_text_channel(ctx: GuildChannel,
17
+ name,
18
+ category=None,
19
+ position=MISSING,
20
+ slowmode=MISSING,
21
+ topic=MISSING, nsfw=MISSING,
22
+ permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
23
+ reason=None):
24
+ """
25
+ Creates a text channel on the server
26
+ """
27
+
28
+ channel_category = ctx.guild.get_channel(category)
29
+
30
+ created_channel = await ctx.guild.create_text_channel(name,
31
+ category=channel_category,
32
+ position=position,
33
+ slowmode_delay=slowmode,
34
+ topic=topic,
35
+ nsfw=nsfw,
36
+ overwrites=permission,
37
+ reason=reason)
38
+
39
+ return created_channel.id
40
+
41
+ async def dshell_create_voice_channel(ctx: GuildChannel,
42
+ name,
43
+ category=None,
44
+ position=MISSING,
45
+ bitrate=MISSING,
46
+ permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
47
+ reason=None):
48
+ """
49
+ Creates a voice channel on the server
50
+ """
51
+
52
+ channel_category = ctx.guild.get_channel(category)
53
+
54
+ created_channel = await ctx.guild.create_voice_channel(name,
55
+ category=channel_category,
56
+ position=position,
57
+ bitrate=bitrate,
58
+ overwrites=permission,
59
+ reason=reason)
60
+
61
+ return created_channel.id
62
+
63
+
64
+ async def dshell_delete_channel(ctx: GuildChannel, channel=None, reason=None, timeout=0):
65
+ """
66
+ Deletes a channel.
67
+ You can add a waiting time before it is deleted (in seconds)
68
+ """
69
+
70
+ channel_to_delete = ctx if channel is None else ctx.guild.get_channel(channel)
71
+
72
+ if channel_to_delete is None:
73
+ raise Exception(f"Le channel {channel} n'existe pas !")
74
+
75
+ await sleep(timeout)
76
+
77
+ await channel_to_delete.delete(reason=reason)
78
+
79
+ return channel_to_delete.id
80
+
81
+
82
+ async def dshell_delete_channels(ctx: GuildChannel, name=None, regex=None, reason=None):
83
+ """
84
+ Deletes all channels with the same name and/or matching the same regex.
85
+ If neither is set, it will delete all channels with the same name as the one where the command was executed.
86
+ """
87
+ for channel in ctx.guild.channels:
88
+
89
+ if name is not None and channel.name == str(name):
90
+ await channel.delete(reason=reason)
91
+
92
+ elif regex is not None and search(regex, channel.name):
93
+ await channel.delete(reason=reason)
@@ -0,0 +1,54 @@
1
+ from discord import Member, User, MISSING
2
+ from discord.abc import GuildChannel
3
+
4
+
5
+ __all__ = [
6
+ "dshell_ban_member",
7
+ "dshell_unban_member",
8
+ "dshell_kick_member"
9
+ ]
10
+
11
+ async def dshell_ban_member(ctx: GuildChannel, member: int, reason: str = MISSING):
12
+ """
13
+ Bans a member from the server.
14
+ """
15
+ banned_member = ctx.guild.get_member(member)
16
+
17
+ if not banned_member:
18
+ return 1 # Member not found in the server
19
+
20
+ await ctx.guild.ban(banned_member, reason=reason)
21
+
22
+ return banned_member.id
23
+
24
+ async def dshell_unban_member(ctx: GuildChannel, user: int, reason: str = MISSING):
25
+ """
26
+ Unbans a user from the server.
27
+ """
28
+ banned_users = ctx.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.guild.unban(user_to_unban, reason=reason)
40
+
41
+ return user_to_unban.id
42
+
43
+ async def dshell_kick_member(ctx: GuildChannel, member: int, reason: str = MISSING):
44
+ """
45
+ Kicks a member from the server.
46
+ """
47
+ kicked_member = ctx.guild.get_member(member)
48
+
49
+ if not kicked_member:
50
+ return 1 # Member not found in the server
51
+
52
+ await ctx.guild.kick(kicked_member, reason=reason)
53
+
54
+ return kicked_member.id
@@ -11,12 +11,12 @@ __all__ = [
11
11
  async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, channel=None, embeds=None, embed=None):
12
12
  from .._DshellParser.ast_nodes import ListNode
13
13
  """
14
- Envoie un message sur Discord
14
+ Sends a message on Discord
15
15
  """
16
16
  channel_to_send = ctx if channel is None else ctx.guild.get_channel(channel)
17
17
 
18
18
  if channel_to_send is None:
19
- raise Exception(f'Le channel {channel} est introuvable !')
19
+ raise Exception(f'Channel {channel} not found!')
20
20
 
21
21
  if embeds is None:
22
22
  embeds = ListNode([])
@@ -36,25 +36,25 @@ async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, chan
36
36
 
37
37
  async def dshell_delete_message(ctx: GuildChannel, message, reason=None, delay=0):
38
38
  """
39
- Supprime un message
39
+ Deletes a message
40
40
  """
41
41
 
42
- delete_message = ctx.get_partial_message(message) # construit une référence au message (même s'il n'existe pas)
42
+ delete_message = ctx.get_partial_message(message) # builds a reference to the message (even if it doesn't exist)
43
43
 
44
44
  if delay > 3600:
45
- raise Exception(f'Le délait de suppression du message est trop grand ! ({delay} secondes)')
45
+ raise Exception(f'The message deletion delay is too long! ({delay} seconds)')
46
46
 
47
47
  await delete_message.delete(delay=delay, reason=reason)
48
48
 
49
49
 
50
50
  async def dshell_purge_message(ctx: GuildChannel, message_number, channel=None, reason=None):
51
51
  """
52
- Purge les messages d'un salon
52
+ Purges messages from a channel
53
53
  """
54
54
 
55
55
  purge_channel = ctx if channel is None else ctx.guild.get_channel(channel)
56
56
 
57
57
  if purge_channel is None:
58
- raise Exception(f"Le salon {channel} à purgé est introuvable !")
58
+ raise Exception(f"Channel {channel} to purge not found!")
59
59
 
60
60
  await purge_channel.purge(limit=message_number, reason=reason)
@@ -2,6 +2,7 @@ from asyncio import sleep
2
2
  from re import findall
3
3
  from typing import TypeVar, Union, Any, Optional, Callable
4
4
 
5
+
5
6
  from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role
6
7
  from discord.abc import GuildChannel, PrivateChannel
7
8
 
@@ -18,12 +19,17 @@ context = TypeVar('context', AutoShardedBot, GuildChannel, PrivateChannel)
18
19
 
19
20
 
20
21
  class DshellInterpreteur:
22
+ """
23
+ Discord Dshell interpreter.
24
+ Make what you want with Dshell code to interact with Discord !
25
+ """
21
26
 
22
- 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):
23
28
  """
24
- 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.
25
31
  """
26
- self.ast: list[ASTNode] = parse(DshellTokenizer(ast_or_code).start(), StartNode([]))[0]
32
+ self.ast: list[ASTNode] = parse(DshellTokenizer(code).start(), StartNode([]))[0]
27
33
  self.env: dict[str, Any] = {}
28
34
  self.ctx: context = ctx
29
35
  if debug:
@@ -31,7 +37,16 @@ class DshellInterpreteur:
31
37
 
32
38
  async def execute(self, ast: Optional[list[All_nodes]] = None):
33
39
  """
34
- 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.
35
50
  """
36
51
  if ast is None:
37
52
  ast = self.ast
@@ -90,19 +105,20 @@ class DshellInterpreteur:
90
105
  elif isinstance(node, SleepNode):
91
106
  sleep_time = eval_expression(node.body, self)
92
107
  if sleep_time > 3600:
93
- 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)")
94
109
  elif sleep_time < 1:
95
- 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)")
96
111
 
97
112
  await sleep(sleep_time)
98
113
 
99
114
 
100
115
  elif isinstance(node, EndNode):
101
- raise RuntimeError(f"Execution interromput -> #end atteint")
116
+ raise RuntimeError("Execution stopped - EndNode encountered")
102
117
 
103
118
  def eval_data_token(self, token: Token):
104
119
  """
105
- Evalue les tokens de data
120
+ Eval a data token and returns its value in Python.
121
+ :param token: The token to evaluate.
106
122
  """
107
123
 
108
124
  if not hasattr(token, 'type'):
@@ -135,7 +151,9 @@ class DshellInterpreteur:
135
151
 
136
152
  def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) -> Token:
137
153
  """
138
- 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.
139
157
  """
140
158
  if eval_expression(if_node.condition, interpreter):
141
159
  return eval_expression(if_node.body, interpreter)
@@ -145,7 +163,9 @@ def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) ->
145
163
 
146
164
  def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any:
147
165
  """
148
- 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.
149
169
  """
150
170
  postfix = to_postfix(tokens)
151
171
  stack = []
@@ -170,24 +190,28 @@ def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any
170
190
  stack.append(result)
171
191
 
172
192
  else:
173
- raise SyntaxError(f"Token inattendu en condition: {token}")
193
+ raise SyntaxError(f"Unexpected token type: {token.type} - {token.value}")
174
194
 
175
195
  if len(stack) != 1:
176
- raise SyntaxError("Condition mal formée")
196
+ raise SyntaxError("Invalid expression: stack should contain exactly one element after evaluation.")
177
197
 
178
198
  return stack[0]
179
199
 
180
200
 
181
201
  async def call_function(function: Callable, args: ArgsCommandNode, interpreter: DshellInterpreteur):
182
202
  """
183
- 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.
184
208
  """
185
209
  reformatted = regroupe_commandes(args.body, interpreter)[0]
186
210
 
187
211
  # conversion des args en valeurs Python
188
212
  absolute_args = reformatted.pop('*', list())
189
213
 
190
- reformatted: dict[str, Token] # ne sert à rien, juste à indiquer ce qu'il contient dorénanvant
214
+ reformatted: dict[str, Token]
191
215
 
192
216
  absolute_args.insert(0, interpreter.ctx)
193
217
  keyword_args = {
@@ -198,64 +222,69 @@ async def call_function(function: Callable, args: ArgsCommandNode, interpreter:
198
222
 
199
223
  def regroupe_commandes(body: list[Token], interpreter: DshellInterpreteur) -> list[dict[str, list[Any]]]:
200
224
  """
201
- Regroupe les arguments de la commande sous la forme d'un dictionnaire python.
202
- 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 !
203
- Les paramètres non obligatoire seront stocké dans une liste sous la forme de tokens avec comme clé '*'.
204
- 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.
205
234
  """
206
- tokens = {'*': []} # les tokens à renvoyer
207
- 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
208
237
  n = len(body)
209
238
  list_tokens: list[dict] = [tokens]
210
239
 
211
240
  i = 0
212
241
  while i < n:
213
242
  if body[i].type == DTT.SEPARATOR and body[
214
- i + 1].type == DTT.IDENT: # On regarde si c'est un séparateur et si le token suivant est un IDENT
215
- current_arg = body[i + 1].value # on change l'argument actuel. Il sera donc impossible de revenir à l'*
216
- tokens[current_arg] = '' # on lui crée une paire clé/valeur
217
- 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
218
247
 
219
248
  elif body[
220
- 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
221
250
  list_tokens += regroupe_commandes(
222
251
  [Token(
223
252
  type_=DTT.SEPARATOR, value=body[i].value, position=body[i].position)
224
253
  ] + body[i + 1:], interpreter
225
- ) # on ajoute un sous-dictionnaire pour les sous-commandes
254
+ ) # add a sub-dictionary for sub-commands
226
255
  return list_tokens
227
256
 
228
257
  else:
229
258
  if current_arg == '*':
230
259
  tokens[current_arg].append(interpreter.eval_data_token(body[i]))
231
260
  else:
232
- 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
233
262
  i += 1
234
263
  return list_tokens
235
264
 
236
265
 
237
266
  def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: DshellInterpreteur) -> Embed:
238
267
  """
239
- Construit un embed à partir des informations de la commande.
268
+ Builds an embed from the command information.
240
269
  """
241
270
  args_main_embed: dict[str, list[Any]] = regroupe_commandes(body, interpreter)[0]
242
- args_main_embed.pop('*') # on enlève les paramètres non spécifié pour l'embed
243
- 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
244
273
 
245
274
  args_fields: list[dict[str, Token]] = []
246
- 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
247
276
  a = regroupe_commandes(field.body, interpreter)[0]
248
277
  a.pop('*')
249
278
  a: dict[str, Token]
250
279
  args_fields.append(a)
251
280
 
252
281
  if 'color' in args_main_embed and isinstance(args_main_embed['color'],
253
- 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
254
283
  args_main_embed['color'] = Colour.from_rgb(*args_main_embed['color'])
255
284
 
256
- embed = Embed(**args_main_embed) # on construit l'embed principal
285
+ embed = Embed(**args_main_embed) # build the main embed
257
286
  for field in args_fields:
258
- embed.add_field(**field) # on joute tous les fields
287
+ embed.add_field(**field) # add all fields
259
288
 
260
289
  return embed
261
290
 
@@ -263,7 +292,7 @@ def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: Ds
263
292
  def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict[
264
293
  Union[Member, Role], PermissionOverwrite]:
265
294
  """
266
- Construit un dictionnaire de permissions à partir des informations de la commande.
295
+ Builds a dictionary of PermissionOverwrite objects from the command information.
267
296
  """
268
297
  args_permissions: list[dict[str, list[Any]]] = regroupe_commandes(body, interpreter)
269
298
  permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
@@ -272,12 +301,12 @@ def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict
272
301
  i.pop('*')
273
302
  permissions.update(DshellPermissions(i).get_permission_overwrite(interpreter.ctx.guild))
274
303
 
275
- print(args_permissions)
304
+ return permissions
276
305
 
277
306
 
278
307
  class DshellIterator:
279
308
  """
280
- Utilisé pour transformer n'importe quoi en un iterable
309
+ Used to transform anything into an iterable
281
310
  """
282
311
 
283
312
  def __init__(self, data):
@@ -301,20 +330,20 @@ class DshellPermissions:
301
330
 
302
331
  def __init__(self, target: dict[str, list[int]]):
303
332
  """
304
- Permet de créer un objet de permissions Dshell.
305
- :param target: Un dictionnaire contenant les paramètres et leurs valeurs.
306
- Paramètres attendus : "allow", "deny", "members", "roles".
307
- 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.
308
337
  """
309
338
  self.target: dict[str, Union[ListNode, int]] = target
310
339
 
311
340
  @staticmethod
312
341
  def get_instance(guild: Guild, target_id: int) -> Union[Member, Role]:
313
342
  """
314
- Retourne l'instance correspondante à l'id donné. Uniquement un Member ou un Role.
315
- :param guild: Le serveur Discord dans lequel chercher
316
- :param target_id: L'ID du membre ou du rôle
317
- :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
318
347
  """
319
348
  try:
320
349
  member = DshellPermissions.get_member(guild, target_id)
@@ -332,48 +361,46 @@ class DshellPermissions:
332
361
  if role is not None:
333
362
  return role
334
363
 
335
- raise ValueError(f"Aucun membre ou rôle trouvé avec l'ID {target_id} dans le serveur {guild.name}.")
336
-
337
364
  @staticmethod
338
365
  def get_member(guild: Guild, target_id: int) -> Member:
339
366
  """
340
- Retourne l'instance de Member correspondante à l'id donné.
341
- :param guild: Le serveur Discord dans lequel chercher
342
- :param target_id: L'ID du membre
343
- :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
344
371
  """
345
372
  member = guild.get_member(target_id)
346
373
  if member is not None:
347
374
  return member
348
375
 
349
- 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}.")
350
377
 
351
378
  @staticmethod
352
379
  def get_role(guild: Guild, target_id: int) -> Role:
353
380
  """
354
- Retourne l'instance de Role correspondante à l'id donné.
355
- :param guild: Le serveur Discord dans lequel chercher
356
- :param target_id: L'ID du rôle
357
- :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
358
385
  """
359
386
  role = guild.get_role(target_id)
360
387
  if role is not None:
361
388
  return role
362
389
 
363
- 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}.")
364
391
 
365
392
  def get_permission_overwrite(self, guild: Guild) -> dict[Union[Member, Role], PermissionOverwrite]:
366
393
  """
367
- Retourne un objet PermissionOverwrite avec les permissions des membres et rôles.
368
- :param guild: Le serveur Discord
369
- :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
370
397
  """
371
398
  permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
372
399
  target_keys = self.target.keys()
373
400
 
374
401
  if 'members' in target_keys:
375
402
  for member_id in (
376
- 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
377
404
  member = self.get_member(guild, member_id)
378
405
  permissions[member] = PermissionOverwrite.from_pair(
379
406
  allow=Permissions(permissions=self.target.get('allow', 0)),
@@ -382,13 +409,13 @@ class DshellPermissions:
382
409
 
383
410
  elif 'roles' in target_keys:
384
411
  for role_id in (
385
- 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
386
413
  role = self.get_role(guild, role_id)
387
414
  permissions[role] = PermissionOverwrite.from_pair(
388
415
  allow=Permissions(permissions=self.target.get('allow', 0)),
389
416
  deny=Permissions(permissions=self.target.get('deny', 0))
390
417
  )
391
418
  else:
392
- raise ValueError("Aucun membre ou rôle spécifié dans les permissions.")
419
+ raise ValueError("No members or roles specified in the permissions target.")
393
420
 
394
421
  return permissions