Moondancer
Moondancer

Reputation: 133

Exec run async function

I know that I shouldn't use exec because it's insecure but the code it run comes from the same file and is a string. How can I use exec to run an async function? It always returns me SyntaxError: 'await' outside function if I try it.

Edit: This is the Code where I am using exec:

async def command_processor(guild):
    while True:
        commands = {"[1] - Bot Permissions abrufen" : "print_permissions(guild)",
                    "Derzeit nicht verwendbar - [2] - Invite zu Gilde erstellen (max Nutzungen pro Invite: 1)" : "await print_invite(guild)",
                    "[3] - Gebannte Benutzer auflisten (benötigt Berechtigung {Mitglieder bannen}" : "print_banned(guild)",
                    "[4] - Ausgewählten Server wechseln" : "change_guild()",
                    "[5] - Ausgewählten Bot wechseln" : "change_bot()",
                    "[6] - Beenden" : "sys.exit()"
            }
        print("\n\n--------------- Befehle ---------------\n")
        for i in range(len(commands.keys())):
            print(list(commands.keys())[i])
        sel = input()
        print()
        try:
            int(sel)
        except:
            print("Bitte hier nur die Zahl eingeben")
        if int(sel) in range(len(commands.keys())):
            exec(list(commands.values())[int(sel)-1])

Upvotes: 1

Views: 250

Answers (1)

obeq
obeq

Reputation: 675

You could do this, I think. The problem with exec is that it doesn't return anything, so you would need to use eval instead. I think this could work:

async def command_processor(guild):
    while True:
        commands = {"[1] - Bot Permissions abrufen" : "print_permissions(guild)",
                    "Derzeit nicht verwendbar - [2] - Invite zu Gilde erstellen (max Nutzungen pro Invite: 1)" : "await print_invite(guild)",
                    "[3] - Gebannte Benutzer auflisten (benötigt Berechtigung {Mitglieder bannen}" : "print_banned(guild)",
                    "[4] - Ausgewählten Server wechseln" : "change_guild()",
                    "[5] - Ausgewählten Bot wechseln" : "change_bot()",
                    "[6] - Beenden" : "sys.exit()"
            }

# ...

        if int(sel) in range(len(commands.keys())):
            await eval(list(commands.values())[int(sel)-1])

But there's no need to use eval here, and you have a lot to lose. A simple way could be to use a dict, something along the lines:

commands = {1: {"description": "[1] - Bot Permission abrufen", "command" : print_permissions, "args": [guild]},
# ...
}

for cmd in commands:
    print(cmd['description'])

# ...
selected_command = commands[sel]
await selected_command['command'](*selected_command['args'])

But it gets tricky, since sometimes you have a coroutine and sometimes a regular method. To get around that, I guess you could do this:

commands = {
    1: {"description": "[1] - Bot Permission abrufen", "exec" : print_permissions, "args": [guild]},
    2: {"description": "Derzeit nicht verwendbar - [2] - Invite zu Gilde erstellen (max Nutzungen pro Invite: 1)", "exec": print_invite, "args": [guild]},
# ...
}

for cmd in commands:
    print(cmd['description'])

# ...
selected_command = commands[sel]
if asyncio.iscoroutinefunction(selected_command['exec']):
    await selected_command['exec'](*selected_command['args'])
else:
    selected_command['exec'](*selected_command['args'])

On a final note: It make's me nervous that we now have the key that needs to pressed in two different places. This will lead to tears in the end, mark my words. I would do something like this:

commands = [
    {
        "description": "[{keynum}] - Bot Permission abrufen",
        "exec" : print_permissions, "args": [guild]
    },
    {
        "description": "Derzeit nicht verwendbar - [{keynum}] - Invite zu Gilde erstellen (max Nutzungen pro Invite: 1)",
        "exec": print_invite, "args": [guild]
    },
]

for keynum, command in enumerate(commands):
    print(command['description'].format(keynum=keynum))

I haven't tested that code, so there's probably a bug, but you get the idea.

Upvotes: 1

Related Questions