aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/__main__.py14
-rw-r--r--bot/cogs/__init__.py3
-rw-r--r--bot/cogs/bot.py62
-rw-r--r--bot/cogs/eval.py77
-rw-r--r--bot/cogs/logging.py32
-rw-r--r--bot/interpreter.py42
6 files changed, 221 insertions, 9 deletions
diff --git a/bot/__main__.py b/bot/__main__.py
index cb4157707..1579b6bd3 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -1,15 +1,11 @@
-#!/usr/bin/env python3
-
-import discord
-from discord.ext import commands
+# coding=utf-8
import os
-bot = commands.Bot(command_prefix=commands.when_mentioned_or(
- os.environ.get("BOT_PREFIX")))
+from discord.ext.commands import AutoShardedBot, when_mentioned_or
+bot = AutoShardedBot(command_prefix=when_mentioned_or(">>>", ">>> "))
-async def ping(ctx):
- await ctx.send("Pong.")
+bot.load_extension("bot.cogs.logging")
+bot.load_extension("bot.cogs.bot")
bot.run(os.environ.get("BOT_TOKEN"))
diff --git a/bot/cogs/__init__.py b/bot/cogs/__init__.py
new file mode 100644
index 000000000..ba286add3
--- /dev/null
+++ b/bot/cogs/__init__.py
@@ -0,0 +1,3 @@
+# coding=utf-8
+
+__author__ = "Gareth Coles"
diff --git a/bot/cogs/bot.py b/bot/cogs/bot.py
new file mode 100644
index 000000000..435051fdf
--- /dev/null
+++ b/bot/cogs/bot.py
@@ -0,0 +1,62 @@
+# coding=utf-8
+from discord import Embed
+from discord.ext.commands import AutoShardedBot, group, Context
+
+__author__ = "Gareth Coles"
+
+
+class Bot:
+ """
+ Bot information commands
+ """
+
+ def __init__(self, bot: AutoShardedBot):
+ self.bot = bot
+
+ @group(invoke_without_command=True, name="bot")
+ async def bot_group(self, ctx: Context):
+ """
+ Bot information commands
+ """
+
+ await ctx.invoke(self.bot.get_command("help"), "bot")
+
+ @bot_group.command(aliases=["about"])
+ async def info(self, ctx: Context):
+ """
+ Get information about the current bot
+ """
+
+ if not hasattr(self.bot, "shard_id") or self.bot.shard_id is None:
+ embed = Embed(
+ description="A utility bot designed just for the Python server!. Try `>>> help` for more info.\n\n"
+ "**Currently __not sharded__.**",
+ url="https://github.com/discord-python/bot"
+ )
+ else:
+ embed = Embed(
+ description="A utility bot designed just for the Python server! Try `>>> help` for more info.",
+ url="https://github.com/discord-python/bot"
+ )
+ embed.add_field(
+ name="Total Shards", value=self.bot.shard_count
+ )
+ embed.add_field(
+ name="Current Shard", value=self.bot.shard_id
+ )
+
+ embed.add_field(name="Visible Guilds", value=str(len(self.bot.guilds)))
+ embed.add_field(name="Visible Users", value=str(len(self.bot.users)))
+
+ embed.set_author(
+ name="Python Bot",
+ url="https://github.com/discord-python/bot",
+ icon_url="https://avatars3.githubusercontent.com/u/36101493?s=200&v=4"
+ )
+
+ await ctx.send(embed=embed)
+
+
+def setup(bot):
+ bot.add_cog(Bot(bot))
+ print("Cog loaded: Bot")
diff --git a/bot/cogs/eval.py b/bot/cogs/eval.py
new file mode 100644
index 000000000..82d55bbc3
--- /dev/null
+++ b/bot/cogs/eval.py
@@ -0,0 +1,77 @@
+# coding=utf-8
+from discord.ext.commands import AutoShardedBot, Context, is_owner, command
+from io import StringIO
+
+from bot.interpreter import Interpreter
+
+__author__ = "Gareth Coles"
+
+
+class Eval:
+ """
+ Bot owner only: Evaluate Python code
+ """
+
+ def __init__(self, bot: AutoShardedBot):
+ self.bot = bot
+ self.interpreter = Interpreter(bot)
+
+ @command()
+ @is_owner()
+ async def eval(self, ctx: Context, *, string: str):
+ """
+ Bot owner only: Evaluate Python code
+
+ Your code may be surrounded in a code fence, but it's not required.
+ Scope will be preserved - variables set will be present later on.
+ """
+
+ code = string.strip()
+
+ if code.startswith("```") and code.endswith("```"):
+ if code.startswith("```python"):
+ code = code[9:-3]
+ elif code.startswith("```py"):
+ code = code[5:-3]
+ else:
+ code = code[3:-3]
+ elif code.startswith("`") and code.endswith("`"):
+ code = code[1:-1]
+
+ code = code.strip().strip("\n")
+ io = StringIO()
+
+ try:
+ rvalue = await self.interpreter.run(code, ctx, io)
+ except Exception as e:
+ await ctx.send(
+ f"{ctx.author.mention} **Code**\n"
+ f"```py\n{code}```\n\n"
+ f"**Error**\n```{e}```"
+ )
+ else:
+ out_message = (
+ f"{ctx.author.mention} **Code**\n"
+ f"```py\n{code}\n```"
+ )
+
+ output = io.getvalue()
+
+ if output:
+ out_message = (
+ f"{out_message}\n\n"
+ f"**Output**\n```{output}```"
+ )
+
+ if rvalue is not None:
+ out_message = (
+ f"{out_message}\n\n"
+ f"**Returned**\n```py\n{repr(rvalue)}\n```"
+ )
+
+ await ctx.send(out_message)
+
+
+def setup(bot):
+ bot.add_cog(Eval(bot))
+ print("Cog loaded: Eval")
diff --git a/bot/cogs/logging.py b/bot/cogs/logging.py
new file mode 100644
index 000000000..150cd7c14
--- /dev/null
+++ b/bot/cogs/logging.py
@@ -0,0 +1,32 @@
+# coding=utf-8
+from discord import Message
+from discord.ext.commands import AutoShardedBot
+
+__author__ = "Gareth Coles"
+
+
+class Logging:
+ """
+ Debug logging module
+ """
+
+ def __init__(self, bot: AutoShardedBot):
+ self.bot = bot
+
+ async def on_ready(self):
+ print("Ready!")
+
+ async def on_message(self, message: Message):
+ if not message.guild: # It's a DM
+ print(f"DM: @{message.author.name}#{message.author.discriminator} -> {message.clean_content}")
+ else:
+ print(
+ f"{message.guild.name} | #{message.channel.name} | "
+ f"@{message.author.name}#{message.author.discriminator} -> "
+ f"{message.clean_content}"
+ )
+
+
+def setup(bot):
+ bot.add_cog(Logging(bot))
+ print("Cog loaded: Logging")
diff --git a/bot/interpreter.py b/bot/interpreter.py
new file mode 100644
index 000000000..3e7b822d9
--- /dev/null
+++ b/bot/interpreter.py
@@ -0,0 +1,42 @@
+# coding=utf-8
+from code import InteractiveInterpreter
+from io import StringIO
+
+__author__ = 'Gareth Coles'
+
+CODE_TEMPLATE = """
+async def _func():
+{}
+"""
+
+
+class Interpreter(InteractiveInterpreter):
+ write_callable = None
+
+ def __init__(self, bot):
+ _locals = {"bot": bot}
+ super().__init__(_locals)
+
+ async def run(self, code, ctx, io, *args, **kwargs):
+ self.locals["_rvalue"] = []
+ self.locals["ctx"] = ctx
+ self.locals["print"] = lambda x: io.write(f"{x}\n")
+
+ code_io = StringIO()
+
+ for line in code.split("\n"):
+ code_io.write(f" {line}\n")
+
+ code = CODE_TEMPLATE.format(code_io.getvalue())
+ del code_io
+
+ self.runsource(code, *args, **kwargs)
+ self.runsource("_rvalue = _func()", *args, **kwargs)
+
+ rvalue = await self.locals["_rvalue"]
+
+ del self.locals["_rvalue"]
+ del self.locals["ctx"]
+ del self.locals["print"]
+
+ return rvalue