diff options
| -rw-r--r-- | bot/exts/utils/snekbox/_cog.py | 8 | ||||
| -rw-r--r-- | bot/exts/utils/snekbox/_eval.py | 77 | 
2 files changed, 58 insertions, 27 deletions
| diff --git a/bot/exts/utils/snekbox/_cog.py b/bot/exts/utils/snekbox/_cog.py index f8ddbbf0e..6aa7c6324 100644 --- a/bot/exts/utils/snekbox/_cog.py +++ b/bot/exts/utils/snekbox/_cog.py @@ -278,7 +278,9 @@ class Snekbox(Cog):          """          async with ctx.typing():              result = await self.post_job(job) -            msg, error = result.get_message(job) +            msg = result.get_message(job) +            error = result.error_message +            files_error = result.files_error_message              if error:                  output, paste_link = error, None @@ -293,6 +295,10 @@ class Snekbox(Cog):              if paste_link:                  msg += f"Full output: {paste_link}" +            # Additional files error message after output +            if files_error: +                msg += f"\n{files_error}" +              # Collect stats of job fails + successes              if result.returncode != 0:                  self.bot.stats.incr("snekbox.python.fail") diff --git a/bot/exts/utils/snekbox/_eval.py b/bot/exts/utils/snekbox/_eval.py index d955d26d0..748b58a3b 100644 --- a/bot/exts/utils/snekbox/_eval.py +++ b/bot/exts/utils/snekbox/_eval.py @@ -70,41 +70,66 @@ class EvalResult:          else:  # Exception              return ":x:" -    def get_message(self, job: EvalJob) -> tuple[str, str]: -        """Return a user-friendly message and error corresponding to the process's return code.""" -        msg = f"Your {job.version} {job.name} job has completed with return code {self.returncode}" +    @property +    def error_message(self) -> str: +        """Return an error message corresponding to the process's return code."""          error = "" -          if self.returncode is None: -            msg = f"Your {job.version} {job.name} job has failed"              error = self.stdout.strip() -        elif self.returncode == 128 + SIGKILL: -            msg = f"Your {job.version} {job.name} job timed out or ran out of memory"          elif self.returncode == 255: -            msg = f"Your {job.version} {job.name} job has failed"              error = "A fatal NsJail error occurred" +        return error + +    @property +    def files_error_message(self) -> str: +        """Return an error message corresponding to the failed files.""" +        if not self.failed_files: +            return "" + +        failed_files = f"({self.failed_files_str()})" + +        n_failed = len(self.failed_files) +        files = f"file{'s' if n_failed > 1 else ''}" +        msg = f"Failed to upload {n_failed} {files} {failed_files}" + +        if (n_failed + len(self.files)) > FILE_COUNT_LIMIT: +            it_they = "they" if n_failed > 1 else "it" +            msg += f" as {it_they} exceeded the {FILE_COUNT_LIMIT} file limit." +        else: +            msg += f". File sizes should each not exceed {sizeof_fmt(FILE_SIZE_LIMIT)}." + +        return msg + +    def failed_files_str(self, char_max: int = 85, file_max: int = 5) -> str: +        """Return a string containing the names of failed files, truncated to lower of char_max and file_max.""" +        names = [] +        for file in self.failed_files: +            char_max -= len(file) +            if char_max <= 0 or len(names) >= file_max: +                names.append("...") +                break +            names.append(file) +        text = ", ".join(names) +        return text + +    def get_message(self, job: EvalJob) -> str: +        """Return a user-friendly message corresponding to the process's return code.""" +        msg = f"Your {job.version} {job.name} job" + +        if self.returncode is None: +            msg += " has failed" +        elif self.returncode == 128 + SIGKILL: +            msg += " timed out or ran out of memory" +        elif self.returncode == 255: +            msg += " has failed"          else: +            msg += f" has completed with return code {self.returncode}"              # Try to append signal's name if one exists              with contextlib.suppress(ValueError):                  name = Signals(self.returncode - 128).name -                msg = f"{msg} ({name})" - -        # Add error message for failed attachments -        if self.failed_files: -            failed_files = f"({', '.join(self.failed_files)})" -            # Case for over 10 -            if len(self.failed_files) + len(self.files) > FILE_COUNT_LIMIT: -                msg += ( -                    f".\n\n> Some files were not able to be uploaded, as they exceeded" -                    f" the {FILE_COUNT_LIMIT} file upload limit {failed_files}" -                ) -            else: -                msg += ( -                    f".\n\n> Some files were not able to be uploaded {failed_files}." -                    f" Check that the file size is less than {sizeof_fmt(FILE_SIZE_LIMIT)}" -                ) - -        return msg, error +                msg += f" ({name})" + +        return msg      @classmethod      def from_dict(cls, data: dict[str, str | int | list[dict[str, str]]]) -> EvalResult: | 
