dshellInterpreter 0.1.10__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.10 → 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.10 → dshellinterpreter-0.1.11}/Dshell/DISCORD_COMMANDS/dshell_message.py +7 -7
  5. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellInterpreteur/dshell_interpreter.py +88 -63
  6. dshellinterpreter-0.1.11/Dshell/_DshellParser/ast_nodes.py +317 -0
  7. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellParser/dshell_parser.py +3 -1
  8. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_keywords.py +10 -8
  9. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_token_type.py +1 -1
  10. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/dshell_tokenizer.py +3 -2
  11. {dshellinterpreter-0.1.10/dshellInterpreter.egg-info → dshellinterpreter-0.1.11}/PKG-INFO +1 -1
  12. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11/dshellInterpreter.egg-info}/PKG-INFO +1 -1
  13. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/SOURCES.txt +1 -0
  14. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/setup.py +1 -1
  15. dshellinterpreter-0.1.10/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -64
  16. dshellinterpreter-0.1.10/Dshell/_DshellParser/ast_nodes.py +0 -214
  17. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellInterpreteur/__init__.py +0 -0
  18. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellParser/__init__.py +0 -0
  19. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/_DshellTokenizer/__init__.py +0 -0
  20. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/Dshell/__init__.py +0 -0
  21. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/LICENSE +0 -0
  22. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/README.md +0 -0
  23. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
  24. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/requires.txt +0 -0
  25. {dshellinterpreter-0.1.10 → dshellinterpreter-0.1.11}/dshellInterpreter.egg-info/top_level.txt +0 -0
  26. {dshellinterpreter-0.1.10 → 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)
@@ -1,7 +1,6 @@
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
6
  from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role
@@ -20,12 +19,17 @@ context = TypeVar('context', AutoShardedBot, GuildChannel, 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,7 +292,7 @@ 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] = {}
@@ -279,7 +306,7 @@ def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict
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