Beispiel #1
0
    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)
Beispiel #2
0
    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}")
Beispiel #3
0
    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}).")

            if use_file_check(ctx,
                              len(data)):  # File "full content" preview limit
                # Shallow language detection
                language = None

                for hint in hints:
                    language = get_language(hint)

                    if language:
                        break

                await ctx.send(
                    file=disnake.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)
Beispiel #4
0
    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)
Beispiel #5
0
    async def jsk_source(self, ctx: commands.Context, *, command_name: str):
        """
        Displays the source code for a command.
        """

        command = self.bot.get_command(command_name) or self.get_slash_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."
            )

        filename = "source.py"

        try:
            filename = pathlib.Path(inspect.getfile(command.callback)).name
        except (TypeError, OSError):
            pass

        # getsourcelines for some reason returns WITH line endings
        source_text = ''.join(source_lines)

        if use_file_check(
                ctx, len(source_text)):  # File "full content" preview limit
            await ctx.send(file=disnake.File(
                filename=filename, fp=io.BytesIO(source_text.encode('utf-8'))))
        else:
            paginator = WrappedPaginator(prefix='```py',
                                         suffix='```',
                                         max_size=1985)

            paginator.add_line(
                source_text.replace('```', '``\N{zero width space}`'))

            interface = PaginatorInterface(ctx.bot,
                                           paginator,
                                           owner=ctx.author)
            await interface.send_to(ctx)
Beispiel #6
0
    async def jsk_disassemble(self, ctx: commands.Context, *,
                              argument: codeblock_converter):
        """
        Disassemble Python code into bytecode.
        """

        arg_dict = get_var_dict_from_ctx(ctx, Flags.SCOPE_PREFIX)

        async with ReplResponseReactor(ctx.message):
            text = "\n".join(disassemble(argument.content, arg_dict=arg_dict))

            if use_file_check(ctx,
                              len(text)):  # File "full content" preview limit
                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)