diff options
author | romangraef <romangraef@loves.dicksinhisan.us> | 2018-11-26 21:26:08 +0100 |
---|---|---|
committer | romangraef <romangraef@loves.dicksinhisan.us> | 2018-11-26 21:26:08 +0100 |
commit | 72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1 (patch) | |
tree | 2603a9a5baa3e6eb38cb680c977294ec45329fe0 | |
parent | c8808ec947590b0ab2cce69484e71aa90fecabf0 (diff) | |
download | drutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.tar.gz drutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.tar.bz2 drutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.zip |
added eval
-rw-r--r-- | drutils/__init__.py | 4 | ||||
-rw-r--r-- | drutils/eval.py | 77 |
2 files changed, 80 insertions, 1 deletions
diff --git a/drutils/__init__.py b/drutils/__init__.py index 7f362ee..2aaa5c6 100644 --- a/drutils/__init__.py +++ b/drutils/__init__.py @@ -1,7 +1,9 @@ from .awaiter import AdvancedAwaiter, AwaitException, AwaitCanceled, AwaitTimedOut +from .eval import handle_eval from .version import VERSION, VersionInfo __all__ = ( 'AdvancedAwaiter', 'AwaitException', 'AwaitCanceled', 'AwaitTimedOut', - 'VERSION', 'VersionInfo' + 'handle_eval', + 'VERSION', 'VersionInfo', ) diff --git a/drutils/eval.py b/drutils/eval.py new file mode 100644 index 0000000..fd105b5 --- /dev/null +++ b/drutils/eval.py @@ -0,0 +1,77 @@ +import ast +import os +import re + +import discord +from discord import Embed, Color + +REPLACEMENTS = { + re.compile(r'<@!?(?P<id>[0-9]+)>'): '(guild.get_member({id}) if guild is not None else client.get_user({id}))', + re.compile(r'<#(?P<id>[0-9]+)>'): '(discord.utils.get(all_channels, id={id}))', + re.compile(r'<@&(?P<id>[0-9]+)>'): '(discord.utils.get(all_roles, id={id}))', + +} + + +async def handle_eval(message: discord.Message, client: discord.Client, to_eval: str, **kwargs): + channel = message.channel + author = message.author + + all_channels = [] + all_roles = [] + for guild in client.guilds: + all_channels += guild.channels + all_roles += guild.roles + + variables = { + 'message': message, + 'author': author, + 'channel': channel, + 'all_channels': all_channels, + 'all_roles': all_roles, + 'client': client, + 'discord': discord, + 'os': os, + 'print': (lambda *text: client.loop.create_task(channel.send(' '.join(text)))), + 'guild': channel.guild if hasattr(channel, 'guild') else None, + } + variables.update(kwargs) + lines = to_eval.strip().split('\n') + block = '\n'.join(' ' + line for line in lines) + code = ("async def code({variables}):\n" + "{block}").format(variables=', '.join(variables.keys()), block=block) + + for regex, replacement in REPLACEMENTS.items(): + code = re.sub(regex, lambda match: replacement.format(**match.groupdict()), code) + + try: + module = ast.parse(code) + except Exception as e: + await message.channel.send( + embed=Embed(color=Color.red(), description="Syntax Error: `%s`" % str(e))) + return + + last = module.body[0].body[-1] + if isinstance(last, ast.Expr): + module.body[0].body[-1] = ast.copy_location(ast.Return(last.value), last) + + _globals, _locals = {}, {} + try: + code = compile(module, '<string>', 'exec') + exec(code, _globals, _locals) + except Exception as e: + await message.channel.send( + embed=discord.Embed(color=discord.Color.red(), description="Compiler Error: `%s`" % (str(e)))) + return + result = {**_globals, **_locals} + try: + result = await result["code"](**variables) + except Exception as e: + await message.channel.send( + embed=discord.Embed(color=discord.Color.red(), description="Runtime Error: `%s`" % (str(e)))) + return + + return await channel.send( + embed=Embed( + color=Color.red(), + description="📥 Evaluation success: ```py\n%r\n```" % result)) |