Skip to content

Commit 0f7f84d

Browse files
Paillat-devLumabotsIcebluewolfCopilot
authored
refactor: utils (#44)
* Move utils.py to utils/ * 🔥 Remove `filter_params` * ♻️ Merge `time_snowflake` and `generate_snowflake`, move `basic_autocomplete` to `utils/public.py` * ♻️ Merge `time_snowflake` and `generate_snowflake`, move `basic_autocomplete` to `utils/public.py` * 🔥 Remove `utils.sleep_until` * chore: Start migration to uv & ruff & hatch (#4) * Start migration to uv * Setup ruff and hatch * Change pre-commit to use ruff * Format with ruff * Fix mistake * Add dev deps * Change workflows to use uv and ruff * ➕ Add colorlog and remove requirements folder and fix build * 💚 Fix sphinx build ? * 🐛 Add __version.py for version management and update import in __init__.py * ✏️ Update lib-checks.yml to run ruff on ubuntu-latest * 🐛 Update lib-checks.yml to run mypy with uv * 🔥 Delete MANIFEST.in * ✨ Enhance lib-checks.yml to include ruff formatter check * ♻️ Refactor pyproject.toml and uv.lock to use optional-dependencies for voice and speed * Setup CHANGELOG.md (#6) * chore: update docs workflows to use 'uv' for dependency management (#33) * chore: Update localization workflows to use 'uv' for dependency management * chore: refactor Read the Docs configuration to use uv * 🔥 Move stuff to private * :refactor: move parse_time function to private utils and update references * 📝 update CHANGELOG to reflect utility function changes * 🎨 Format * ♻️ move deprecation utilities to private utils and update references * ♻️ move snowflake_time function to public.py * ♻️ move oauth_url and Undefined class to public.py; update imports * 📝 remove deprecated utility functions from documentation * 📝 remove (re)moved utility functions from documentation * 📝 add utils.resolve_template to changelog and remove from documentation * 🐛 fix import path for warn_deprecated utility function * :refactor: reorganize utility function imports and move evaluate_annotation to private module * ♻️ update import paths for utility functions to use relative imports * ♻️ move delay_task function to private * ♻️ removed `utils.get` in favor of `utils.find` * ♻️ removed `utils._unique` It was used twice, and once it wasn't even necessary * ♻️ move `async_all` to private * ♻️ move `maybe_coroutine` to private * ♻️ rename `maybe_coroutine` to `maybe_awaitable` * ♻️ move `sane_wait_for` to private * ♻️ move `format_dt` to public * ♻️ remove `as_chunks` function * 📝 update `utils.sleep_until` and `utils.parse_time` changelog to suggest alternatives * ♻️ move `compute_timedelta` function * ♻️ move `valid_icon_size` to `asset.py` * ♻️ refactor `utils.get` to `utils.find` across multiple files * ♻️ refactor markdown and mention handling functions in `__init__.py` and `public.py` * ♻️ move SnowflakeList to `private.py` * ♻️ move `find` function from `__init__.py` to `public.py` * ♻️ move `copy_doc` to private * ♻️ refactor `get` to `find` in onboarding and sticker modules * 🐛 fix `copy_doc` decorator usage in context.py * ♻️ move SequenceProxy to private module * ♻️ move cached_slot_property to private * 🚨 add noqa comments to prevent linting errors * ♻️ move get_slots function to private module * ♻️ refactor JSON serialization functions to private module * ♻️ replace custom cached_property implementation with functools.cached_property * ✏️ fix typo in CHANGELOG-V3.md * ➖ remove unused dependencies from pyproject.toml and uv.lock * ⚰️ remove test.py * ♻️ remove duplicate import of raw_mentions in __init__.py * 🐛 fix raw_role_mentions import in utils/__init__.py * 🔥 Duplicate `Iterable` import * Apply suggestion from @Lumabots Co-authored-by: Lumouille <[email protected]> Signed-off-by: Paillat <[email protected]> * 🔥 Simplify imports * 🔥 Simplify imports number 2 * 🔥 Simplify imports number 3 omg this is amazing * 🔥 Simplify imports number 4 omg this is amazing yee * 🔥 Simplify imports number 5 * Update discord/ext/commands/converter.py Co-authored-by: Ice Wolfy <[email protected]> Signed-off-by: Paillat <[email protected]> * Apply suggestions from code review Co-authored-by: Ice Wolfy <[email protected]> Co-authored-by: Lumouille <[email protected]> Signed-off-by: Paillat <[email protected]> * Update discord/state.py Co-authored-by: Lumouille <[email protected]> Signed-off-by: Paillat <[email protected]> * Update discord/state.py Co-authored-by: Lumouille <[email protected]> Signed-off-by: Paillat <[email protected]> * ♻️ Remove _ prefix in from and to json * ♻️ Make import less weird * Update utils.po Signed-off-by: Paillat <[email protected]> * empty commit * Update discord/poll.py Co-authored-by: Copilot <[email protected]> Signed-off-by: Paillat <[email protected]> * Update discord/utils/private.py Co-authored-by: Copilot <[email protected]> Signed-off-by: Paillat <[email protected]> * 🐛 Fix broken import after merge * 🐛 Fix emojis.json path * 🐛 Fix broken imports * 🎨 Format stuff * 🐛 Fix import --------- Signed-off-by: Paillat <[email protected]> Signed-off-by: Paillat <[email protected]> Co-authored-by: Lumouille <[email protected]> Co-authored-by: Ice Wolfy <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent d06725e commit 0f7f84d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1607
-1747
lines changed

CHANGELOG-V3.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,17 @@ release.
1212
### Deprecated
1313

1414
### Removed
15+
16+
- `utils.filter_params`
17+
- `utils.sleep_until` use `asyncio.sleep` combined with `datetime.datetime` instead
18+
- `utils.compute_timedelta` use the `datetime` module instead
19+
- `utils.resolve_invite`
20+
- `utils.resolve_template`
21+
- `utils.parse_time` use `datetime.datetime.fromisoformat` instead
22+
- `utils.time_snowflake` use `utils.generate_snowflake` instead
23+
- `utils.warn_deprecated`
24+
- `utils.deprecated`
25+
- `utils.get` use `utils.find` with `lambda i: i.attr == val` instead
26+
- `AsyncIterator.get` use `AsyncIterator.find` with `lambda i: i.attr == val` instead
27+
- `utils.as_chunks` use `itertools.batched` on Python 3.12+ or your own implementation
28+
instead

discord/__version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
from typing import Literal, NamedTuple
3737

38-
from .utils import deprecated
38+
from .utils.private import deprecated
3939
from ._version import __version__, __version_tuple__
4040

4141

discord/abc.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
runtime_checkable,
4242
)
4343

44+
from .utils.private import warn_deprecated
4445
from . import utils
4546
from .context_managers import Typing
4647
from .enums import ChannelType
@@ -724,7 +725,7 @@ def permissions_for(self, obj: Member | Role, /) -> Permissions:
724725
if obj.is_default():
725726
return base
726727

727-
overwrite = utils.get(self._overwrites, type=_Overwrites.ROLE, id=obj.id)
728+
overwrite = utils.find(lambda o: o.type == _Overwrites.ROLE and o.id == obj.id, self._overwrites)
728729
if overwrite is not None:
729730
base.handle_overwrite(overwrite.allow, overwrite.deny)
730731

@@ -1529,7 +1530,7 @@ async def send(
15291530
from .message import MessageReference # noqa: PLC0415
15301531

15311532
if not isinstance(reference, MessageReference):
1532-
utils.warn_deprecated(
1533+
warn_deprecated(
15331534
f"Passing {type(reference).__name__} to reference",
15341535
"MessageReference",
15351536
"2.7",

discord/activity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from .colour import Colour
3333
from .enums import ActivityType, try_enum
3434
from .partial_emoji import PartialEmoji
35-
from .utils import _get_as_snowflake
35+
from .utils.private import get_as_snowflake
3636

3737
__all__ = (
3838
"BaseActivity",
@@ -226,7 +226,7 @@ def __init__(self, **kwargs):
226226
self.timestamps: ActivityTimestamps = kwargs.pop("timestamps", {})
227227
self.assets: ActivityAssets = kwargs.pop("assets", {})
228228
self.party: ActivityParty = kwargs.pop("party", {})
229-
self.application_id: int | None = _get_as_snowflake(kwargs, "application_id")
229+
self.application_id: int | None = get_as_snowflake(kwargs, "application_id")
230230
self.url: str | None = kwargs.pop("url", None)
231231
self.flags: int = kwargs.pop("flags", 0)
232232
self.sync_id: str | None = kwargs.pop("sync_id", None)

discord/appinfo.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
from typing import TYPE_CHECKING
2929

30+
from .utils.private import warn_deprecated, get_as_snowflake
3031
from . import utils
3132
from .asset import Asset
3233
from .permissions import Permissions
@@ -200,9 +201,9 @@ def __init__(self, state: ConnectionState, data: AppInfoPayload):
200201
self._summary: str = data["summary"]
201202
self.verify_key: str = data["verify_key"]
202203

203-
self.guild_id: int | None = utils._get_as_snowflake(data, "guild_id")
204+
self.guild_id: int | None = get_as_snowflake(data, "guild_id")
204205

205-
self.primary_sku_id: int | None = utils._get_as_snowflake(data, "primary_sku_id")
206+
self.primary_sku_id: int | None = get_as_snowflake(data, "primary_sku_id")
206207
self.slug: str | None = data.get("slug")
207208
self._cover_image: str | None = data.get("cover_image")
208209
self.terms_of_service_url: str | None = data.get("terms_of_service_url")
@@ -261,7 +262,7 @@ def summary(self) -> str | None:
261262
.. versionadded:: 1.3
262263
.. deprecated:: 2.7
263264
"""
264-
utils.warn_deprecated(
265+
warn_deprecated(
265266
"summary",
266267
"description",
267268
reference="https://discord.com/developers/docs/resources/application#application-object-application-structure",

discord/asset.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
MISSING = utils.MISSING
4848

4949

50+
def _valid_icon_size(size: int) -> bool:
51+
"""Icons must be power of 2 within [16, 4096]."""
52+
return not size & (size - 1) and 4096 >= size >= 16
53+
54+
5055
class AssetMixin:
5156
url: str
5257
_state: Any | None
@@ -373,7 +378,7 @@ def replace(
373378
url = url.with_path(f"{path}.{static_format}")
374379

375380
if size is not MISSING:
376-
if not utils.valid_icon_size(size):
381+
if not _valid_icon_size(size):
377382
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
378383
url = url.with_query(size=size)
379384
else:
@@ -400,7 +405,7 @@ def with_size(self, size: int, /) -> Asset:
400405
InvalidArgument
401406
The asset had an invalid size.
402407
"""
403-
if not utils.valid_icon_size(size):
408+
if not _valid_icon_size(size):
404409
raise InvalidArgument("size must be a power of 2 between 16 and 4096")
405410

406411
url = str(yarl.URL(self._url).with_query(size=size))

discord/audit_logs.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
from __future__ import annotations
2727

2828
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generator, TypeVar
29+
from functools import cached_property
2930

31+
from .utils.private import get_as_snowflake
3032
from . import enums, utils
3133
from .asset import Asset
3234
from .automod import AutoModAction, AutoModTriggerMetadata
@@ -559,21 +561,21 @@ def _from_data(self, data: AuditLogEntryPayload) -> None:
559561
# into meaningful data when requested
560562
self._changes = data.get("changes", [])
561563

562-
self.user = self._get_member(utils._get_as_snowflake(data, "user_id")) # type: ignore
563-
self._target_id = utils._get_as_snowflake(data, "target_id")
564+
self.user = self._get_member(get_as_snowflake(data, "user_id")) # type: ignore
565+
self._target_id = get_as_snowflake(data, "target_id")
564566

565567
def _get_member(self, user_id: int) -> Member | User | None:
566568
return self.guild.get_member(user_id) or self._users.get(user_id)
567569

568570
def __repr__(self) -> str:
569571
return f"<AuditLogEntry id={self.id} action={self.action} user={self.user!r}>"
570572

571-
@property
573+
@cached_property
572574
def created_at(self) -> datetime.datetime:
573575
"""Returns the entry's creation time in UTC."""
574576
return utils.snowflake_time(self.id)
575577

576-
@property
578+
@cached_property
577579
def target(
578580
self,
579581
) -> (
@@ -602,7 +604,7 @@ def category(self) -> enums.AuditLogActionCategory:
602604
"""The category of the action, if applicable."""
603605
return self.action.category
604606

605-
@property
607+
@cached_property
606608
def changes(self) -> AuditLogChanges:
607609
"""The list of changes this entry has."""
608610
obj = AuditLogChanges(self, self._changes, state=self._state)

discord/bot.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
from .shard import AutoShardedClient
6464
from .types import interactions
6565
from .user import User
66-
from .utils import MISSING, async_all, find, get
66+
from .utils import MISSING, find
67+
from .utils.private import async_all
6768

6869
if TYPE_CHECKING:
6970
from .member import Member
@@ -216,13 +217,13 @@ def get_application_command(
216217
return command
217218
elif (names := name.split())[0] == command.name and isinstance(command, SlashCommandGroup):
218219
while len(names) > 1:
219-
command = get(commands, name=names.pop(0))
220+
command = find(lambda c: c.name == names.pop(0), commands)
220221
if not isinstance(command, SlashCommandGroup) or (
221222
guild_ids is not None and command.guild_ids != guild_ids
222223
):
223224
return
224225
commands = command.subcommands
225-
command = get(commands, name=names.pop())
226+
command = find(lambda c: c.name == names.pop(), commands)
226227
if not isinstance(command, type) or (guild_ids is not None and command.guild_ids != guild_ids):
227228
return
228229
return command
@@ -357,7 +358,7 @@ def _check_command(cmd: ApplicationCommand, match: Mapping[str, Any]) -> bool:
357358

358359
# Now let's see if there are any commands on discord that we need to delete
359360
for cmd, value_ in registered_commands_dict.items():
360-
match = get(pending, name=value_["name"])
361+
match = find(lambda c: c.name == value_["name"], pending)
361362
if match is None:
362363
# We have this command registered but not in our list
363364
return_value.append(
@@ -516,7 +517,7 @@ def register(
516517
)
517518
continue
518519
# We can assume the command item is a command, since it's only a string if action is delete
519-
match = get(pending, name=cmd["command"].name, type=cmd["command"].type)
520+
match = find(lambda c: c.name == cmd["command"].name and c.type == cmd["command"].type, pending)
520521
if match is None:
521522
continue
522523
if cmd["action"] == "edit":
@@ -605,10 +606,9 @@ def register(
605606
registered = await register("bulk", data, guild_id=guild_id)
606607

607608
for i in registered:
608-
cmd = get(
609+
cmd = find(
610+
lambda c: c.name == i["name"] and c.type == i.get("type"),
609611
self.pending_application_commands,
610-
name=i["name"],
611-
type=i.get("type"),
612612
)
613613
if not cmd:
614614
raise ValueError(f"Registered command {i['name']}, type {i.get('type')} not found in pending commands")
@@ -712,11 +712,9 @@ async def on_connect():
712712
registered_guild_commands[guild_id] = app_cmds
713713

714714
for i in registered_commands:
715-
cmd = get(
715+
cmd = find(
716+
lambda c: c.name == i["name"] and c.guild_ids is None and c.type == i.get("type"),
716717
self.pending_application_commands,
717-
name=i["name"],
718-
guild_ids=None,
719-
type=i.get("type"),
720718
)
721719
if cmd:
722720
cmd.id = i["id"]

0 commit comments

Comments
 (0)