async def git(self, ctx: commands.Context, pull_push, *, commit_msg=None): """ Executes git statements in the system shell. This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise. Execution can be cancelled by closing the paginator. """ if pull_push == "push": shellcmd = f'sudo git add .&&sudo git commit -m "{commit_msg}"&&sudo git push' if pull_push == "pull": shellcmd = 'sudo git pull' if pull_push not in ['pull', 'push']: return await ctx.send("Invalid option given") async with ReplResponseReactor(ctx.message): paginator = WrappedPaginator(prefix="```sh", max_size=1985) paginator.add_line(f"$ git {pull_push}\n") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) self.bot.loop.create_task(interface.send_to(ctx)) if commit_msg is None: commit_msg = "File changes" with ShellReader(shellcmd) as reader: async for line in reader: if interface.closed: return await interface.add_line(line)
async def jsk_shell(self, ctx: commands.Context, *, argument: codeblock_converter): """ Executes statements in the system shell. This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise. Execution can be cancelled by closing the paginator. """ async with ReplResponseReactor(ctx.message): with self.submit(ctx): with ShellReader(argument.content) as reader: prefix = "```" + reader.highlight paginator = WrappedPaginator(prefix=prefix, max_size=1975) paginator.add_line(f"{reader.ps1} {argument.content}\n") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) self.bot.loop.create_task(interface.send_to(ctx)) async for line in reader: if interface.closed: return await interface.add_line(line) await interface.add_line( f"\n[status] Return code {reader.close_code}")
async def git(self, ctx, pull_push, *, message=None): """ Executes git statements in the system shell. This uses the system shell as defined in $SHELL, or `/bin/bash` otherwise. Execution can be cancelled by closing the paginator. """ message = message if message is not None else "Updated files." if pull_push == "push": shellcmd = f'sudo git add .&&sudo git commit -m "{message}"&&sudo git push' elif pull_push == "pull": shellcmd = 'sudo git pull' else: return await ctx.send("Invalid option given") async with ReplResponseReactor(ctx.message): paginator = WrappedPaginator(prefix="```sh", max_size=1985) paginator.add_line(f"$ git {pull_push}\n") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) self.bot.loop.create_task(interface.send_to(ctx)) with ShellReader(shellcmd) as reader: async for line in reader: if interface.closed: return await interface.add_line(line)
async def emoji(self, ctx, *, search: str = None): lists = [] paginator = WrappedPaginator(max_size=500, prefix="", suffix="") if search != None: emojis = finder(search, self.bot.emojis, key=lambda i: i.name, lazy=False) if emojis == []: return await ctx.send("no emoji found") for i in emojis: if i.animated == True: lists.append(f"{str(i)} `<a:{i.name}:{i.id}>`") else: lists.append(f"{str(i)} `<:{i.name}:{i.id}>`") paginator.add_line("\n".join(lists)) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx) for i in self.bot.emojis: if i.animated == True: lists.append(f"{str(i)} `<a:{i.name}:{i.id}>`") else: lists.append(f"{str(i)} `<:{i.name}:{i.id}>`") paginator.add_line("\n".join(lists)) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_curl(self, ctx: commands.Context, url: str): """ Download and display a text file from the internet. This command is similar to jsk cat, but accepts a URL. """ # remove embed maskers if present url = url.lstrip("<").rstrip(">") async with ReplResponseReactor(ctx.message): async with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.read() hints = ( response.content_type, url ) code = response.status if not data: return await ctx.send(f"HTTP response was empty (status code {code}).") try: paginator = WrappedFilePaginator(io.BytesIO(data), language_hints=hints, max_size=1985) except UnicodeDecodeError: return await ctx.send(f"Couldn't determine the encoding of the response. (status code {code})") except ValueError as exc: return await ctx.send(f"Couldn't read response (status code {code}), {exc}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def send_pages(self): destination = self.get_destination() interface = PaginatorInterface(self.context.bot, self.paginator, owner=self.context.author) await interface.send_to(destination)
async def _lyrics(self, ctx: AnimeContext, *, name: str): paginator = commands.Paginator(max_size=500) lyrics = await self.get_lyrics(name) for i in lyrics.split("\n"): paginator.add_line(i) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def listguilds(self, ctx): if not self.bot.isadmin(ctx.author): return await ctx.error('no') data = [[ 'Name', 'ID', 'Members', 'Channels', 'Boosts', 'Shard', 'Public' ]] for guild in sorted(self.bot.guilds, key=lambda g: len(g.members), reverse=True): data.append([ shorten(guild.name), guild.id, format(len(guild.members), ',d'), len(guild.channels), guild.premium_subscription_count, guild.shard_id, 'PUBLIC' in guild.features ]) table = AsciiTable(data) header = table.table.split('\n')[:3] paginator = WrappedPaginator(prefix='```\n' + '\n'.join(header), suffix='```', max_size=1950) for ln in table.table.split('\n'): if ln not in header: paginator.add_line(ln) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx)
async def a(self, ctx: commands.Context, *, command_name: str): """ Displays the source code for a command. """ import inspect command = self.bot.get_command(command_name) if not command: return await ctx.send(f"Couldn't find command `{command_name}`.") try: source_lines, _ = inspect.getsourcelines(command.callback) except (TypeError, OSError): return await ctx.send( f"Was unable to retrieve the source for `{command}` for some reason." ) # getsourcelines for some reason returns WITH line endings source_lines = ''.join(source_lines).split('\n') paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985) for line in source_lines: paginator.add_line(line) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_python_inspect(self, ctx: commands.Context, *, argument: codeblock_converter): """ Evaluation of Python code with inspect information. """ arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX) arg_dict["_"] = self.last_result scope = self.scope try: async with ReplResponseReactor(ctx.message): with self.submit(ctx): executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict) async for send, result in AsyncSender(executor): self.last_result = result header = repr(result).replace("``", "`\u200b`").replace(self.bot.http.token, "[token omitted]") if len(header) > 485: header = header[0:482] + "..." paginator = WrappedPaginator(prefix=f"```prolog\n=== {header} ===\n", max_size=1985) for name, res in all_inspections(result): paginator.add_line(f"{name:16.16} :: {res}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) send(await interface.send_to(ctx)) finally: scope.clear_intersection(arg_dict)
async def jsk_python(self, ctx: commands.Context, *, argument: codeblock_converter): """ Direct evaluation of Python code. """ arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX) arg_dict["_"] = self.last_result scope = self.scope try: async with ReplResponseReactor(ctx.message): with self.submit(ctx): executor = AsyncCodeExecutor( argument.content, scope, arg_dict=arg_dict ) async for send, result in AsyncSender(executor): if result is None: continue self.last_result = result if isinstance(result, discord.File): send(await ctx.send(file=result)) elif isinstance(result, discord.Embed): send(await ctx.send(embed=result)) elif isinstance(result, PaginatorInterface): send(await result.send_to(ctx)) else: if not isinstance(result, str): # repr all non-strings result = repr(result) if len(result) > 2000: # inconsistency here, results get wrapped in codeblocks when they are too large # but don't if they're not. probably not that bad, but noting for later review paginator = WrappedPaginator( prefix="```py", suffix="```", max_size=1985 ) paginator.add_line(result) interface = PaginatorInterface( ctx.bot, paginator, owner=ctx.author ) send(await interface.send_to(ctx)) else: if result.strip() == "": result = "\u200b" send( await ctx.send( result.replace( self.bot.http.token, "[token omitted]", ) ) ) finally: scope.clear_intersection(arg_dict)
async def xp_lb(self, ctx): """Displays the xp leaderboard""" data = read("./data/level.json") users = {} for user in data.keys(): for guild in data[user].keys(): if users.get(user): try: users[user] += data[user][guild]['xp'] except KeyError: continue else: try: users[user] = data[user][guild]['xp'] except KeyError: pass sorted_keys = sorted(users.keys(), key=lambda a: users[a], reverse=True) paginator = PaginatorInterface( self.bot, commands.Paginator(max_size=1000, prefix='', suffix='')) for n, u in enumerate(sorted_keys, start=1): # await ctx.send(u) us = self.bot.get_user(int(u)) # await ctx.send(str(us)) mention = discord.utils.escape_markdown( discord.utils.escape_mentions( str(us))) if us else 'Unknown#0000' level = CustomConverters.level_converter(ctx, users[u]) await paginator.add_line( f"{n}. {mention}: {users[u]}xp (level {level})") return await paginator.send_to(ctx.channel)
async def jsk_disassemble(self, ctx: commands.Context, *, argument: codeblock_converter): """ Disassemble Python code into bytecode. """ arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX) async with ReplResponseReactor(ctx.message): text = "\n".join(disassemble(argument.content, arg_dict=arg_dict)) # Guild's advertised limit minus 1KiB for the HTTP content filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024 if len(text) < filesize_threshold: await ctx.send(file=discord.File( filename="dis.py", fp=io.BytesIO(text.encode('utf-8')) )) else: paginator = WrappedPaginator(prefix='```py', max_size=1985) paginator.add_line(text) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def source(self, ctx, *, command_name: str): """ Displays the source code for a command. """ command = self.bot.get_command(command_name) if not command: return await ctx.send(f"Couldn't find command `{command_name}`.") try: source_lines, _ = inspect.getsourcelines(command.callback) except (TypeError, OSError): return await ctx.send( f"Was unable to retrieve the source for `{command}` for some reason." ) # getsourcelines for some reason returns WITH line endings source_lines = "".join(source_lines).split("\n") paginator = WrappedPaginator(prefix="```py", suffix="```", max_size=1985) for num, line in enumerate(source_lines, start=1): paginator.add_line(f"{str(num)} {ctx.escape(line)}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_python_inspect(self, ctx: commands.Context, *, argument: codeblock_converter): """ Evaluation of Python code with inspect information. """ arg_dict = get_var_dict_from_ctx(ctx, Flags.SCOPE_PREFIX) arg_dict["_"] = self.last_result scope = self.scope try: async with ReplResponseReactor(ctx.message): with self.submit(ctx): executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict) async for send, result in AsyncSender(executor): self.last_result = result header = repr(result).replace("``", "`\u200b`").replace( self.bot.http.token, "[token omitted]") if len(header) > 485: header = header[0:482] + "..." lines = [f"=== {header} ===", ""] for name, res in all_inspections(result): lines.append(f"{name:16.16} :: {res}") docstring = (inspect.getdoc(result) or '').strip() if docstring: lines.append(f"\n=== Help ===\n\n{docstring}") text = "\n".join(lines) if use_file_check(ctx, len( text)): # File "full content" preview limit send(await ctx.send(file=discord.File( filename="inspection.prolog", fp=io.BytesIO(text.encode('utf-8'))))) else: paginator = WrappedPaginator(prefix="```prolog", max_size=1985) paginator.add_line(text) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) send(await interface.send_to(ctx)) finally: scope.clear_intersection(arg_dict)
async def jsk_cat(self, ctx: commands.Context, argument: str): # pylint: disable=too-many-locals """ Read out a file, using syntax highlighting if detected. Lines and linespans are supported by adding '#L12' or '#L12-14' etc to the end of the filename. """ match = self.__cat_line_regex.search(argument) if not match: # should never happen return await ctx.send("Couldn't parse this input.") path = match.group(1) line_span = None if match.group(2): start = int(match.group(2)) line_span = (start, int(match.group(3) or start)) if not os.path.exists(path) or os.path.isdir(path): return await ctx.send(f"`{path}`: No file by that name.") size = os.path.getsize(path) if size <= 0: return await ctx.send(f"`{path}`: Cowardly refusing to read a file with no size stat" f" (it may be empty, endless or inaccessible).") if size > 128 * (1024 ** 2): return await ctx.send(f"`{path}`: Cowardly refusing to read a file >128MB.") try: with open(path, "rb") as file: if use_file_check(ctx, size): if line_span: content, *_ = guess_file_traits(file.read()) lines = content.split('\n')[line_span[0] - 1:line_span[1]] await ctx.send(file=discord.File( filename=pathlib.Path(file.name).name, fp=io.BytesIO('\n'.join(lines).encode('utf-8')) )) else: await ctx.send(file=discord.File( filename=pathlib.Path(file.name).name, fp=file )) else: paginator = WrappedFilePaginator(file, line_span=line_span, max_size=1985) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx) except UnicodeDecodeError: return await ctx.send(f"`{path}`: Couldn't determine the encoding of this file.") except ValueError as exc: return await ctx.send(f"`{path}`: Couldn't read this file, {exc}")
async def servers(self, ctx): """Lists servers.""" paginator = PaginatorInterface(self.bot, commands.Paginator(prefix="```md", max_size=500)) for number, guild in enumerate(ctx.bot.guilds, start=1): dot = '\u200B.' backtick = '\u200B`' await paginator.add_line( discord.utils.escape_markdown(f'{number}) {guild.name.replace(".", dot).replace("`", backtick)}\n')) await paginator.send_to(ctx.channel)
async def jsk_curl(self, ctx: commands.Context, url: str): """ Download and display a text file from the internet. This command is similar to jsk cat, but accepts a URL. """ # remove embed maskers if present url = url.lstrip("<").rstrip(">") async with ReplResponseReactor(ctx.message): async with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.read() hints = (response.content_type, url) code = response.status if not data: return await ctx.send( f"HTTP response was empty (status code {code}).") # Guild's advertised limit minus 1KiB for the HTTP content filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024 if len(data) < filesize_threshold: # Shallow language detection language = None for hint in hints: language = get_language(hint) if language: break await ctx.send( file=discord.File(filename=f"response.{language or 'txt'}", fp=io.BytesIO(data))) else: try: paginator = WrappedFilePaginator(io.BytesIO(data), language_hints=hints, max_size=1985) except UnicodeDecodeError: return await ctx.send( f"Couldn't determine the encoding of the response. (status code {code})" ) except ValueError as exc: return await ctx.send( f"Couldn't read response (status code {code}), {exc}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def speedtest(self, ctx): async with ReplResponseReactor(ctx.message): with ShellReader("speedtest-cli") as reader: prefix = "```" + reader.highlight paginator = WrappedPaginator(prefix=prefix, max_size=1975) paginator.add_line(f"{reader.ps1} 'speedtest-cli'\n") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) self.bot.loop.create_task(interface.send_to(ctx)) async for line in reader: if interface.closed: return await interface.add_line(line) await interface.add_line( f"\n[status] Return code {reader.close_code}")
async def discordstatus(self, ctx): """ Shows discord's status """ paginator = commands.Paginator(max_size=500, prefix='```yaml', suffix='```') for i in await self.get_status(): paginator.add_line(i) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_python_result_handling(self, ctx: commands.Context, result): # pylint: disable=too-many-return-statements """ Determines what is done with a result when it comes out of jsk py. This allows you to override how this is done without having to rewrite the command itself. What you return is what gets stored in the temporary _ variable. """ if isinstance(result, discord.Message): return await ctx.send(f"<Message <{result.jump_url}>>") if isinstance(result, discord.File): return await ctx.send(file=result) if isinstance(result, discord.Embed): return await ctx.send(embed=result) if isinstance(result, PaginatorInterface): return await result.send_to(ctx) if not isinstance(result, str): # repr all non-strings result = repr(result) # Eventually the below handling should probably be put somewhere else if len(result) <= 2000: if result.strip() == '': result = "\u200b" return await ctx.send( result.replace(self.bot.http.token, "[token omitted]"), allowed_mentions=discord.AllowedMentions.none()) if use_file_check(ctx, len(result)): # File "full content" preview limit # Discord's desktop and web client now supports an interactive file content # display for files encoded in UTF-8. # Since this avoids escape issues and is more intuitive than pagination for # long results, it will now be prioritized over PaginatorInterface if the # resultant content is below the filesize threshold return await ctx.send(file=discord.File( filename="output.py", fp=io.BytesIO(result.encode('utf-8')))) # inconsistency here, results get wrapped in codeblocks when they are too large # but don't if they're not. probably not that bad, but noting for later review paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985) paginator.add_line(result) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx)
async def cache(self, ctx): """ tell you how many messages the bot have cached if you don't know what is cache then this is not the right command for you """ paginator = commands.Paginator(max_size=1000) lines = list(self.bot.cached_messages) lines.append( f"Total amount of messages cached {len(self.bot.cached_messages)}") for i in lines: i = str(i) paginator.add_line(i) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def eval(self, ctx, *, code: str): env = { "ctx": ctx, "author": ctx.author, "message": ctx.message, "guild": ctx.guild, "bot": self.bot, "reference": ctx.message.reference, "resolved": ctx.message.reference.resolved if ctx.message.reference else None, } env.update(globals()) imports = "import asyncio\n" "import discord\nfrom discord.ext import commands\nimport aiohttp\n" body = "async def func():\n" + textwrap.indent(imports + code, " ") try: import_expression.exec(body, env, locals()) except Exception as e: etype = type(e) trace = e.__traceback__ lines = traceback.format_exception(etype, e, trace) paginator = WrappedPaginator(max_size=500, prefix="A weird error occured```py", suffix="```") paginator.add_line("".join(lines)) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx) try: maybe_coro = locals()["func"]() if inspect.isasyncgen(maybe_coro): async for i in maybe_coro: await ctx.send(i) return thing = await maybe_coro if thing: if isinstance(thing, discord.Embed): return await ctx.send(embed=thing) if isinstance(thing, discord.File): return await ctx.send(file=thing) else: await ctx.send(thing) except Exception as e: await ctx.send(e)
async def auto_paginate(ctx, text, prefix='```', suffix='```', max_size=2000, wrap_at=(' ', '\n')): paginator = WrappedPaginator(prefix=prefix, suffix=suffix, max_size=max_size, wrap_on=wrap_at) paginator.add_line(text) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx) return interface.message
async def jsk_disassemble(self, ctx: commands.Context, *, argument: codeblock_converter): """ Disassemble Python code into bytecode. """ arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX) async with ReplResponseReactor(ctx.message): paginator = WrappedPaginator(prefix='```py', suffix='```', max_size=1985) for line in disassemble(argument.content, arg_dict=arg_dict): paginator.add_line(line) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def config(self, ctx, option: str = None): if not option: paginator = WrappedPaginator(prefix='```ini', suffix='```', max_size=800) gconf = self.bot.configs[ctx.guild.id] for opt, data in gconf.options.items(): current = gconf.get(opt) if isinstance(current, list): current = ', '.join(str(current)) accepted = data["accepts"] if isinstance(accepted, list): accepted = f'List of {accepted[0].__name__}' else: accepted = accepted.__name__ paginator.add_line(f'[{opt}]\n{data["description"].split(" | ")[-1]}\nDefault: {data["default"]}\nCurrent: {gconf.get(opt)}\nAccepts: {accepted}\n') interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx)
async def jsk_tasks(self, ctx: commands.Context): """ Shows the currently running jishaku tasks. """ if not self.tasks: return await ctx.send("No currently running tasks.") paginator = commands.Paginator(max_size=1985) for task in self.tasks: paginator.add_line(f"{task.index}: `{task.ctx.command.qualified_name}`, invoked at " f"{task.ctx.message.created_at.strftime('%Y-%m-%d %H:%M:%S')} UTC") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) return await interface.send_to(ctx)
async def emojis(self, ctx, search=None): emojis = [] if search: result = finder(text=search, collection=self.bot.emojis, key=lambda emoji: emoji.name, lazy=False) if result == []: return await ctx.send("Nothing found for your query.") for emoji in result: emojis.append(f"{str(emoji)} `{emoji.name}`") paginator = WrappedPaginator(prefix='', suffix='', max_size=500) else: for emoji in self.bot.emojis: emojis.append(f"{str(emoji)} `{emoji.name}`") paginator = WrappedPaginator(prefix='', suffix='', max_size=1000) paginator.add_line('\n'.join(emojis)) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_cat(self, ctx: commands.Context, argument: str): """ Read out a file, using syntax highlighting if detected. Lines and linespans are supported by adding '#L12' or '#L12-14' etc to the end of the filename. """ match = self.__cat_line_regex.search(argument) if not match: # should never happen return await ctx.send("Couldn't parse this input.") path = match.group(1) line_span = None if match.group(2): start = int(match.group(2)) line_span = (start, int(match.group(3) or start)) if not os.path.exists(path) or os.path.isdir(path): return await ctx.send(f"`{path}`: No file by that name.") size = os.path.getsize(path) if size <= 0: return await ctx.send( f"`{path}`: Cowardly refusing to read a file with no size stat" f" (it may be empty, endless or inaccessible).") if size > 50 * (1024**2): return await ctx.send( f"`{path}`: Cowardly refusing to read a file >50MB.") try: with open(path, "rb") as file: paginator = WrappedFilePaginator(file, line_span=line_span, max_size=1985) except UnicodeDecodeError: return await ctx.send( f"`{path}`: Couldn't determine the encoding of this file.") except ValueError as exc: return await ctx.send(f"`{path}`: Couldn't read this file, {exc}") interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) await interface.send_to(ctx)
async def jsk_python_inspect(self, ctx: commands.Context, *, argument: codeblock_converter): # pylint: disable=too-many-locals """ Evaluation of Python code with inspect information. """ arg_dict = get_var_dict_from_ctx(ctx, SCOPE_PREFIX) arg_dict["_"] = self.last_result scope = self.scope try: async with ReplResponseReactor(ctx.message): with self.submit(ctx): executor = AsyncCodeExecutor(argument.content, scope, arg_dict=arg_dict) async for send, result in AsyncSender(executor): self.last_result = result header = repr(result).replace("``", "`\u200b`").replace(self.bot.http.token, "[token omitted]") if len(header) > 485: header = header[0:482] + "..." lines = [f"=== {header} ===", ""] for name, res in all_inspections(result): lines.append(f"{name:16.16} :: {res}") text = "\n".join(lines) # Guild's advertised limit minus 1KiB for the HTTP content filesize_threshold = (ctx.guild.filesize_limit if ctx.guild else 8 * 1024 * 1024) - 1024 if len(text) < filesize_threshold: send(await ctx.send(file=discord.File( filename="inspection.prolog", fp=io.BytesIO(text.encode('utf-8')) ))) else: paginator = WrappedPaginator(prefix="```prolog", max_size=1985) paginator.add_line(text) interface = PaginatorInterface(ctx.bot, paginator, owner=ctx.author) send(await interface.send_to(ctx)) finally: scope.clear_intersection(arg_dict)