Skip to content

Commit 39fb0ee

Browse files
committed
fixed all the bugs
1 parent 176d4de commit 39fb0ee

File tree

9 files changed

+231
-127
lines changed

9 files changed

+231
-127
lines changed

bot.py

+14-7
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
SOFTWARE.
2222
"""
23+
from __future__ import annotations
24+
25+
import asyncio
2326
import json
2427
import pathlib
2528
from asyncio import Queue
2629
from collections import deque
27-
from typing import Any
30+
from typing import TYPE_CHECKING, Any
2831

2932
import aiohttp
3033
import asyncpg
@@ -38,12 +41,16 @@
3841
from modules import EXTENSIONS
3942

4043

44+
if TYPE_CHECKING:
45+
from logging import LogRecord
46+
47+
4148
class Bot(commands.Bot):
4249
session: aiohttp.ClientSession
4350
pool: asyncpg.Pool[asyncpg.Record]
4451
log_handler: LogHandler
4552
mb_client: mystbin.Client
46-
logging_queue: Queue[str]
53+
logging_queue: Queue[LogRecord]
4754

4855
__slots__ = (
4956
"session",
@@ -67,15 +74,12 @@ async def get_context(self, message: discord.Message | discord.Interaction) -> C
6774
async def on_ready(self) -> None:
6875
"""On Bot ready - cache is built."""
6976
assert self.user
70-
print(f"Online. Logged in as {self.user.name} || {self.user.id}")
77+
self.log_handler.info("Online. Logged in as %s || %s", self.user.name, self.user.id)
7178

7279
async def on_socket_response(self, message: Any) -> None:
7380
"""Quick override to log websocket events."""
7481
self._previous_websocket_events.append(message)
7582

76-
async def setup_hook(self) -> None:
77-
self.session = aiohttp.ClientSession()
78-
7983
async def start(self, token: str, *, reconnect: bool = True) -> None:
8084
try:
8185
await super().start(token=token, reconnect=reconnect)
@@ -99,7 +103,7 @@ async def close(self) -> None:
99103
async def main() -> None:
100104
async with Bot() as bot, aiohttp.ClientSession() as session, asyncpg.create_pool(
101105
dsn=CONFIG["DATABASE"]["dsn"]
102-
) as pool, LogHandler() as handler:
106+
) as pool, LogHandler(bot=bot) as handler:
103107
bot.logging_queue = Queue()
104108
bot.session = session
105109
bot.pool = pool
@@ -117,3 +121,6 @@ async def main() -> None:
117121
)
118122

119123
await bot.start(CONFIG["TOKENS"]["bot"])
124+
125+
126+
asyncio.run(main())

core/context.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import discord
66
from discord.ext import commands
77

8+
89
if TYPE_CHECKING:
910
from bot import Bot
1011

@@ -13,8 +14,8 @@
1314
"Interaction",
1415
)
1516

16-
Interaction: TypeAlias = discord.Interaction[Bot]
17+
Interaction: TypeAlias = discord.Interaction["Bot"]
1718

1819

19-
class Context(commands.Context[Bot]):
20+
class Context(commands.Context["Bot"]):
2021
pass

core/utils/logging.py

+23-101
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,39 @@
33
import logging
44
import pathlib
55
from logging.handlers import RotatingFileHandler
6-
from typing import TYPE_CHECKING, Any, Mapping
6+
from typing import TYPE_CHECKING, Any
77

8-
from discord.utils import (
9-
_ColourFormatter as ColourFormatter, # type: ignore # shh, I need it
10-
)
11-
from discord.utils import stream_supports_colour
8+
from discord.utils import _ColourFormatter as ColourFormatter, stream_supports_colour # type: ignore # shh, I need it
129

13-
if TYPE_CHECKING:
14-
from logging import _ExcInfoType # type: ignore # shh, I need it
1510

11+
if TYPE_CHECKING:
1612
from typing_extensions import Self
1713

14+
from bot import Bot
15+
16+
17+
class QueueEmitHandler(logging.Handler):
18+
def __init__(self, bot: Bot, /) -> None:
19+
self.bot: Bot = bot
20+
super().__init__(logging.INFO)
21+
22+
def emit(self, record: logging.LogRecord) -> None:
23+
self.bot.logging_queue.put_nowait(record)
24+
1825

1926
class LogHandler:
20-
def __init__(self, *, stream: bool = True) -> None:
27+
def __init__(self, *, bot: Bot, stream: bool = True) -> None:
2128
self.log: logging.Logger = logging.getLogger()
2229
self.max_bytes: int = 32 * 1024 * 1024
2330
self.logging_path = pathlib.Path("./logs/")
2431
self.logging_path.mkdir(exist_ok=True)
2532
self.stream: bool = stream
33+
self.bot: Bot = bot
34+
self.debug = self.log.debug
35+
self.info = self.log.info
36+
self.warning = self.log.warning
37+
self.error = self.log.error
38+
self.critical = self.log.critical
2639

2740
async def __aenter__(self) -> Self:
2841
return self.__enter__()
@@ -40,9 +53,7 @@ def __enter__(self: Self) -> Self:
4053
backupCount=5,
4154
)
4255
dt_fmt = "%Y-%m-%d %H:%M:%S"
43-
fmt = logging.Formatter(
44-
"[{asctime}] [{levelname:<7}] {name}: {message}", dt_fmt, style="{"
45-
)
56+
fmt = logging.Formatter("[{asctime}] [{levelname:<7}] {name}: {message}", dt_fmt, style="{")
4657
handler.setFormatter(fmt)
4758
self.log.addHandler(handler)
4859

@@ -51,6 +62,7 @@ def __enter__(self: Self) -> Self:
5162
if stream_supports_colour(stream_handler):
5263
stream_handler.setFormatter(ColourFormatter())
5364
self.log.addHandler(stream_handler)
65+
self.log.addHandler(QueueEmitHandler(self.bot))
5466

5567
return self
5668

@@ -62,93 +74,3 @@ def __exit__(self, *args: Any) -> None:
6274
for hdlr in handlers:
6375
hdlr.close()
6476
self.log.removeHandler(hdlr)
65-
66-
def debug(
67-
self,
68-
message: object,
69-
*args: Any,
70-
exc_info: _ExcInfoType,
71-
stack_info: bool = False,
72-
stack_level: int = 1,
73-
extra: Mapping[str, Any] | None = None,
74-
) -> None:
75-
self.log.debug(
76-
msg=message,
77-
*args,
78-
exc_info=exc_info,
79-
stack_info=stack_info,
80-
stacklevel=stack_level,
81-
extra=extra,
82-
)
83-
84-
def info(
85-
self,
86-
message: object,
87-
*args: Any,
88-
exc_info: _ExcInfoType,
89-
stack_info: bool = False,
90-
stack_level: int = 1,
91-
extra: Mapping[str, Any] | None = None,
92-
) -> None:
93-
self.log.info(
94-
msg=message,
95-
*args,
96-
exc_info=exc_info,
97-
stack_info=stack_info,
98-
stacklevel=stack_level,
99-
extra=extra,
100-
)
101-
102-
def warning(
103-
self,
104-
message: object,
105-
*args: Any,
106-
exc_info: _ExcInfoType,
107-
stack_info: bool = False,
108-
stack_level: int = 1,
109-
extra: Mapping[str, Any] | None = None,
110-
) -> None:
111-
self.log.warning(
112-
msg=message,
113-
*args,
114-
exc_info=exc_info,
115-
stack_info=stack_info,
116-
stacklevel=stack_level,
117-
extra=extra,
118-
)
119-
120-
def error(
121-
self,
122-
message: object,
123-
*args: Any,
124-
exc_info: _ExcInfoType,
125-
stack_info: bool = False,
126-
stack_level: int = 1,
127-
extra: Mapping[str, Any] | None = None,
128-
) -> None:
129-
self.log.warning(
130-
msg=message,
131-
*args,
132-
exc_info=exc_info,
133-
stack_info=stack_info,
134-
stacklevel=stack_level,
135-
extra=extra,
136-
)
137-
138-
def critical(
139-
self,
140-
message: object,
141-
*args: Any,
142-
exc_info: _ExcInfoType,
143-
stack_info: bool = False,
144-
stack_level: int = 1,
145-
extra: Mapping[str, Any] | None = None,
146-
) -> None:
147-
self.log.critical(
148-
msg=message,
149-
*args,
150-
exc_info=exc_info,
151-
stack_info=stack_info,
152-
stacklevel=stack_level,
153-
extra=extra,
154-
)

dev-requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
black
2+
isort

modules/eval.py

+20-12
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ def __init__(self, bot: Bot, endpoint_url: str) -> None:
4747
self.bot: Bot = bot
4848
self.eval_endpoint: str = endpoint_url
4949

50+
async def perform_eval(self, code: Codeblock) -> str:
51+
async with self.bot.session.post(self.eval_endpoint, json={"input": code.content[1]}) as eval_response:
52+
if eval_response.status != 200:
53+
raise InvalidEval(eval_response.status, "There was an issue running this eval command.")
54+
55+
eval_data = await eval_response.json()
56+
57+
return eval_data["stdout"]
58+
5059
@commands.command()
5160
@commands.max_concurrency(1, per=commands.BucketType.user, wait=False)
5261
@commands.cooldown(rate=1, per=10.0, type=commands.BucketType.user)
@@ -58,21 +67,20 @@ async def eval(self, ctx: Context, *, code: Codeblock = commands.param(converter
5867
code_body: :class:`Codeblock`
5968
This will attempt to convert your current passed parameter into proper Python code.
6069
"""
70+
reaction = "\U00002705"
6171
async with ctx.typing():
62-
async with self.bot.session.post(self.eval_endpoint, json={"input": code.content[1]}) as eval_response:
63-
if eval_response.status != 200:
64-
# TODO: error logging? Error handler and webhook post. Global or local?
65-
raise InvalidEval(eval_response.status, "There was an issue running this eval command.")
66-
67-
eval_data = await eval_response.json()
68-
69-
stdout = eval_data["stdout"]
70-
71-
if len(stdout) > 500:
72-
codeblock = await self.bot.mb_client.create_paste(content=stdout, filename="eval.py")
72+
try:
73+
output = await self.perform_eval(code)
74+
except InvalidEval:
75+
reaction = "\U0000274c"
76+
return await ctx.message.add_reaction(reaction)
77+
78+
if len(output) > 1000:
79+
codeblock = await self.bot.mb_client.create_paste(content=output, filename="eval.py")
7380
else:
74-
codeblock = formatters.to_codeblock(stdout, escape_md=False)
81+
codeblock = formatters.to_codeblock(output, escape_md=False)
7582

