# Buggy code
async def repl(self, ctx):
    """Open an interactive REPL.

    The REPL will only recognise code as messages which start with a
    backtick. This includes codeblocks, and as such multiple lines can be
    evaluated.
    """
    variables = {
        "ctx": ctx,
        "bot": ctx.bot,
        "message": ctx.message,
        "guild": ctx.guild,
        "channel": ctx.channel,
        "author": ctx.author,
        "asyncio": asyncio,
        "_": None,
        "__builtins__": __builtins__,
    }

    if ctx.channel.id in self.sessions:
        await ctx.send(
            _("Already running a REPL session in this channel. Exit it with `quit`.")
        )
        return

    self.sessions.add(ctx.channel.id)
    await ctx.send(_("Enter code to execute or evaluate. `exit()` or `quit` to exit."))

    while True:
        response = await ctx.bot.wait_for(
            "message", check=MessagePredicate.regex(r"^`", ctx)
        )

        cleaned = self.cleanup_code(response.content)

        if cleaned in ("quit", "exit", "exit()"):
            await ctx.send(_("Exiting."))
            self.sessions.remove(ctx.channel.id)
            return

        executor = None
        if cleaned.count("\n") == 0:
            # single statement, potentially 'eval'
            try:
                code = self.async_compile(cleaned, "<repl session>", "eval")
            except SyntaxError:
                pass
            else:
                executor = eval

        if executor is None:
            try:
                code = self.async_compile(cleaned, "<repl session>", "exec")
            except SyntaxError as e:
                await ctx.send(self.get_syntax_error(e))
                continue

        variables["message"] = response

        stdout = io.StringIO()

        msg = ""

        try:
            with redirect_stdout(stdout):
                if executor is None:
                    result = types.FunctionType(code, variables)()
                else:
                    result = executor(code, variables)
                result = await self.maybe_await(result)
        except:
            value = stdout.getvalue()
            msg = "{}{}".format(value, traceback.format_exc())
        else:
            value = stdout.getvalue()
            if result is not None:
                msg = "{}{}".format(value, result)
                variables["_"] = result
            elif value:
                msg = "{}".format(value)

        msg = self.sanitize_output(ctx, msg)

        try:
            await ctx.send_interactive(self.get_pages(msg), box_lang="py")
        except discord.Forbidden:
            pass
        except discord.HTTPException as e:
            await ctx.send(_("Unexpected error: `{}`").format(e))


# Traceback (KeyError)
Traceback (most recent call last):
File "/home/ubuntu/red-venv/lib/python3.8/site-packages/redbot/core/dev_commands.py", line 192, in _eval
result = await func()
File "<string>", line 3, in func
File "<string>", line 2, in <module>
File "/usr/lib/python3.8/typing.py", line 603, in __init__
def_mod = sys._getframe(1).f_globals['__name__']  # for pickling
KeyError: '__name__'

# Fixed code
async def repl(self, ctx):
    """Open an interactive REPL.

    The REPL will only recognise code as messages which start with a
    backtick. This includes codeblocks, and as such multiple lines can be
    evaluated.
    """
    variables = {
        "ctx": ctx,
        "bot": ctx.bot,
        "message": ctx.message,
        "guild": ctx.guild,
        "channel": ctx.channel,
        "author": ctx.author,
        "asyncio": asyncio,
        "_": None,
        "__builtins__": __builtins__,
        "__name__": "__main__",
    }

    if ctx.channel.id in self.sessions:
        await ctx.send(
            _("Already running a REPL session in this channel. Exit it with `quit`.")
        )
        return

    self.sessions.add(ctx.channel.id)
    await ctx.send(_("Enter code to execute or evaluate. `exit()` or `quit` to exit."))

    while True:
        response = await ctx.bot.wait_for(
            "message", check=MessagePredicate.regex(r"^`", ctx)
        )

        cleaned = self.cleanup_code(response.content)

        if cleaned in ("quit", "exit", "exit()"):
            await ctx.send(_("Exiting."))
            self.sessions.remove(ctx.channel.id)
            return

        executor = None
        if cleaned.count("\n") == 0:
            # single statement, potentially 'eval'
            try:
                code = self.async_compile(cleaned, "<repl session>", "eval")
            except SyntaxError:
                pass
            else:
                executor = eval

        if executor is None:
            try:
                code = self.async_compile(cleaned, "<repl session>", "exec")
            except SyntaxError as e:
                await ctx.send(self.get_syntax_error(e))
                continue

        variables["message"] = response

        stdout = io.StringIO()

        msg = ""

        try:
            with redirect_stdout(stdout):
                if executor is None:
                    result = types.FunctionType(code, variables)()
                else:
                    result = executor(code, variables)
                result = await self.maybe_await(result)
        except:
            value = stdout.getvalue()
            msg = "{}{}".format(value, traceback.format_exc())
        else:
            value = stdout.getvalue()
            if result is not None:
                msg = "{}{}".format(value, result)
                variables["_"] = result
            elif value:
                msg = "{}".format(value)

        msg = self.sanitize_output(ctx, msg)

        try:
            await ctx.send_interactive(self.get_pages(msg), box_lang="py")
        except discord.Forbidden:
            pass
        except discord.HTTPException as e:
            await ctx.send(_("Unexpected error: `{}`").format(e))