aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorromangraef <romangraef@loves.dicksinhisan.us>2018-11-26 21:26:08 +0100
committerromangraef <romangraef@loves.dicksinhisan.us>2018-11-26 21:26:08 +0100
commit72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1 (patch)
tree2603a9a5baa3e6eb38cb680c977294ec45329fe0
parentc8808ec947590b0ab2cce69484e71aa90fecabf0 (diff)
downloaddrutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.tar.gz
drutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.tar.bz2
drutils-72e5ec1f113a8cc07c8d9ae24b13286dc3de2da1.zip
added eval
-rw-r--r--drutils/__init__.py4
-rw-r--r--drutils/eval.py77
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))