bot.exts.utilities.snekbox._cog#

Module Contents#

Classes#

FilteredFiles

CodeblockConverter

Attempts to extract code from a codeblock, if provided.

PythonVersionSwitcherButton

A button that allows users to re-run their eval command in a different Python version.

Snekbox

Safe evaluation of Python code using Snekbox.

Functions#

predicate_message_edit(→ bool)

Return True if the edited message is the context message and the content was indeed modified.

predicate_emoji_reaction(→ bool)

Return True if the reaction REDO_EMOJI was added by the context message author on this message.

Attributes#

bot.exts.utilities.snekbox._cog.log[source]#
bot.exts.utilities.snekbox._cog.ESCAPE_REGEX[source]#
bot.exts.utilities.snekbox._cog.TIMEIT_SETUP_WRAPPER = Multiline-String[source]#
Show Value
"""
import atexit
import sys
from collections import deque

if not hasattr(sys, "_setup_finished"):
    class Writer(deque):
        '''A single-item deque wrapper for sys.stdout that will return the last line when read() is called.'''

        def __init__(self:Self):
            super().__init__(maxlen=1)

        def write(self:Self, string):
            '''Append the line to the queue if it is not empty.'''
            if string.strip():
                self.append(string)

        def read(self:Self):
            '''This method will be called when print() is called.

            The queue is emptied as we don't need the output later.
            '''
            return self.pop()

        def flush(self:Self):
            '''This method will be called eventually, but we don't need to do anything here.'''
            pass

    sys.stdout = Writer()

    def print_last_line():
        if sys.stdout: # If the deque is empty (i.e. an error happened), calling read() will raise an error
            # Use sys.__stdout__ here because sys.stdout is set to a Writer() instance
            print(sys.stdout.read(), file=sys.__stdout__)

    atexit.register(print_last_line) # When exiting, print the last line (hopefully it will be the timeit output)
    sys._setup_finished = None
{setup}
"""
bot.exts.utilities.snekbox._cog.MAX_PASTE_LENGTH = 10000[source]#
bot.exts.utilities.snekbox._cog.MAX_OUTPUT_BLOCK_LINES = 10[source]#
bot.exts.utilities.snekbox._cog.MAX_OUTPUT_BLOCK_CHARS = 1000[source]#
bot.exts.utilities.snekbox._cog.NO_SNEKBOX_CHANNELS = ()[source]#
bot.exts.utilities.snekbox._cog.NO_SNEKBOX_CATEGORIES = ()[source]#
bot.exts.utilities.snekbox._cog.SNEKBOX_ROLES = ()[source]#
bot.exts.utilities.snekbox._cog.REDO_EMOJI = '🔁'[source]#
bot.exts.utilities.snekbox._cog.REDO_TIMEOUT = 30[source]#
bot.exts.utilities.snekbox._cog.SupportedPythonVersions[source]#
class bot.exts.utilities.snekbox._cog.FilteredFiles[source]#

Bases: NamedTuple

allowed: list[bot.exts.utilities.snekbox._io.FileAttachment][source]#
blocked: list[bot.exts.utilities.snekbox._io.FileAttachment][source]#
class bot.exts.utilities.snekbox._cog.CodeblockConverter[source]#

Bases: discord.ext.commands.Converter

Attempts to extract code from a codeblock, if provided.

async classmethod convert(ctx: discord.ext.commands.Context, code: str) list[str][source]#

Extract code from the Markdown, format it, and insert it into the code template.

If there is any code block, ignore text outside the code block. Use the first code block, but prefer a fenced code block. If there are several fenced code blocks, concatenate only the fenced code blocks.

Return a list of code blocks if any, otherwise return a list with a single string of code.

class bot.exts.utilities.snekbox._cog.PythonVersionSwitcherButton(version_to_switch_to: SupportedPythonVersions, snekbox_cog: Self, ctx: discord.ext.commands.Context, job: bot.exts.utilities.snekbox._eval.EvalJob)[source]#

Bases: discord.ui.Button

A button that allows users to re-run their eval command in a different Python version.

async callback(interaction: discord.Interaction) None[source]#

Tell snekbox to re-run the user’s code in the alternative Python version.

Use a task calling snekbox, as run_job is blocking while it waits for edit/reaction on the message.

class bot.exts.utilities.snekbox._cog.Snekbox(bot: bot.bot.Bot)[source]#

Bases: discord.ext.commands.Cog

Safe evaluation of Python code using Snekbox.

