From 08416dead732cab03fad96406630036c3dc2cc15 Mon Sep 17 00:00:00 2001 From: Natalie Fearnley Date: Tue, 21 May 2024 00:24:17 -0400 Subject: [PATCH] cleaned up eval.py --- sizebot/cogs/eval.py | 6 +- sizebot/lib/eval.py | 147 ++++++++++++++++++++----------------------- 2 files changed, 70 insertions(+), 83 deletions(-) diff --git a/sizebot/cogs/eval.py b/sizebot/cogs/eval.py index d386ba6b..f1988d2b 100644 --- a/sizebot/cogs/eval.py +++ b/sizebot/cogs/eval.py @@ -7,7 +7,7 @@ from sizebot.lib import utils from sizebot.lib.constants import emojis -from sizebot.lib.eval import runEval +from sizebot.lib.eval import run_eval from sizebot.lib.types import BotContext @@ -36,7 +36,7 @@ async def eval(self, ctx: BotContext, *, evalStr: str): async with ctx.typing(): try: - result = await runEval(ctx, evalStr) + result = await run_eval(ctx, evalStr) except Exception as err: logger.error("eval error:\n" + utils.format_traceback(err)) await ctx.send(emojis.warning + f" ` {format_error(err)} `") @@ -69,7 +69,7 @@ async def evil(self, ctx: BotContext, *, evalStr: str): async with ctx.typing(): try: - await runEval(ctx, evalStr) + await run_eval(ctx, evalStr) except Exception as err: logger.error("eval error:\n" + utils.format_traceback(err)) await ctx.author.send(emojis.warning + f" ` {format_error(err)} `") diff --git a/sizebot/lib/eval.py b/sizebot/lib/eval.py index d1085136..2352b17a 100644 --- a/sizebot/lib/eval.py +++ b/sizebot/lib/eval.py @@ -34,59 +34,7 @@ logger = logging.getLogger("sizebot") -def eformat(name: str, value: Any) -> str: - if value is None: - emojiType = "❓" - elif callable(value): - emojiType = "🚙" - elif isinstance(value, (list, tuple)): - emojiType = "🗒️" - elif isinstance(value, set): - emojiType = "📘" - elif isinstance(value, dict): - emojiType = "📗" - elif isinstance(value, bool): - if value: - emojiType = "✅" - else: - emojiType = "❎" - elif isinstance(value, (int, float)): - emojiType = "💯" - elif isinstance(value, str): - emojiType = "✏️" - elif isinstance(value, discord.member.Member): - emojiType = "👥" - elif isinstance(value, discord.user.User): - emojiType = "👤" - elif isinstance(value, commands.Bot): - emojiType = "🤖" - elif isinstance(value, commands.cog.Cog): - emojiType = "⚙️" - elif isinstance(value, SV): - emojiType = "🇸" - elif isinstance(value, WV): - emojiType = "🇼" - elif isinstance(value, TV): - emojiType = "🇹" - elif isinstance(value, arrow.arrow.Arrow): - emojiType = "🏹" - else: - emojiType = "▫️" - return f"{emojiType} {name}" - - -def edir(o: Any) -> Embed: - """send embed of an object's attributes, with type notation""" - e = Embed(title=utils.get_fullname(o)) - attrs = [eformat(n, v) for n, v in ddir(o).items()] - pageLen = math.ceil(len(attrs) / 3) - for page in utils.chunk_list(attrs, pageLen): - e.add_field(value="\n".join(page)) - return e - - -# TODO: CamelCase -def cachedCopy(fn: Callable) -> Callable: +def _cached_copy(fn: Callable) -> Callable: """Decorator that calls the wrapper function the first time it's called, and returns copies of the cached result on all later calls""" isCached = False r = None @@ -102,9 +50,8 @@ def wrapper(*args, **kwargs) -> Any: return wrapper -# TODO: CamelCase -@cachedCopy -def getEvalGlobals() -> dict[str, Any]: +@_cached_copy +def get_eval_globals() -> dict[str, Any]: """Construct a globals dict for eval""" # Create a dict of builtins, excluding any in the blacklist blacklist = [ @@ -122,10 +69,10 @@ def getEvalGlobals() -> dict[str, Any]: "super", "__import__" ] - evalBuiltins = {n: (v if n not in blacklist else None) for n, v in vars(builtins).items()} + eval_builtins = {n: (v if n not in blacklist else None) for n, v in vars(builtins).items()} - evalGlobals = { - "__builtins__": evalBuiltins, + eval_globals = { + "__builtins__": eval_builtins, "inspect": inspect, "help": str_help, "Decimal": Decimal, @@ -146,7 +93,6 @@ def getEvalGlobals() -> dict[str, Any]: "emojis": emojis, "itertools": itertools, "conf": conf, - "findOne": find_one, "datetime": datetime, "date": date, "time": time, @@ -163,14 +109,13 @@ def getEvalGlobals() -> dict[str, Any]: "errors": errors, "arrow": arrow, "roll": roll, - "_evalmath": _evalmath + "evalmath": _evalmath } - return evalGlobals + return eval_globals -# TODO: CamelCase -def buildEvalWrapper(evalStr: str, addReturn: bool = True) -> tuple[CodeType, str]: +def _build_eval_wrapper(evalStr: str, addReturn: bool = True) -> tuple[CodeType, str]: """Build a wrapping async function that lets the eval command run multiple lines, and return the result of the last line""" evalLines = evalStr.rstrip().split("\n") if evalLines[-1].startswith(" "): @@ -183,21 +128,20 @@ def buildEvalWrapper(evalStr: str, addReturn: bool = True) -> tuple[CodeType, st except SyntaxError: # If we get a syntax error, maybe it's because someone is trying to do an assignment on the last line? Might as well try it without a return statement and see if it works. if addReturn: - return buildEvalWrapper(evalStr, False) + return _build_eval_wrapper(evalStr, False) raise return evalWrapper, evalWrapperStr -# TODO: CamelCase -async def runEval(ctx: BotContext, evalStr: str) -> Any: - evalGlobals = getEvalGlobals() +async def run_eval(ctx: BotContext, evalStr: str) -> Any: + evalGlobals = get_eval_globals() evalLocals = {} # Add ctx to the globals evalGlobals["ctx"] = ctx - evalWrapper, evalWrapperStr = buildEvalWrapper(evalStr) + evalWrapper, evalWrapperStr = _build_eval_wrapper(evalStr) logger.debug(f"Executing eval:\n{evalWrapperStr}") @@ -211,7 +155,58 @@ async def runEval(ctx: BotContext, evalStr: str) -> Any: return await evalFn() -def pformat(name: str, value: Any) -> str: +def _eformat(name: str, value: Any) -> str: + if value is None: + emojiType = "❓" + elif callable(value): + emojiType = "🚙" + elif isinstance(value, (list, tuple)): + emojiType = "🗒️" + elif isinstance(value, set): + emojiType = "📘" + elif isinstance(value, dict): + emojiType = "📗" + elif isinstance(value, bool): + if value: + emojiType = "✅" + else: + emojiType = "❎" + elif isinstance(value, (int, float)): + emojiType = "💯" + elif isinstance(value, str): + emojiType = "✏️" + elif isinstance(value, discord.member.Member): + emojiType = "👥" + elif isinstance(value, discord.user.User): + emojiType = "👤" + elif isinstance(value, commands.Bot): + emojiType = "🤖" + elif isinstance(value, commands.cog.Cog): + emojiType = "⚙️" + elif isinstance(value, SV): + emojiType = "🇸" + elif isinstance(value, WV): + emojiType = "🇼" + elif isinstance(value, TV): + emojiType = "🇹" + elif isinstance(value, arrow.arrow.Arrow): + emojiType = "🏹" + else: + emojiType = "▫️" + return f"{emojiType} {name}" + + +def edir(o: Any) -> Embed: + """send embed of an object's attributes, with type notation""" + e = Embed(title=utils.get_fullname(o)) + attrs = [_eformat(n, v) for n, v in _ddir(o).items()] + pageLen = math.ceil(len(attrs) / 3) + for page in utils.chunk_list(attrs, pageLen): + e.add_field(value="\n".join(page)) + return e + + +def _pformat(name: str, value: Any) -> str: if value is None: return f"{name}?" if callable(value): @@ -227,21 +222,13 @@ def pformat(name: str, value: Any) -> str: def pdir(o: Any) -> list: """return a list of an object's attributes, with type notation.""" - return [pformat(n, v) for n, v in ddir(o).items()] + return [_pformat(n, v) for n, v in _ddir(o).items()] -def ddir(o: Any) -> dict: +def _ddir(o: Any) -> dict: """return a dictionary of an object's attributes.""" return {n: v for n, v in inspect.getmembers(o) if not n.startswith("_")} -def find_one(iterator: Iterator) -> Any | None: - try: - val = next(iterator) - except StopIteration: - val = None - return val - - def str_help(topic: str) -> str: return pydoc.plain(pydoc.render_doc(topic))