:spakles: eval keeps locals
This commit is contained in:
parent
6d1560ceaa
commit
924abea6c8
|
@ -1,8 +1,11 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
import traceback
|
import traceback
|
||||||
|
from contextlib import redirect_stdout
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
from textwrap import indent
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import TextChannel, PermissionOverwrite, Message, ChannelType
|
from discord import TextChannel, PermissionOverwrite, Message, ChannelType
|
||||||
|
@ -35,13 +38,14 @@ COGS_SHORTCUTS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
RE_QUERY = re.compile(
|
RE_QUERY = re.compile(
|
||||||
r"^! ?e(val)? (`{1,3}py(thon)?\n)?(?P<query>.*?)\n?(`{1,3})?\n?$", re.DOTALL
|
r"^! ?e(val)?[ \n]+(`{1,3}(py(thon)?\n)?)?(?P<query>.*?)\n?(`{1,3})?\n?$", re.DOTALL
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DevCog(Cog, name="Dev tools"):
|
class DevCog(Cog, name="Dev tools"):
|
||||||
def __init__(self, bot: CustomBot):
|
def __init__(self, bot: CustomBot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
self.eval_locals = {}
|
||||||
|
|
||||||
@command(name="interrupt")
|
@command(name="interrupt")
|
||||||
@has_role(Role.DEV)
|
@has_role(Role.DEV)
|
||||||
|
@ -225,57 +229,99 @@ class DevCog(Cog, name="Dev tools"):
|
||||||
await channel.delete_messages(to_delete)
|
await channel.delete_messages(to_delete)
|
||||||
await ctx.message.delete()
|
await ctx.message.delete()
|
||||||
|
|
||||||
def eval(self, msg: Message) -> discord.Embed:
|
async def eval(self, msg: Message) -> discord.Embed:
|
||||||
guild: discord.Guild = msg.guild
|
guild: discord.Guild = msg.guild
|
||||||
roles = guild.roles
|
roles = guild.roles
|
||||||
members = guild.members
|
members = guild.members
|
||||||
|
hugs_cog = self.bot.get_cog("Divers")
|
||||||
|
hugs = hugs_cog.hugs
|
||||||
|
channel: TextChannel = msg.channel
|
||||||
|
send = lambda text: asyncio.create_task(channel.send(text))
|
||||||
|
|
||||||
query = re.match(RE_QUERY, msg.content).group("query")
|
query = re.match(RE_QUERY, msg.content).group("query")
|
||||||
|
|
||||||
if not query:
|
if not query:
|
||||||
raise TfjmError("No query found.")
|
raise TfjmError("No query found.")
|
||||||
|
|
||||||
if "\n" in query:
|
if any(word in query for word in ("=", "return", "await", ":", "\n")):
|
||||||
lines = query.splitlines()
|
lines = query.splitlines()
|
||||||
if "return" not in lines[-1] and "=" not in lines[-1]:
|
if (
|
||||||
|
"return" not in lines[-1]
|
||||||
|
and "=" not in lines[-1]
|
||||||
|
and not lines[-1].startswith(" ")
|
||||||
|
):
|
||||||
lines[-1] = f"return {lines[-1]}"
|
lines[-1] = f"return {lines[-1]}"
|
||||||
query = "\n ".join(lines)
|
query = "\n".join(lines)
|
||||||
query = f"def q():\n {query}\nresp = q()"
|
full_query = f"""async def query():
|
||||||
|
try:
|
||||||
|
{indent(query, " " * 8)}
|
||||||
|
finally:
|
||||||
|
self.eval_locals.update(locals())
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
full_query = query
|
||||||
|
|
||||||
|
globs = {**globals(), **locals(), **self.eval_locals}
|
||||||
|
stdout = StringIO()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if "\n" in query:
|
with redirect_stdout(stdout):
|
||||||
q = compile(query, filename="query.py", mode="exec")
|
if "\n" in full_query:
|
||||||
globs = {**globals(), **locals()}
|
|
||||||
locs = {}
|
locs = {}
|
||||||
exec(query, globs, locs)
|
exec(full_query, globs, locs)
|
||||||
resp = locs["resp"]
|
resp = await locs["query"]()
|
||||||
else:
|
else:
|
||||||
resp = eval(query, globals(), locals())
|
resp = eval(query, globs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
tb = StringIO()
|
tb = StringIO()
|
||||||
traceback.print_tb(e.__traceback__, file=tb)
|
traceback.print_tb(e.__traceback__, file=tb)
|
||||||
tb.seek(0)
|
|
||||||
|
|
||||||
embed = discord.Embed(title=str(e), color=discord.Colour.red())
|
embed = discord.Embed(title=str(e), color=discord.Colour.red())
|
||||||
embed.add_field(name="Query", value=f"```py\n{query}\n```", inline=False)
|
|
||||||
embed.add_field(
|
embed.add_field(
|
||||||
name="Traceback", value=f"```py\n{tb.read()}```", inline=False
|
name="Query", value=f"```py\n{full_query}\n```", inline=False
|
||||||
|
)
|
||||||
|
embed.add_field(
|
||||||
|
name="Traceback", value=self.to_field_value(tb), inline=False
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
pprint(resp, out)
|
pprint(resp, out)
|
||||||
out.seek(0)
|
|
||||||
embed = discord.Embed(title="Result", color=discord.Colour.green())
|
embed = discord.Embed(title="Result", color=discord.Colour.green())
|
||||||
embed.add_field(name="Query", value=f"```py\n{query}```", inline=False)
|
embed.add_field(name="Query", value=f"```py\n{full_query}```", inline=False)
|
||||||
embed.add_field(name="Value", value=f"```py\n{out.read()}```", inline=False)
|
|
||||||
|
value = self.to_field_value(out)
|
||||||
|
if resp is not None and value:
|
||||||
|
embed.add_field(name="Value", value=value, inline=False)
|
||||||
|
|
||||||
|
stdout = self.to_field_value(stdout)
|
||||||
|
if stdout:
|
||||||
|
embed.add_field(name="Standard output", value=stdout, inline=False)
|
||||||
|
|
||||||
embed.set_footer(text="You may edit your message.")
|
embed.set_footer(text="You may edit your message.")
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
|
def to_field_value(self, string: Union[str, StringIO]):
|
||||||
|
if isinstance(string, StringIO):
|
||||||
|
string.seek(0)
|
||||||
|
string = string.read()
|
||||||
|
|
||||||
|
if not string:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(string) > 1000:
|
||||||
|
string = string[:500] + "\n...\n" + string[-500:]
|
||||||
|
|
||||||
|
return f"```py\n{string}```"
|
||||||
|
|
||||||
@command(name="eval", aliases=["e"])
|
@command(name="eval", aliases=["e"])
|
||||||
@is_owner()
|
@is_owner()
|
||||||
async def eval_cmd(self, ctx: Context):
|
async def eval_cmd(self, ctx: Context):
|
||||||
""""""
|
"""(dev) Evalue l'entrée."""
|
||||||
embed = self.eval(ctx.message)
|
|
||||||
|
self.eval_locals["ctx"] = ctx
|
||||||
|
|
||||||
|
embed = await self.eval(ctx.message)
|
||||||
resp = await ctx.send(embed=embed)
|
resp = await ctx.send(embed=embed)
|
||||||
|
|
||||||
def check(before, after):
|
def check(before, after):
|
||||||
|
@ -289,7 +335,7 @@ class DevCog(Cog, name="Dev tools"):
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
break
|
break
|
||||||
|
|
||||||
embed = self.eval(after)
|
embed = await self.eval(after)
|
||||||
await resp.edit(embed=embed)
|
await resp.edit(embed=embed)
|
||||||
|
|
||||||
# Remove the "You may edit your message"
|
# Remove the "You may edit your message"
|
||||||
|
|
|
@ -8,6 +8,7 @@ import urllib
|
||||||
from collections import defaultdict, Counter
|
from collections import defaultdict, Counter
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from itertools import groupby
|
||||||
from math import log
|
from math import log
|
||||||
from operator import attrgetter, itemgetter
|
from operator import attrgetter, itemgetter
|
||||||
from time import time
|
from time import time
|
||||||
|
@ -177,7 +178,7 @@ class MiscCog(Cog, name="Divers"):
|
||||||
|
|
||||||
@command(name="fan", aliases=["join", "adhere"], hidden=True)
|
@command(name="fan", aliases=["join", "adhere"], hidden=True)
|
||||||
async def fan_club_cmd(self, ctx: Context, who: Member):
|
async def fan_club_cmd(self, ctx: Context, who: Member):
|
||||||
"""Permet de rejoindre le fan-club d'Ananas ou Citron Vert."""
|
"""Permet de rejoindre un fan club existant."""
|
||||||
role_id = FAN_CLUBS.get(who.id, None)
|
role_id = FAN_CLUBS.get(who.id, None)
|
||||||
role = get(ctx.guild.roles, id=role_id)
|
role = get(ctx.guild.roles, id=role_id)
|
||||||
|
|
||||||
|
@ -362,10 +363,6 @@ class MiscCog(Cog, name="Divers"):
|
||||||
diffs[m.id].add(h.hugger)
|
diffs[m.id].add(h.hugger)
|
||||||
|
|
||||||
for m, d in diffs.items():
|
for m, d in diffs.items():
|
||||||
if m == self.bot.user.id:
|
|
||||||
print(everyone_diff)
|
|
||||||
print(d)
|
|
||||||
print(everyone_diff.union(d))
|
|
||||||
stats[m] += len(everyone_diff.union(d)) * 42 + everyone_hugs
|
stats[m] += len(everyone_diff.union(d)) * 42 + everyone_hugs
|
||||||
|
|
||||||
top = sorted(list(stats.items()), key=itemgetter(1), reverse=True)
|
top = sorted(list(stats.items()), key=itemgetter(1), reverse=True)
|
||||||
|
@ -392,10 +389,7 @@ class MiscCog(Cog, name="Divers"):
|
||||||
|
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=embed)
|
||||||
|
|
||||||
async def send_hugs_stats_for(self, ctx: Context, who: Member):
|
async def send_hugs_stats_for(self, ctx: Context, who: discord.Member):
|
||||||
embed = discord.Embed(
|
|
||||||
title=f"Câlins de {who.display_name}", color=discord.Colour.magenta()
|
|
||||||
)
|
|
||||||
|
|
||||||
given = self.hugs_given(ctx, who.id)
|
given = self.hugs_given(ctx, who.id)
|
||||||
received = self.hugs_received(ctx, who.id)
|
received = self.hugs_received(ctx, who.id)
|
||||||
|
@ -410,6 +404,26 @@ class MiscCog(Cog, name="Divers"):
|
||||||
"Morceaux": (len(cut), 30),
|
"Morceaux": (len(cut), 30),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
most_given = Counter(h.hugged for h in given).most_common(1)
|
||||||
|
most_received = Counter(h.hugger for h in received).most_common(1)
|
||||||
|
most_given = most_given[0] if most_given else (0, 0)
|
||||||
|
most_received = most_received[0] if most_received else (0, 0)
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"Câlins de {who.display_name}",
|
||||||
|
color=discord.Colour.magenta(),
|
||||||
|
description=(
|
||||||
|
f"On peut dire que {who.mention} est très câlin·e, avec un score de "
|
||||||
|
f"{self.score_for(ctx, who.id)}. Iel a beaucoup câliné "
|
||||||
|
f"{self.name_for(ctx, most_given[0])} "
|
||||||
|
f"*({most_given[1]} :heart:)* et "
|
||||||
|
f"s'est beaucoup fait câliner par {self.name_for(ctx, most_received[0])} "
|
||||||
|
f"*({most_received[1]} :heart:)* !"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
user: discord.User = self.bot.get_user(who.id)
|
||||||
|
embed.set_thumbnail(url=user.avatar_url)
|
||||||
|
|
||||||
for f, (v, h_factor) in infos.items():
|
for f, (v, h_factor) in infos.items():
|
||||||
heart = self.heart_for_stat(v * h_factor)
|
heart = self.heart_for_stat(v * h_factor)
|
||||||
if f == "Morceaux":
|
if f == "Morceaux":
|
||||||
|
@ -454,7 +468,13 @@ class MiscCog(Cog, name="Divers"):
|
||||||
if memb is not None:
|
if memb is not None:
|
||||||
name = memb.mention
|
name = memb.mention
|
||||||
else:
|
else:
|
||||||
name = ctx.guild.get_role(member_or_role_id).mention
|
role = ctx.guild.get_role(member_or_role_id)
|
||||||
|
if role is None:
|
||||||
|
name = getattr(
|
||||||
|
self.bot.get_user(member_or_role_id), "mention", "Personne"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
name = role.name
|
||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
|
@ -510,7 +510,7 @@ class TirageCog(Cog, name="Tirages"):
|
||||||
@commands.command(name="dice-all", aliases=["da"])
|
@commands.command(name="dice-all", aliases=["da"])
|
||||||
@commands.has_role(Role.DEV)
|
@commands.has_role(Role.DEV)
|
||||||
async def dice_all_cmd(self, ctx, *teams):
|
async def dice_all_cmd(self, ctx, *teams):
|
||||||
"""(dev) Lance un dé pour chaque equipe afin de tester les tirages."""
|
"""(dev) Lance un dé pour chaque equipe en entrée."""
|
||||||
channel = ctx.channel.id
|
channel = ctx.channel.id
|
||||||
if channel in self.tirages:
|
if channel in self.tirages:
|
||||||
for t in teams:
|
for t in teams:
|
||||||
|
|
|
@ -12,6 +12,7 @@ __all__ = [
|
||||||
"TEAMS_CHANNEL_CATEGORY",
|
"TEAMS_CHANNEL_CATEGORY",
|
||||||
"DIEGO",
|
"DIEGO",
|
||||||
"ANANAS",
|
"ANANAS",
|
||||||
|
"YOHANN",
|
||||||
"FAN_CLUBS",
|
"FAN_CLUBS",
|
||||||
"BOT",
|
"BOT",
|
||||||
"TOURNOIS",
|
"TOURNOIS",
|
||||||
|
|
Loading…
Reference in New Issue