async def load_dev(self, ctx: commands.Context, replace_mock: Optional[str] = None): """ Dynamically loads dev cog `[replace_mock]` the replacement command name for `[p]mock` If nothing is provided this will not replace `[p]mock`. """ dev = Dev() # log.debug(dir(dev)) # return if not replace_mock: replace_mock = await self.config.replace_mock() if replace_mock: for command in dev.walk_commands(): if command.name == "mock": del dev.all_commands[str(command)] command.name = replace_mock dev.all_commands[replace_mock] = command log.debug(command.name) self.bot.remove_cog("Dev") # remove currently existing dev cog if it's loaded self.bot.add_cog(dev) await ctx.send( _("The following package was loaded: `{pack}`").format(pack="dev"))
async def initialize(self): replace_mock = await self.config.replace_mock() if await self.config.auto_load_dev(): dev = Dev() if replace_mock: for command in dev.walk_commands(): if command.name == "mock": del dev.all_commands[str(command)] command.name = replace_mock dev.all_commands[replace_mock] = command log.debug("Replaced Mock command") self.bot.remove_cog("Dev") self.bot.add_cog(dev)
async def on_command_error(self, ctx, error, unhandled_by_cog=False): if isinstance(error, commands.CommandInvokeError): # let me know if you want that generate error ticket ID feature here # logging and stuff is straight out of events.py to make sure those # still occur for this error type cmd = ctx.command log.exception(f"Exception in command '{cmd.qualified_name}'", exc_info=error.original) exception_log = f"Exception in command '{cmd.qualified_name}'\n" exception_log += "".join( traceback.format_exception(type(error), error, error.__traceback__) ) ctx.bot._last_exception = exception_log eh_cog = ctx.bot.get_cog("ErrorHandler") if eh_cog._eval_string is None: eh_cog._eval_string = await eh_cog.config.response() # redbot.core.dev_commands L186 helped a bunch here # also could probably use locals() here but don't care env = { 'ctx': ctx, 'error': error, 'discord': discord, 'cf': cf } to_compile = "async def func():\n%s" % textwrap.indent(eh_cog._eval_string, " ") try: compiled = Dev.async_compile(to_compile, "<string>", "exec") exec(compiled, env) except SyntaxError as e: return await ctx.send(Dev.get_syntax_error(e)) func = env["func"] await func() return await self._old_handler(ctx, error, unhandled_by_cog)
async def set_handler(self, ctx, *, code): """ Set the string to evaluate, use a python code block. Environment variables: cf - redbot.core.utils.chat_formatting module ctx - context of invokation error - the error that was raised discord - discord.py library """ body = Dev.cleanup_code(code) await self.config.response.set(value=body) await ctx.send(f"Handler code set to\n```py\n{body}\n```\nIt's recommended that you test the handler by running `{ctx.prefix}errorhandler test`") self._eval_string = body
def main(): description = "Bot Base - Version {}".format(__version__) cli_flags = parse_cli_flags(sys.argv[1:]) if cli_flags.list_instances: list_instances() elif cli_flags.version: print(description) sys.exit(0) elif not cli_flags.instance_name and not cli_flags.no_instance: print("Error: No instance name was provided!") sys.exit(1) if cli_flags.no_instance: print( "\033[1m" "Warning: The data will be placed in a temporary folder and removed on next system " "reboot." "\033[0m") cli_flags.instance_name = "temporary_red" create_temp_config() load_basic_configuration(cli_flags.instance_name) log = init_loggers(cli_flags) loop = asyncio.get_event_loop() red = Red(cli_flags=cli_flags, description=description, pm_help=None) init_global_checks(red) init_events(red, cli_flags) loop.run_until_complete(red.cog_mgr.initialize()) red.add_cog(Core(red)) red.add_cog(CogManagerUI()) if cli_flags.dev: red.add_cog(Dev()) # noinspection PyProtectedMember modlog._init() # noinspection PyProtectedMember bank._init() if os.name == "posix": loop.add_signal_handler( SIGTERM, lambda: asyncio.ensure_future(sigterm_handler(red, log))) tmp_data = {} loop.run_until_complete(_get_prefix_and_token(red, tmp_data)) token = os.environ.get("RED_TOKEN", tmp_data["token"]) if cli_flags.token: token = cli_flags.token prefix = cli_flags.prefix or tmp_data["prefix"] if not (token and prefix): if cli_flags.no_prompt is False: new_token = interactive_config(red, token_set=bool(token), prefix_set=bool(prefix)) if new_token: token = new_token else: log.critical("Token and prefix must be set in order to login.") sys.exit(1) loop.run_until_complete(_get_prefix_and_token(red, tmp_data)) if cli_flags.dry_run: loop.run_until_complete(red.http.close()) sys.exit(0) try: loop.run_until_complete(red.start(token, bot=True)) except discord.LoginFailure: log.critical("This token doesn't seem to be valid.") db_token = loop.run_until_complete(red.db.token()) if db_token and not cli_flags.no_prompt: print("\nDo you want to reset the token? (y/n)") if confirm("> "): loop.run_until_complete(red.db.token.set("")) print("Token has been reset.") except KeyboardInterrupt: log.info("Keyboard interrupt detected. Quitting...") loop.run_until_complete(red.logout()) red._shutdown_mode = ExitCodes.SHUTDOWN except Exception as e: log.critical("Fatal exception", exc_info=e) loop.run_until_complete(red.logout()) finally: pending = asyncio.Task.all_tasks(loop=red.loop) gathered = asyncio.gather(*pending, loop=red.loop, return_exceptions=True) gathered.cancel() try: loop.run_until_complete(red.rpc.close()) except AttributeError: pass sys.exit(red._shutdown_mode.value)