83+
await ctx.message.add_reaction(reaction)
7684
await ctx.send(f"Hey {ctx.author.display_name}, here is your eval output:\n{codeblock}")
7785

7886
@eval.error

modules/logging.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222
"""
2323
from __future__ import annotations
2424

25+
import datetime
26+
import textwrap
2527
from typing import TYPE_CHECKING
2628

2729
import discord
2830
from discord.ext import commands, tasks
31+
from discord.utils import format_dt
2932

3033
import core
3134

@@ -37,13 +40,19 @@
3740
class Logging(commands.Cog):
3841
def __init__(self, bot: Bot) -> None:
3942
self.bot: Bot = bot
40-
self.webhook = discord.Webhook.from_url(core.CONFIG["LOGGING"]["webhook_url"], client=bot)
43+
self.webhook = discord.Webhook.from_url(core.CONFIG["LOGGING"]["webhook_url"], session=bot.session, client=bot)
4144

4245
@tasks.loop(seconds=0)
4346
async def logging_loop(self) -> None:
4447
to_log = await self.bot.logging_queue.get()
48+
attributes = {"INFO": "\U00002139\U0000fe0f", "WARNING": "\U000026a0\U0000fe0f"}
4549

46-
await self.webhook.send(to_log, username="PythonistaBot Logging")
50+
emoji = attributes.get(to_log.levelname, "\N{CROSS MARK}")
51+
dt = datetime.datetime.utcfromtimestamp(to_log.created)
52+
53+
message = textwrap.shorten(f"{emoji} {format_dt(dt)}\n{to_log.message}", width=1990)
54+
55+
await self.webhook.send(message, username="PythonistaBot Logging")
4756

4857

4958
async def setup(bot: Bot) -> None:

0 commit comments

Comments
 (0)