Exemple #1
0
    def better_exec(script, globals_=None, locals_=None):
        parsed = import_expression.parse(script)
        base_function = "async def __evaluate_code(): pass"
        parsed_function = import_expression.parse(base_function)

        for node in parsed.body:
            ast.increment_lineno(node)

        def check_for_yield(payload):
            if isinstance(payload, (list, tuple)):
                for node_ in payload:
                    if check_for_yield(node_):
                        return True
            if isinstance(payload, (ast.Yield, ast.YieldFrom)):
                return True
            if hasattr(payload, 'body'):
                for node_ in payload.body:
                    if check_for_yield(node_):
                        return True
            if hasattr(payload, 'value'):
                if check_for_yield(payload.value):
                    return True
            return False

        if not check_for_yield(parsed.body):
            insert_returns(parsed.body)

        parsed_function.body[0].body = parsed.body

        import_expression.exec(
            import_expression.compile(parsed_function, filename="<evaluator>", mode='exec'),
            globals_, locals_
        )
Exemple #2
0
def wrap_code(code_input):
    code_in = import_expression.parse(code_input)
    base = import_expression.parse(code_base)
    try_block = base.body[-1].body[-1].body
    try_block.extend(code_in.body)
    ast.fix_missing_locations(base)
    insert_yield(try_block)
    return base
Exemple #3
0
def wrap_code(code: str, args: str = '') -> ast.Module:
    """
    Compiles Python code into an async function or generator,
    and automatically adds return if the function body is a single evaluation.
    Also adds inline import expression support.
    """

    if sys.version_info >= (3, 7):
        user_code = import_expression.parse(code, mode='exec')
        injected = ''
    else:
        injected = code

    mod = import_expression.parse(CORO_CODE.format(args, textwrap.indent(injected, ' ' * 8)), mode='exec')

    definition = mod.body[-1]  # async def ...:
    assert isinstance(definition, ast.AsyncFunctionDef)

    try_block = definition.body[-1]  # try:
    assert isinstance(try_block, ast.Try)

    if sys.version_info >= (3, 7):
        try_block.body.extend(user_code.body)
    else:
        ast.increment_lineno(mod, -16)  # bring line numbers back in sync with repl

    ast.fix_missing_locations(mod)

    KeywordTransformer().generic_visit(try_block)

    last_expr = try_block.body[-1]

    # if the last part isn't an expression, ignore it
    if not isinstance(last_expr, ast.Expr):
        return mod

    # if the last expression is not a yield
    if not isinstance(last_expr.value, ast.Yield):
        # copy the value of the expression into a yield
        yield_stmt = ast.Yield(last_expr.value)
        ast.copy_location(yield_stmt, last_expr)
        # place the yield into its own expression
        yield_expr = ast.Expr(yield_stmt)
        ast.copy_location(yield_expr, last_expr)

        # place the yield where the original expression was
        try_block.body[-1] = yield_expr

    return mod
Exemple #4
0
def create_tree(code: str, use_ansi: bool = True):
    """
    Compiles code into an AST tree and then formats it
    """

    user_code = import_expression.parse(code, mode='exec')
    return '\n'.join(format_ast_node(user_code, use_ansi=use_ansi))
Exemple #5
0
def decode(b, errors='strict'):
    if not b:
        return '', 0

    decoded = codecs.decode(b, errors=errors, encoding='utf-8')
    parsed = ie.parse(decoded)
    parsed.body.insert(0, IMPORT_STATEMENT)
    unparsed = astunparse.unparse(parsed)
    return unparsed, len(decoded)
