Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions discord/commands/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@

if TYPE_CHECKING:
from collections.abc import Awaitable, Callable

from typing_extensions import ParamSpec
from typing import ParamSpec

import discord

Expand Down
9 changes: 4 additions & 5 deletions discord/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import inspect
import re
import types
from collections import OrderedDict
from collections.abc import Callable, Coroutine, Generator
from enum import Enum
from typing import (
Expand Down Expand Up @@ -84,9 +83,9 @@
)

if TYPE_CHECKING:
from typing import Concatenate
from typing import Concatenate, ParamSpec

from typing_extensions import Never, ParamSpec
from typing_extensions import Never

from .. import Permissions
from ..bot import C
Expand Down Expand Up @@ -479,7 +478,7 @@ async def dispatch_error(self, ctx: ApplicationContext, error: Exception) -> Non
ctx.bot.dispatch("application_command_error", ctx, error)

def _get_signature_parameters(self):
return OrderedDict(inspect.signature(self.callback).parameters)
return dict(inspect.signature(self.callback).parameters)

def error(self, coro):
"""A decorator that registers a coroutine as a local error handler.
Expand Down Expand Up @@ -915,7 +914,7 @@ def _match_option_param_names(self, params, options):
)
o._parameter_name = p_name

left_out_params = OrderedDict()
left_out_params = {}
for k, v in params:
left_out_params[k] = v
options.extend(self._parse_options(left_out_params, check_params=False))
Expand Down
95 changes: 47 additions & 48 deletions discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,49 +536,49 @@ def category(self) -> AuditLogActionCategory | None:

@property
def target_type(self) -> str | None:
v = self.value
if v == -1:
return "all"
elif v < 10:
return "guild"
elif v < 20:
return "channel"
elif v < 30:
return "user"
elif v < 40:
return "role"
elif v < 50:
return "invite"
elif v < 60:
return "webhook"
elif v < 70:
return "emoji"
elif v == 73:
return "channel"
elif v < 80:
return "message"
elif v < 83:
return "integration"
elif v < 90:
return "stage_instance"
elif v < 93:
return "sticker"
elif v < 103:
return "scheduled_event"
elif v < 113:
return "thread"
elif v < 122:
return "application_command_permission"
elif v < 146:
return "auto_moderation_rule"
elif v < 152:
return "monetization"
elif v < 168:
return "onboarding"
elif v < 192:
return "server_guide"
elif v < 194:
return "voice_channel_status"
match self.value:
Comment thread
Paillat-dev marked this conversation as resolved.
case -1:
return "all"
case v if v < 10:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also imo this hurts readability since it's not proper equivalence.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly went for it since it removes the repeated elif v < boilerplate. Under the hood this compiles to the same sequential guard evaluation as the if-elif chain, so there's no difference. I think the reduced repetition is worth it here, and PEP 634 explicitly documents guard clauses (case x if ...) as valid usage.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid sure but this is more confusing in this case. In my mind case x if is for specific edge cases, not 99% of the conditions. In this case it is just more messy.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not an actual convention and I think this comes down to preference rather than a correctness. Nothing in PEP63* suggests guards should stay rare relative to structural cases, and for a scalar subject like this there's no structural pattern to lean on in the first place, so guard-per-case is just what matching an int naturally looks like.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course it's preference.

return "guild"
case v if v < 20:
return "channel"
case v if v < 30:
return "user"
case v if v < 40:
return "role"
case v if v < 50:
return "invite"
case v if v < 60:
return "webhook"
case v if v < 70:
return "emoji"
case 73:
return "channel"
case v if v < 80:
return "message"
case v if v < 83:
return "integration"
case v if v < 90:
return "stage_instance"
case v if v < 93:
return "sticker"
case v if v < 103:
return "scheduled_event"
case v if v < 113:
return "thread"
case v if v < 122:
return "application_command_permission"
case v if v < 146:
return "auto_moderation_rule"
case v if v < 152:
return "monetization"
case v if v < 168:
return "onboarding"
case v if v < 192:
return "server_guide"
case v if v < 194:
return "voice_channel_status"


class UserFlags(Enum):
Expand Down Expand Up @@ -840,11 +840,10 @@ def from_datatype(cls, datatype):
else:
raise TypeError("Invalid usage of typing.Union")

py_3_10_union_type = hasattr(types, "UnionType") and isinstance(
datatype, types.UnionType
)

if py_3_10_union_type or getattr(datatype, "__origin__", None) is Union:
if (
isinstance(datatype, types.UnionType)
or getattr(datatype, "__origin__", None) is Union
):
# Python 3.10+ "|" operator or typing.Union has been used. The __args__ attribute is a tuple of the types.
# Type checking fails for this case, so ignore it.
return cls.from_datatype(datatype.__args__) # type: ignore
Expand Down
2 changes: 2 additions & 0 deletions discord/ext/commands/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
DEALINGS IN THE SOFTWARE.
"""

from __future__ import annotations

from collections.abc import Callable, Coroutine
from typing import TYPE_CHECKING, Any, TypeVar, Union

Expand Down
8 changes: 6 additions & 2 deletions discord/ext/commands/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from discord.message import Message

if TYPE_CHECKING:
from typing_extensions import ParamSpec
from typing import ParamSpec

