Skip to content

Commit 5a23cc2

Browse files
committed
😡Ruff it up x3
1 parent 9ebe525 commit 5a23cc2

File tree

7 files changed

+63
-40
lines changed

7 files changed

+63
-40
lines changed

__main__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from utils.database import create_pool
1212

1313
try:
14-
import uvloop # type: ignore
14+
import uvloop # pyright: ignore[reportMissingImports]
1515
except ImportError:
1616
# WINDOWS
1717
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

bot/bot.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ def __init__(
9090
# TODO: fill in scopes= argument once we figure out what it's used for :x
9191
)
9292
self.database: asyncpg.Pool[asyncpg.Record] = pool
93-
self.pool: PoolTypedWithAny = pool # type: ignore # asyncpg typehinting crutch, read `utils.database` for more
93+
# asyncpg typehinting crutch, read `utils.database` for more
94+
self.pool: PoolTypedWithAny = pool # pyright: ignore[reportAttributeAccessIssue]
9495
self.session: ClientSession = session
9596
self.extensions: tuple[str, ...] = EXTENSIONS
9697

@@ -119,6 +120,10 @@ def __init__(
119120
# print(auth_url) # noa: T201
120121

121122
def print_bot_oauth(self) -> None:
123+
"""Print a link for me (developer) to click and authorize the bot scopes for the bot account.
124+
125+
Required for proper work of Twitch Eventsub events and API requests.
126+
"""
122127
scopes = "%20".join(
123128
[
124129
"user:read:chat",
@@ -135,14 +140,16 @@ def print_bot_oauth(self) -> None:
135140
print(f"🤖🤖🤖 BOT OAUTH LINK: 🤖🤖🤖\n{link}") # noqa: T201
136141

137142
def print_broadcaster_oauth(self) -> None:
138-
"""
143+
"""Print a link for streamers to click and authorize the scopes for the bot.
144+
145+
Required for proper work of Twitch Eventsub events and API requests.
139146
140147
Notes
141148
-----
142149
* Currently my developer console has localhost as a callback: http://localhost:4343/oauth/callback
143150
But if we ever switch to multi-streams setup then I already have some things set up with
144151
* https://parrot-thankful-trivially.ngrok-free.app/oauth/callback (in developer console)
145-
* ngrok http --url=parrot-thankful-trivially.ngrok-free.app 80 (in my/vps terminal)
152+
* `ngrok http --url=parrot-thankful-trivially.ngrok-free.app 80` (in my/vps terminal)
146153
Look ngrok dashboard for more.
147154
148155
With it a user needs to go to a link like this:
@@ -172,7 +179,8 @@ async def setup_hook(self) -> None:
172179
for the first time (or after adding extra scopes):
173180
1. Uncomment three first lines in this function;
174181
2. Run the bot;
175-
3. Click generated links using proper accounts (i.e. broadcaster = the browser with streamer account logged in);
182+
3. Click generated links using proper accounts:
183+
(i.e. broadcaster = the browser with streamer account logged in);
176184
4. The bot will update the tokens in the database automatically;
177185
5. Comment the lines back. In normal state, they should be commented.
178186
@@ -188,10 +196,9 @@ async def setup_hook(self) -> None:
188196
self.check_if_online.start()
189197

190198
async def create_eventsub_subscriptions(self) -> None:
191-
"""
192-
Subscribe to all EventSub subscriptions that are required for the bot to work.
193-
The function also includes (in code) a table showcasing which subscriptions/scopes are required for what.
199+
"""Subscribe to all EventSub subscriptions that are required for the bot to work.
194200
201+
The function also includes (in code) a table showcasing which subscriptions/scopes are required for what.
195202
For more links:
196203
197204
TwitchDev Docs
@@ -261,7 +268,7 @@ async def add_token(self, token: str, refresh: str) -> twitchio.authentication.V
261268
return resp
262269

263270
@override
264-
async def load_tokens(self, path: str | None = None) -> None:
271+
async def load_tokens(self, _: str | None = None) -> None: # _ is `path`
265272
# We don't need to call this manually, it is called in .login() from .start() internally...
266273

267274
rows: list[LoadTokensQueryRow] = await self.pool.fetch("""SELECT * from ttv_tokens""")
@@ -328,9 +335,9 @@ async def event_command_error(self, payload: commands.CommandErrorPayload) -> No
328335
}
329336
await ctx.send(guard_mapping.get(error.guard.__qualname__, str(error)))
330337
case twitchio.HTTPException():
331-
# log.error("%s", error.__class__.__name__, exc_info=error)
332338
await ctx.send(
333-
f"{error.extra.get('error', 'Error')} {error.extra.get('status', 'XXX')}: "
339+
f"{error.extra.get('error', 'Error')} "
340+
f"{error.extra.get('status', 'XXX')}: "
334341
f"{error.extra.get('message', 'Unknown')} {const.STV.dankFix}",
335342
)
336343
case commands.MissingRequiredArgument():
@@ -406,19 +413,26 @@ def error_ping(self) -> str:
406413
return config.ERROR_PING
407414

408415
async def aluerie_stream(self) -> twitchio.Stream | None:
416+
"""Shortcut to get @Aluerie's stream."""
409417
return next(iter(await self.fetch_streams(user_ids=[const.UserID.Aluerie])), None)
410418

411419
@lueloop(count=1)
412420
async def check_if_online(self) -> None:
421+
"""Check if aluerie is online - used to make my own (proper) online event instead of twitchio's."""
413422
await asyncio.sleep(1.0) # just in case;
414423
if await self.aluerie_stream():
415424
self.aluerie_online = True
416425
self.dispatch("aluerie_online")
417426

418427
async def event_stream_online(self, _: twitchio.StreamOnline) -> None:
428+
"""Instead of the twitchio event - dispatch my own online event.
429+
430+
The difference is that my event accounts for the state of my stream when the bot restarts.
431+
"""
419432
self.aluerie_online = True
420433
self.dispatch("aluerie_online")
421434

422435
async def event_stream_offline(self, _: twitchio.StreamOffline) -> None:
436+
"""Instead of the twitchio event - dispatch my own offline event."""
423437
self.aluerie_online = False
424438
self.dispatch("aluerie_offline")

bot/exc_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ async def register_error(self, error: BaseException, embed: discord.Embed, *, me
5757
await asyncio.sleep(total_seconds)
5858

5959
self._most_recent = datetime.datetime.now(datetime.UTC)
60-
await self.send_error(traceback_string, embed, mention)
60+
await self.send_error(traceback_string, embed, mention=mention)
6161

62-
async def send_error(self, traceback: str, embed: discord.Embed, mention: bool) -> None:
62+
async def send_error(self, traceback: str, embed: discord.Embed, *, mention: bool) -> None:
6363
"""Send an error to the webhook.
6464
6565
It is not recommended to call this yourself, call `register_error` instead.

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ ignore = [
133133
# "UP038",
134134

135135
# DOC STRINGS
136-
# general doc string exceptions
136+
# 1. General doc string exceptions
137137
"D100", # Missing docstring in module: no, module level docs aren't always needed
138138
"D105", # Missing docstring in magic method: documenting magic methods is often dumb.
139139
"D107", # Missing docstring in `__init__`: __init__ is the wrong place to doc this.
140140
"D401", # Doc should be starting with an imperative verb: dumb rule, to be honest.
141-
# doc string exceptions
142-
# for this bot because it's a bot and it's pointless to document *everything* in one-man project.
141+
# 2. Exceptions for this bot because it's pointless to document *everything* in one-man project.
143142
"DOC201", # `return` is not documented in docstring
143+
"DOC501", # raised exception is missing from docstring
144144

145145
# "D104", # Missing docstring in public package. Otherwise spams __init__.py and such.
146146
# "D417", # Missing argument description. Otherwise, it keeps asking to document interaction/context args.

utils/formats.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def __init__(self, number: int) -> None:
3333
@override
3434
def __format__(self, format_spec: str) -> str:
3535
number = self.number
36-
singular, separator, plural = format_spec.partition("|")
36+
singular, _, plural = format_spec.partition("|") # _ is `separator`
3737
plural = plural or f"{singular}s"
3838
if abs(number) != 1:
3939
return f"{number} {plural}"
@@ -60,11 +60,10 @@ def timedelta_to_words(
6060
6161
Example:
6262
-------
63-
```py
63+
```
6464
x = datetime.timedelta(seconds=66)
6565
timedelta_to_words(x) # "1 minute 6 seconds"
6666
```
67-
6867
"""
6968
if delta is not MISSING and seconds is not MISSING:
7069
msg = "Cannot mix `delta` and `seconds` keyword arguments."
@@ -98,12 +97,13 @@ def timedelta_to_words(
9897

9998

10099
def ordinal(n: int | str) -> str:
101-
"""Convert an integer into its ordinal representation, i.e. 0->'0th', '3'->'3rd'."""
102-
# Remember that there is always funny lambda possibility
103-
# ```py
104-
# ordinal = lambda n: "%d%s" % (n, "tsnrhtdd"[(n // 10 % 10 != 1) * (n % 10 < 4) * n % 10::4])
105-
# print([ordinal(n) for n in range(1,32)])
106-
# ```
100+
"""Convert an integer into its ordinal representation, i.e. 0->'0th', '3'->'3rd'.
101+
102+
Dev Note
103+
--------
104+
Remember that there is always a funny lambda possibility
105+
`ordinal = lambda n: "%d%s" % (n, "tsnrhtdd"[(n // 10 % 10 != 1) * (n % 10 < 4) * n % 10::4])`
106+
"""
107107
n = int(n)
108108
suffix = "th" if 11 <= n % 100 <= 13 else ["th", "st", "nd", "rd", "th"][min(n % 10, 4)]
109109
return str(n) + suffix

utils/fuzzy.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
"""This Source Code Form is subject to the terms of the Mozilla Public
2-
License, v. 2.0. If a copy of the MPL was not distributed with this
3-
file, You can obtain one at http://mozilla.org/MPL/2.0/.
1+
"""Fuzzy wuzzy string matching utilities.
2+
3+
Sources
4+
-------
5+
* `fuzzy.py` file from RoboDanny (license MPL v2 from Rapptz/RoboDanny)
6+
https://github.com/Rapptz/RoboDanny/blob/rewrite/cogs/utils/fuzzy.py
7+
* Helpful article:
8+
http://chairnerd.seatgeek.com/fuzzywuzzy-fuzzy-string-matching-in-python/
49
"""
510

6-
# help with: http://chairnerd.seatgeek.com/fuzzywuzzy-fuzzy-string-matching-in-python/
7-
811
from __future__ import annotations
912

1013
import heapq
14+
import operator
1115
import re
1216
from difflib import SequenceMatcher
1317
from typing import TYPE_CHECKING, Literal, TypeVar, overload
@@ -20,12 +24,12 @@
2024

2125
def ratio(a: str, b: str) -> int:
2226
m = SequenceMatcher(None, a, b)
23-
return int(round(100 * m.ratio()))
27+
return round(100 * m.ratio())
2428

2529

2630
def quick_ratio(a: str, b: str) -> int:
2731
m = SequenceMatcher(None, a, b)
28-
return int(round(100 * m.quick_ratio()))
32+
return round(100 * m.quick_ratio())
2933

3034

3135
def partial_ratio(a: str, b: str) -> int:
@@ -35,7 +39,7 @@ def partial_ratio(a: str, b: str) -> int:
3539
blocks = m.get_matching_blocks()
3640

3741
scores: list[float] = []
38-
for i, j, n in blocks:
42+
for i, j, _ in blocks:
3943
start = max(j - i, 0)
4044
end = start + len(short)
4145
o = SequenceMatcher(None, short, long[start:end])
@@ -45,7 +49,7 @@ def partial_ratio(a: str, b: str) -> int:
4549
return 100
4650
scores.append(r)
4751

48-
return int(round(100 * max(scores)))
52+
return round(100 * max(scores))
4953

5054

5155
_word_regex = re.compile(r"\W", re.IGNORECASE)
@@ -142,8 +146,8 @@ def extract(
142146
) -> list[tuple[str, int]] | list[tuple[str, int, T]]:
143147
it = _extraction_generator(query, choices, scorer, score_cutoff)
144148
if limit is not None:
145-
return heapq.nlargest(limit, it, key=lambda t: t[1]) # pyright: ignore[reportReturnType]
146-
return sorted(it, key=lambda t: t[1], reverse=True) # pyright: ignore[reportReturnType]
149+
return heapq.nlargest(limit, it, key=operator.itemgetter(1)) # pyright: ignore[reportReturnType]
150+
return sorted(it, key=operator.itemgetter(1), reverse=True) # pyright: ignore[reportReturnType]
147151

148152

149153
@overload
@@ -172,10 +176,10 @@ def extract_one(
172176
*,
173177
scorer: Callable[[str, str], int] = quick_ratio,
174178
score_cutoff: int = 0,
175-
) -> tuple[str, int] | None | tuple[str, int, T]:
179+
) -> tuple[str, int] | tuple[str, int, T] | None:
176180
it = _extraction_generator(query, choices, scorer, score_cutoff)
177181
try:
178-
return max(it, key=lambda t: t[1])
182+
return max(it, key=operator.itemgetter(1))
179183
except:
180184
# iterator could return nothing
181185
return None

utils/helpers.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import logging
99
from time import perf_counter
10-
from typing import TYPE_CHECKING, Any, Self
10+
from typing import TYPE_CHECKING, Self
1111

1212
__all__ = ("measure_time",)
1313

@@ -48,7 +48,12 @@ async def __aenter__(self) -> Self:
4848
return self
4949

5050
def measure_time(self) -> None:
51-
# PT for Performance Time, maybe there are better ideas for abbreviations.
51+
"""Record and debug-log measured PT (Performance Time).
52+
53+
Notes
54+
-----
55+
* maybe there are better ideas for abbreviations than PT.
56+
"""
5257
self.end = end = perf_counter() - self.start
5358
self.log.debug("%s PT: %.3f secs", self.name, end)
5459

0 commit comments

Comments
 (0)