Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot await in exec

hi im trying to make my discord bot do what im typing im my discord client and i want to use exec() + this is just to test and experiment so it doesnt matter if it may be unsecure.

part of my code:

import discord

client = discord.Client()

@client.event
async def on_message(message):
    if message.author == client.user:
        return

    if message.content.startswith('2B: '):
        exec(message.content[4:])   # <--- here is the exec()
    .
    .
    .

but this is the error when i type,

2B: await client.send_message(message.channel, 'please stay quiet -.-')

error:

Ignoring exception in on_message
Traceback (most recent call last):
  File "C:\Users\Shiyon\AppData\Local\Programs\Python\Python36\lib\site-packages\discord\client.py", line 307, in _run_event
    yield from getattr(self, event)(*args, **kwargs)
  File "C:\Users\Shiyon\Desktop\dm_1.py", line 12, in on_message
    exec(message.content[4:])
  File "<string>", line 1
    await client.send_message(message.channel, 'please stay quiet -.-')
               ^
SyntaxError: invalid syntax
like image 631
shiyon sufa Avatar asked Aug 31 '26 17:08

shiyon sufa


1 Answers

I believe this may be your problem:

Be aware that the return and yield statements may not be used outside of function definitions even within the context of code passed to the exec() function

from https://docs.python.org/3/library/functions.html

This should work better:

await eval(input)

If you want to be able to use non coroutines too you could check before awaiting the return of the eval.

Here is a snippet from Rapptz's bot which seems to do something like what you wanted:

@commands.command(pass_context=True, hidden=True)
@checks.is_owner()
async def debug(self, ctx, *, code : str):
    """Evaluates code."""
    code = code.strip('` ')
    python = '```py\n{}\n```'
    result = None

    env = {
        'bot': self.bot,
        'ctx': ctx,
        'message': ctx.message,
        'server': ctx.message.server,
        'channel': ctx.message.channel,
        'author': ctx.message.author
    }

    env.update(globals())

    try:
        result = eval(code, env)
        if inspect.isawaitable(result):
            result = await result
    except Exception as e:
        await self.bot.say(python.format(type(e).__name__ + ': ' + str(e)))
        return

    await self.bot.say(python.format(result))

Explanation edit:

The await keyword only works in context because it does some magic with suspending execution in the loop.

The exec function always returns None and loses the return value of whatever statement it executed. By contrast the eval function returns the return value of its statement.

client.send_message(...) returns an awaitable object which needs to be awaited in context. By using await on the return of the eval, we can do this easily and by checking if it's awaitable first we can also execute non coroutines.

like image 111
Blimmo Avatar answered Sep 02 '26 06:09

Blimmo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!