Exemple #6
0
def wrap_code(code: str, args: str = "") -> ast.Module:
    """
    Compiles Python code into an async function or generator,
    and automatically adds return if the function body is a single evaluation.
    Also adds inline import expression support.
    """

    user_code = import_expression.parse(code, mode="exec")
    mod = import_expression.parse(CORO_CODE.format(args), mode="exec")

    definition = mod.body[-1]  # async def ...:
    assert isinstance(definition, ast.AsyncFunctionDef)

    try_block = definition.body[-1]  # try:
    assert isinstance(try_block, ast.Try)

    try_block.body.extend(user_code.body)

    ast.fix_missing_locations(mod)

    KeywordTransformer().generic_visit(try_block)

    last_expr = try_block.body[-1]

    # if the last part isn't an expression, ignore it
    if not isinstance(last_expr, ast.Expr):
        return mod

    # if the last expression is not a yield
    if not isinstance(last_expr.value, ast.Yield):
        # copy the value of the expression into a yield
        yield_stmt = ast.Yield(last_expr.value)
        ast.copy_location(yield_stmt, last_expr)
        # place the yield into its own expression
        yield_expr = ast.Expr(yield_stmt)
        ast.copy_location(yield_expr, last_expr)

        # place the yield where the original expression was
        try_block.body[-1] = yield_expr

    return mod
Exemple #7
0
def wrap_code(code: str, args: str = '') -> ast.Module:
    """
    Wraps code for disassembly.

    This is similar in function to the jishaku.repl.compilation equivalent,
    but due to the different structure required for clean disassemblies,
    it's implemented separately here.
    """

    user_code = import_expression.parse(code, mode='exec')
    mod = import_expression.parse(CORO_CODE.format(args), mode='exec')

    definition = mod.body[-1]  # async def ...:
    assert isinstance(definition, ast.AsyncFunctionDef)

    # Patch user code directly into the function
    definition.body = user_code.body

    ast.fix_missing_locations(mod)

    # We do not use the keyword transformer here, since it might produce misleading disassembly.

    is_asyncgen = any(
        isinstance(node, ast.Yield) for node in ast.walk(definition))
    last_expr = definition.body[-1]

    # if the last part isn't an expression, ignore it
    if not isinstance(last_expr, ast.Expr):
        return mod

    # if this isn't a generator and the last expression is not a return
    if not is_asyncgen and not isinstance(last_expr.value, ast.Return):
        # copy the value of the expression into a return
        return_stmt = ast.Return(last_expr.value)
        ast.copy_location(return_stmt, last_expr)

        # place the return where the original expression was
        definition.body[-1] = return_stmt

    return mod
Exemple #8
0
def maybe_add_return(code: str, args: str = '') -> ast.Module:
    """
    Compiles Python code into an async function or generator,
    and automatically adds return if the function body is a single evaluation.
    Also adds inline import expression support.
    """

    mod = import_expression.parse(get_wrapped_code(code, args=args),
                                  mode='exec')
    ast.increment_lineno(mod, -12)  # bring line numbers back in sync with repl

    definition = mod.body[-1]  # async def ...:
    assert isinstance(definition, ast.AsyncFunctionDef)

    try_block = definition.body[-1]  # try:
    assert isinstance(try_block, ast.Try)

    is_asyncgen = any(
        isinstance(node, ast.Yield) for node in ast.walk(try_block))

    last_expr = try_block.body[-1]

    # if the last part isn't an expression, ignore it
    if not isinstance(last_expr, ast.Expr):
        return mod

    # if the last expression is not a yield
    if not isinstance(last_expr.value, ast.Yield):
        # copy the expression into a return/yield
        if is_asyncgen:
            # copy the value of the expression into a yield
            yield_stmt = ast.Yield(last_expr.value)
            ast.copy_location(yield_stmt, last_expr)
            # place the yield into its own expression
            yield_expr = ast.Expr(yield_stmt)
            ast.copy_location(yield_expr, last_expr)

            # place the yield where the original expression was
            try_block.body[-1] = yield_expr
        else:
            # copy the expression into a return
            return_stmt = ast.Return(last_expr.value)
            ast.copy_location(return_stmt, last_expr)

            # place the return where the original expression was
            try_block.body[-1] = return_stmt

    return mod