build_python_version_switcher_view(current_python_version: SupportedPythonVersions, ctx: discord.ext.commands.Context, job: bot.exts.utilities.snekbox._eval.EvalJob) pydis_core.utils.interactions.ViewWithUserAndRoleCheck[source]#

Return a view that allows the user to change what version of Python their code is run on.

async post_job(job: bot.exts.utilities.snekbox._eval.EvalJob) bot.exts.utilities.snekbox._eval.EvalResult[source]#

Send a POST request to the Snekbox API to evaluate code and return the results.

async static upload_output(http_session: aiohttp.ClientSession, output: str) str | None[source]#

Upload the job’s output to a paste service and return a URL to it if successful.

static prepare_timeit_input(codeblocks: list[str]) list[str][source]#

Join the codeblocks into a single string, then return the arguments in a list.

If there are multiple codeblocks, insert the first one into the wrapped setup code.

async format_output(output: str, max_lines: int = MAX_OUTPUT_BLOCK_LINES, max_chars: int = MAX_OUTPUT_BLOCK_CHARS, line_nums: bool = True, output_default: str = '[No output]') tuple[str, str | None][source]#

Format the output and return a tuple of the formatted output and a URL to the full output.

Prepend each line with a line number. Truncate if there are over 10 lines or 1000 characters and upload the full output to a paste service.

_filter_files(ctx: discord.ext.commands.Context, files: list[bot.exts.utilities.snekbox._io.FileAttachment], blocked_exts: set[str]) FilteredFiles[source]#

Filter to restrict files to allowed extensions. Return a named tuple of allowed and blocked files lists.

async send_job(ctx: discord.ext.commands.Context, job: bot.exts.utilities.snekbox._eval.EvalJob) discord.Message[source]#

Evaluate code, format it, and send the output to the corresponding channel.

Return the bot response.

async continue_job(ctx: discord.ext.commands.Context, response: discord.Message, job_name: str) bot.exts.utilities.snekbox._eval.EvalJob | None[source]#

Check if the job’s session should continue.

If the code is to be re-evaluated, return the new EvalJob. Otherwise, return None if the job’s session should be terminated.

async get_code(message: discord.Message, command: discord.ext.commands.Command) str | None[source]#

Return the code from message to be evaluated.

If the message is an invocation of the command, return the first argument or None if it doesn’t exist. Otherwise, return the full content of the message.

async run_job(ctx: discord.ext.commands.Context, job: bot.exts.utilities.snekbox._eval.EvalJob) None[source]#

Handle checks, stats and re-evaluation of a snekbox job.

async eval_command(ctx: discord.ext.commands.Context, python_version: SupportedPythonVersions | None, *, code: CodeblockConverter) None[source]#

Run Python code and get the results.

This command supports multiple lines of code, including formatted code blocks. Code can be re-evaluated by editing the original message within 10 seconds and clicking the reaction that subsequently appears.

The starting working directory /home, is a writeable temporary file system. Files created, excluding names with leading underscores, will be uploaded in the response.

If multiple codeblocks are in a message, all of them will be joined and evaluated, ignoring the text outside them.

By default, your code is run on Python 3.11. A python_version arg of 3.10 can also be specified.

We’ve done our best to make this sandboxed, but do let us know if you manage to find an issue with it!

async timeit_command(ctx: discord.ext.commands.Context, python_version: SupportedPythonVersions | None, *, code: CodeblockConverter) None[source]#

Profile Python Code to find execution time.

This command supports multiple lines of code, including code wrapped inside a formatted code block. Code can be re-evaluated by editing the original message within 10 seconds and clicking the reaction that subsequently appears.

If multiple formatted codeblocks are provided, the first one will be the setup code, which will not be timed. The remaining codeblocks will be joined together and timed.

By default, your code is run on Python 3.11. A python_version arg of 3.10 can also be specified.

We’ve done our best to make this sandboxed, but do let us know if you manage to find an issue with it!

bot.exts.utilities.snekbox._cog.predicate_message_edit(ctx: discord.ext.commands.Context, old_msg: discord.Message, new_msg: discord.Message) bool[source]#

Return True if the edited message is the context message and the content was indeed modified.

bot.exts.utilities.snekbox._cog.predicate_emoji_reaction(ctx: discord.ext.commands.Context, reaction: discord.Reaction, user: discord.User) bool[source]#

Return True if the reaction REDO_EMOJI was added by the context message author on this message.