from discord.abc import MessageableChannel
from discord.guild import Guild
Expand Down Expand Up @@ -311,7 +311,11 @@ def me(self) -> Member | ClientUser:
message contexts, or when :meth:`Intents.guilds` is absent.
"""
# bot.user will never be None at this point.
return self.guild.me if self.guild is not None and self.guild.me is not None else self.bot.user # type: ignore
return (
self.guild.me
if self.guild is not None and self.guild.me is not None
else self.bot.user
) # type: ignore

@property
def voice_client(self) -> VoiceProtocol | None:
Expand Down
10 changes: 7 additions & 3 deletions discord/ext/commands/cooldowns.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import time
from collections import deque
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, Deque, TypeVar
from typing import TYPE_CHECKING, Any, TypeVar

import discord.abc
from discord.enums import Enum
Expand Down Expand Up @@ -83,7 +83,11 @@ def get_key(self, msg: Message) -> Any:
# and that yields the same result as for a guild with only the @everyone role
# NOTE: PrivateChannel doesn't actually have an id attribute, but we assume we are
# receiving a DMChannel or GroupChannel which inherit from PrivateChannel and do
return (msg.channel if isinstance(msg.channel, PrivateChannel) else msg.author.top_role).id # type: ignore
return (
msg.channel
if isinstance(msg.channel, PrivateChannel)
else msg.author.top_role
).id # type: ignore

def __call__(self, msg: Message) -> Any:
return self.get_key(msg)
Expand Down Expand Up @@ -311,7 +315,7 @@ class _Semaphore:
def __init__(self, number: int) -> None:
self.value: int = number
self.loop: asyncio.AbstractEventLoop = _get_event_loop()
self._waiters: Deque[asyncio.Future] = deque()
self._waiters: deque[asyncio.Future] = deque()

def __repr__(self) -> str:
return f"<_Semaphore value={self.value} waiters={len(self._waiters)}>"
Expand Down
12 changes: 7 additions & 5 deletions discord/ext/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@
from .errors import *

if TYPE_CHECKING:
from typing import Concatenate, TypeGuard

from typing_extensions import ParamSpec
from typing import Concatenate, ParamSpec, TypeGuard

from discord.message import Message

Expand Down Expand Up @@ -396,7 +394,9 @@ def __init__(

# bandaid for the fact that sometimes parent can be the bot instance
parent = kwargs.get("parent")
self.parent: GroupMixin | None = parent if isinstance(parent, _BaseCommand) else None # type: ignore
self.parent: GroupMixin | None = (
parent if isinstance(parent, _BaseCommand) else None
) # type: ignore

self._before_invoke: Hook | None = None
try:
Expand Down Expand Up @@ -1203,7 +1203,9 @@ async def can_run(self, ctx: Context) -> bool:
# since we have no checks, then we just return True.
return True

return await discord.utils.async_all(predicate(ctx) for predicate in predicates) # type: ignore
return await discord.utils.async_all(
predicate(ctx) for predicate in predicates
) # type: ignore
finally:
ctx.command = original

Expand Down
16 changes: 8 additions & 8 deletions discord/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@
import itertools
import logging
import os
from collections import OrderedDict, deque
from collections import deque
from collections.abc import Callable, Coroutine, Sequence
from typing import (
TYPE_CHECKING,
Any,
Deque,
TypeVar,
Union,
)
Expand Down Expand Up @@ -290,13 +289,13 @@ def clear(self, *, views: bool = True) -> None:
self._sounds: dict[int, SoundboardSound] = {}

# LRU of max size 128
self._private_channels: OrderedDict[int, PrivateChannel] = OrderedDict()
self._private_channels: dict[int, PrivateChannel] = {}
# extra dict to look up private channels by user id
self._private_channels_by_user: dict[int, DMChannel] = {}
if self.max_messages is not None:
self._messages: Deque[Message] | None = deque(maxlen=self.max_messages)
self._messages: deque[Message] | None = deque(maxlen=self.max_messages)
else:
self._messages: Deque[Message] | None = None
self._messages: deque[Message] | None = None

def process_chunk_requests(
self, guild_id: int, nonce: str | None, members: list[Member], complete: bool
Expand Down Expand Up @@ -497,7 +496,7 @@ def _get_private_channel(self, channel_id: int | None) -> PrivateChannel | None:
except KeyError:
return None
else:
self._private_channels.move_to_end(channel_id) # type: ignore
self._private_channels[channel_id] = self._private_channels.pop(channel_id) # type: ignore
return value

def _get_private_channel_by_user(self, user_id: int | None) -> DMChannel | None:
Expand All @@ -509,7 +508,8 @@ def _add_private_channel(self, channel: PrivateChannel) -> None:
self._private_channels[channel_id] = channel

if len(self._private_channels) > 128:
_, to_remove = self._private_channels.popitem(last=False)
oldest_key = next(iter(self._private_channels))
to_remove = self._private_channels.pop(oldest_key)
if isinstance(to_remove, DMChannel) and to_remove.recipient:
self._private_channels_by_user.pop(to_remove.recipient.id, None)

Expand Down Expand Up @@ -1514,7 +1514,7 @@ def parse_guild_delete(self, data) -> None:

# do a cleanup of the messages cache
if self._messages is not None:
self._messages: Deque[Message] | None = deque(
self._messages: deque[Message] | None = deque(
(msg for msg in self._messages if msg.guild != guild),
maxlen=self.max_messages,
)
Expand Down
Loading