Exemple #9
0
    async def eval_(self, ctx, *, code):
        rle = random.choice(self.bot.loading_emotes)
        embed = discord.Embed(title="En cours...",
                              description=f"<{rle}>",
                              color=EMBED_COLOUR,
                              timestamp=datetime.utcnow())
        message = await ctx.send(embed=embed)

        timer = Timer()

        env = {
            'bot': self.bot,
            'ctx': ctx,
            'channel': ctx.channel,
            'author': ctx.author,
            'guild': ctx.guild,
            'message': ctx.message,
            "_": self._last_result,
            "__timer": timer
        }

        env.update(globals())

        code = self.cleanup_code(code)
        stdout = io.StringIO()

        to_parse = CORO_CODE.format(textwrap.indent(code, " " * 8))

        try:
            parsed = import_expression.parse(to_parse, mode="exec")
            exec(compile(parsed, "<eval>", "exec"), env)

        except Exception as e:
            embed.title = "Erreur lors de la compilation"
            embed.description = f'```fix\n{e.__class__.__name__}: {e}\n```'
            await message.edit(embed=embed)

            await ctx.tick(False)
            await ctx.add_delete_reaction(message)
            return

        func = env["func"]
        try:
            with redirect_stdout(stdout):
                ret = await func()

        except Exception:
            value = stdout.getvalue()
            embed.title = "Erreur lors de l'éxecution"
            desc = f"{value}{traceback.format_exc()}"

            if len(desc) > 2015:
                desc = desc[:2015] + "..."
            embed.description = f"```py\n{desc}\n```"
            await message.edit(embed=embed)

            await ctx.tick(False)
            await ctx.add_delete_reaction(message)
        else:
            value = stdout.getvalue()
            try:
                await ctx.tick()
            except discord.Forbidden:
                pass

            embed.title = "Succès!"
            embed.description = f"En {round(timer.elapsed, 3)}s"

            if ret is None:
                if value:
                    text = value
                else:
                    await message.edit(embed=embed)
                    await ctx.add_delete_reaction(message)
                    return
            else:
                self._last_result = ret
                text = f"{value}{ret}"

            class EvalPages(TextPages):
                async def stop_pages(self):
                    await message.delete()
                    await super().stop_pages()

            p = EvalPages(ctx,
                          text,
                          prefix="```py",
                          suffix="```",
                          stop_deletes=True)
            await message.edit(embed=embed)
            await p.paginate()
def wrap_code(code: str, args: str = '') -> ast.Module:
    """Compiles Python code into an async function or generator.

    Automatically adds return if the function body is a single evaluation.
    Also adds inline import expression support.
    """

    if sys.version_info >= (3, 7):
        user_code = import_expression.parse(code, mode='exec')
        injected = ''
    else:
        injected = code

    mod = import_expression.parse(CORO_CODE.format(
        args, textwrap.indent(injected, ' ' * 8)),
                                  mode='exec')

    definition = mod.body[-1]  # async def ...:
    assert isinstance(definition, ast.AsyncFunctionDef)

    try_block = definition.body[-1]  # try:
    assert isinstance(try_block, ast.Try)

    if sys.version_info >= (3, 7):
        try_block.body.extend(user_code.body)
    else:
        preclude_offset = CORO_CODE.split('pass')[0].count('\n') + 1
        ast.increment_lineno(
            mod, -preclude_offset)  # bring line numbers back in sync with repl

    ast.fix_missing_locations(mod)

    is_asyncgen = any(
        isinstance(node, ast.Yield) for node in ast.walk(try_block))

    last_expr = try_block.body[-1]

    # if the last part isn't an expression, ignore it
    if not isinstance(last_expr, ast.Expr):
        return mod

    # if the last expression is not a yield
    if not isinstance(last_expr.value, ast.Yield):
        # copy the expression into a return/yield
        if is_asyncgen:
            # copy the value of the expression into a yield
            yield_stmt = ast.Yield(last_expr.value)
            ast.copy_location(yield_stmt, last_expr)
            # place the yield into its own expression
            yield_expr = ast.Expr(yield_stmt)
            ast.copy_location(yield_expr, last_expr)

            # place the yield where the original expression was
            try_block.body[-1] = yield_expr
        else:
            # copy the expression into a return
            return_stmt = ast.Return(last_expr.value)
            ast.copy_location(return_stmt, last_expr)

            # place the return where the original expression was
            try_block.body[-1] = return_stmt

    return mod