@@ -76,8 +76,6 @@ def override_remove_cog(name: str):
7676 self .remove_cog_commands (cog )
7777 default_remove_function (name )
7878 self ._discord .remove_cog = override_remove_cog
79-
80-
8179
8280 def get_cog_commands (self , cog : commands .Cog ):
8381 """
@@ -608,7 +606,7 @@ def wrapper(cmd):
608606
609607 return wrapper
610608
611- async def process_options (self , guild : discord .Guild , options : list , auto_convert : dict ) -> list :
609+ async def process_options (self , guild : discord .Guild , options : list , auto_convert : dict ) -> typing . Union [ list , dict ] :
612610 """
613611 Processes Role, User, and Channel option types to discord.py's models.
614612
@@ -618,7 +616,7 @@ async def process_options(self, guild: discord.Guild, options: list, auto_conver
618616 :type options: list
619617 :param auto_convert: Dictionary of how to convert option values.
620618 :type auto_convert: dict
621- :return: list
619+ :return: Union[ list, dict]
622620 """
623621 if not guild :
624622 self .logger .info ("This command invoke is missing guild. Skipping option process." )
@@ -631,6 +629,9 @@ async def process_options(self, guild: discord.Guild, options: list, auto_conver
631629 return [x ["value" ] for x in options ]
632630
633631 converters = [
632+ # If extra converters are added and some needs to fetch it,
633+ # you should pass as a list with 1st item as a cache get method
634+ # and 2nd as a actual fetching method.
634635 [guild .get_member , guild .fetch_member ],
635636 guild .get_channel ,
636637 guild .get_role
@@ -654,30 +655,58 @@ async def process_options(self, guild: discord.Guild, options: list, auto_conver
654655 "8" : 2
655656 }
656657
657- to_return = []
658+ to_return = {}
658659
659660 for x in options :
660661 selected = x
661662 if selected ["name" ] in auto_convert :
663+ processed = None # This isn't the best way, but we should to reduce duplicate lines.
662664 if auto_convert [selected ["name" ]] not in types :
663- to_return .append (selected ["value" ])
664- continue
665- loaded_converter = converters [types [auto_convert [selected ["name" ]]]]
666- if isinstance (loaded_converter , list ):
667- cache_first = loaded_converter [0 ](int (selected ["value" ]))
668- if cache_first :
669- to_return .append (cache_first )
670- continue
671- loaded_converter = loaded_converter [1 ]
672- try :
673- to_return .append (await loaded_converter (int (selected ["value" ]))) \
674- if iscoroutinefunction (loaded_converter ) else \
675- to_return .append (loaded_converter (int (selected ["value" ])))
676- except (discord .Forbidden , discord .HTTPException ):
677- self .logger .warning ("Failed fetching user! Passing ID instead." )
678- to_return .append (int (selected ["value" ]))
665+ processed = selected ["value" ]
666+ else :
667+ loaded_converter = converters [types [auto_convert [selected ["name" ]]]]
668+ if isinstance (loaded_converter , list ): # For user type.
669+ cache_first = loaded_converter [0 ](int (selected ["value" ]))
670+ if cache_first :
671+ processed = cache_first
672+ else :
673+ loaded_converter = loaded_converter [1 ]
674+ if not processed :
675+ try :
676+ processed = await loaded_converter (int (selected ["value" ])) \
677+ if iscoroutinefunction (loaded_converter ) else \
678+ loaded_converter (int (selected ["value" ]))
679+ except (discord .Forbidden , discord .HTTPException , discord .NotFound ): # Just in case.
680+ self .logger .warning ("Failed fetching discord object! Passing ID instead." )
681+ processed = int (selected ["value" ])
682+ to_return [selected ["name" ]] = processed
683+ else :
684+ to_return [selected ["name" ]] = selected ["value" ]
679685 return to_return
680686
687+ async def invoke_command (self , func , ctx , args ):
688+ """
689+ Invokes command.
690+
691+ :param func: Command coroutine.
692+ :param ctx: Context.
693+ :param args: Args. Can be list or dict.
694+ """
695+ try :
696+ not_kwargs = False
697+ if isinstance (args , dict ):
698+ try :
699+ await func .invoke (ctx , ** args )
700+ except TypeError :
701+ args = list (args .values ())
702+ not_kwargs = True
703+ else :
704+ not_kwargs = True
705+ if not_kwargs :
706+ await func .invoke (ctx , * args )
707+ except Exception as ex :
708+ await self .on_slash_command_error (ctx , ex )
709+
681710 async def on_socket_response (self , msg ):
682711 """
683712 This event listener is automatically registered at initialization of this class.
@@ -721,10 +750,7 @@ async def on_socket_response(self, msg):
721750
722751 self ._discord .dispatch ("slash_command" , ctx )
723752
724- try :
725- await selected_cmd .invoke (ctx , * args )
726- except Exception as ex :
727- await self .on_slash_command_error (ctx , ex )
753+ await self .invoke_command (selected_cmd , ctx , args )
728754
729755 async def handle_subcommand (self , ctx : context .SlashContext , data : dict ):
730756 """
@@ -755,19 +781,13 @@ async def handle_subcommand(self, ctx: context.SlashContext, data: dict):
755781 args = await self .process_options (ctx .guild , x ["options" ], selected .auto_convert ) \
756782 if "options" in x else []
757783 self ._discord .dispatch ("slash_command" , ctx )
758- try :
759- await selected .invoke (ctx , * args )
760- except Exception as ex :
761- await self .on_slash_command_error (ctx , ex )
784+ await self .invoke_command (selected , ctx , args )
762785 return
763786 selected = base [sub_name ]
764787 args = await self .process_options (ctx .guild , sub_opts , selected .auto_convert ) \
765788 if "options" in sub else []
766789 self ._discord .dispatch ("slash_command" , ctx )
767- try :
768- await selected .invoke (ctx , * args )
769- except Exception as ex :
770- await self .on_slash_command_error (ctx , ex )
790+ await self .invoke_command (selected , ctx , args )
771791
772792 async def on_slash_command_error (self , ctx , ex ):
773793 """
0 commit comments