diff --git a/discord/__init__.py b/discord/__init__.py index 6c7616737..3e4a45085 100644 --- a/discord/__init__.py +++ b/discord/__init__.py @@ -17,54 +17,57 @@ __version__ = '2.0.0a2' __path__ = __import__('pkgutil').extend_path(__path__, __name__) import logging -from typing import NamedTuple, Literal +from typing import Literal, NamedTuple -from .client import * -from .appinfo import * -from .user import * -from .emoji import * -from .partial_emoji import * +from . import abc, opus, utils # type: ignore from .activity import * -from .channel import * -from .guild import * -from .flags import * -from .member import * -from .message import * +from .appinfo import * from .asset import * +from .audit_logs import * +from .channel import * +from .client import * +from .colour import * +from .commands import * +from .components import * +from .connections import * +from .embeds import * +from .emoji import * +from .enums import * from .errors import * -from .permissions import * -from .role import * from .file import * -from .colour import * +from .flags import * +from .guild import * +from .guild_folder import * +from .handlers import * from .integrations import * +from .interactions import * from .invite import * -from .template import * -from .widget import * -from .object import * -from .reaction import * -from . import utils, opus, abc -from .enums import * -from .embeds import * +from .member import * from .mentions import * +from .message import * +from .modal import * +from .object import * +from .partial_emoji import * +from .permissions import * from .player import * -from .webhook import * -from .voice_client import * -from .audit_logs import * +from .profile import * from .raw_models import * -from .team import * -from .sticker import * -from .stage_instance import * -from .scheduled_event import * -from .interactions import * -from .components import * -from .threads import * +from .reaction import * from .relationship import * -from .guild_folder import * +from .role import * +from .scheduled_event import * from .settings import * -from .profile import * +from .stage_instance import * +from .sticker import * +from .team import * +from .template import * +from .threads import * +from .tracking import * +from .user import * +from .voice_client import * +from .webhook import * from .welcome_screen import * -from .modal import * -from .handlers import * +from .widget import * class _VersionInfo(NamedTuple): diff --git a/discord/abc.py b/discord/abc.py index 55eb47c4e..d26371a69 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -58,6 +58,7 @@ from .http import handle_message_parameters from .voice_client import VoiceClient, VoiceProtocol from .sticker import GuildSticker, StickerItem from .settings import ChannelSettings +from .commands import ApplicationCommand from . import utils __all__ = ( @@ -67,6 +68,7 @@ __all__ = ( 'GuildChannel', 'Messageable', 'Connectable', + 'ApplicationCommand', ) T = TypeVar('T', bound=VoiceProtocol) diff --git a/discord/appinfo.py b/discord/appinfo.py index 415be02d2..2c733145d 100644 --- a/discord/appinfo.py +++ b/discord/appinfo.py @@ -46,6 +46,7 @@ if TYPE_CHECKING: __all__ = ( 'Application', + 'ApplicationBot', 'PartialApplication', 'InteractionApplication', ) @@ -340,8 +341,8 @@ class Application(PartialApplication): self.interactions_endpoint_url: Optional[str] = data.get('interactions_endpoint_url') self.verification_state = try_enum(ApplicationVerificationState, data['verification_state']) - self.store_application_state = try_enum(StoreApplicationState, data['store_application_state']) - self.rpc_application_state = try_enum(RPCApplicationState, data['rpc_application_state']) + self.store_application_state = try_enum(StoreApplicationState, data.get('store_application_state', 1)) + self.rpc_application_state = try_enum(RPCApplicationState, data.get('rpc_application_state', 0)) state = self._state team: Optional[TeamPayload] = data.get('team') diff --git a/discord/calls.py b/discord/calls.py index 696bb3f4b..d4f662062 100644 --- a/discord/calls.py +++ b/discord/calls.py @@ -223,7 +223,10 @@ class PrivateCall: The message associated with this call. """ message = await self.channel.fetch_message(self._message_id) + state = self._state if message is not None and self.message is None: + if self._state._messages is not None: + self._state._messages.append(message) self.message = message return message diff --git a/discord/client.py b/discord/client.py index 8cdfd77f4..d35fe3132 100644 --- a/discord/client.py +++ b/discord/client.py @@ -2319,6 +2319,7 @@ class Client: # Passing a username and discriminator: await client.send_friend_request('Jake', '0001') + Parameters ----------- user: Union[:class:`User`, :class:`str`] @@ -2328,14 +2329,14 @@ class Client: discriminator: :class:`str` The discriminator of the user to send the friend request to. - More than 2 parameters or less than 1 parameter raises a :exc:`TypeError`. - Raises ------- Forbidden Not allowed to send a friend request to this user. HTTPException Sending the friend request failed. + TypeError + More than 2 parameters or less than 1 parameter was passed. Returns ------- diff --git a/discord/commands.py b/discord/commands.py index e79cae122..590c9171c 100644 --- a/discord/commands.py +++ b/discord/commands.py @@ -39,7 +39,6 @@ if TYPE_CHECKING: from .state import ConnectionState __all__ = ( - 'ApplicationCommand', 'BaseCommand', 'UserCommand', 'MessageCommand', @@ -68,12 +67,8 @@ class ApplicationCommand(Protocol): The command's name. description: :class:`str` The command's description, if any. - version: :class:`int` - The command's version. type: :class:`AppCommandType` The type of application command. - default_permission: :class:`bool` - Whether the command is enabled in guilds by default. """ __slots__ = () @@ -142,14 +137,8 @@ class BaseCommand(ApplicationCommand, Hashable): ---------- id: :class:`int` The command's ID. - name: :class:`str` - The command's name. - description: :class:`str` - The command's description, if any. version: :class:`int` The command's version. - type: :class:`AppCommandType` - The type of application command. default_permission: :class:`bool` Whether the command is enabled in guilds by default. """ @@ -351,21 +340,7 @@ class UserCommand(BaseCommand): class MessageCommand(BaseCommand): - """Represents a message command. - - Attributes - ---------- - id: :class:`int` - The command's ID. - name: :class:`str` - The command's name. - description: :class:`str` - The command's description, if any. - type: :class:`AppCommandType` - The type of application command. Always :class:`AppCommandType.message`. - default_permission: :class:`bool` - Whether the command is enabled in guilds by default. - """ + """Represents a message command.""" __slots__ = ('_message',) @@ -425,16 +400,6 @@ class SlashCommand(BaseCommand, SlashMixin): Attributes ---------- - id: :class:`int` - The command's ID. - name: :class:`str` - The command's name. - description: :class:`str` - The command's description, if any. - type: :class:`AppCommandType` - The type of application command. Always :class:`AppCommandType.chat_input`. - default_permission: :class:`bool` - Whether the command is enabled in guilds by default. options: List[:class:`Option`] The command's options. children: List[:class:`SubCommand`] @@ -505,12 +470,11 @@ class SubCommand(SlashMixin): ---------- parent: :class:`SlashCommand` The parent command. - name: :class:`str` - The command's name. - description: :class:`str` - The command's description, if any. - type: :class:`AppCommandType` - The type of application command. Always :class:`AppCommandType.chat_input`. + options: List[:class:`Option`] + The subcommand's options. + children: List[:class:`SubCommand`] + The subcommand's subcommands. If a subcommand has subcommands, it is a group and cannot be used. + You can access (and use) subcommands directly as attributes of the class. """ __slots__ = ( diff --git a/discord/enums.py b/discord/enums.py index e978b1756..8ed358b74 100644 --- a/discord/enums.py +++ b/discord/enums.py @@ -286,15 +286,15 @@ class ContentFilter(Enum, comparable=True): class UserContentFilter(Enum): - always = 0 - on_interaction = 1 - never = 2 + disabled = 0 + non_friends = 1 + all_messages = 2 class StickerAnimationOptions(Enum): - disabled = 2 - friends = 1 - all_messages = 0 + always = 0 + on_interaction = 1 + never = 2 class FriendFlags(Enum): @@ -364,7 +364,7 @@ class DefaultAvatar(Enum): return self.name -class RelationshipType(Enum, comparable=True): +class RelationshipType(Enum): friend = 1 blocked = 2 incoming_request = 3 @@ -581,7 +581,7 @@ class PremiumType(Enum, comparable=True): nitro = 2 -class TeamMembershipState(Enum): +class TeamMembershipState(Enum, comparable=True): invited = 1 accepted = 2 diff --git a/discord/ext/commands/_types.py b/discord/ext/commands/_types.py index c0c782fee..dbec8f1af 100644 --- a/discord/ext/commands/_types.py +++ b/discord/ext/commands/_types.py @@ -36,13 +36,15 @@ if TYPE_CHECKING: from .cog import Cog from .errors import CommandError + _Bot = Bot P = ParamSpec('P') MaybeAwaitableFunc = Callable[P, 'MaybeAwaitable[T]'] else: + _Bot = 'Bot' + P = TypeVar('P') MaybeAwaitableFunc = Tuple[P, T] -_Bot = Bot Coro = Coroutine[Any, Any, T] CoroFunc = Callable[..., Coro[Any]] MaybeCoro = Union[T, Coro[T]] @@ -53,7 +55,7 @@ Hook = Union[Callable[["Cog", "ContextT"], Coro[Any]], Callable[["ContextT"], Co Error = Union[Callable[["Cog", "ContextT", "CommandError"], Coro[Any]], Callable[["ContextT", "CommandError"], Coro[Any]]] ContextT = TypeVar('ContextT', bound='Context[Any]') -BotT = TypeVar('BotT', bound=_Bot, covariant=True) +BotT = TypeVar('BotT', bound='Bot', covariant=True) ErrorT = TypeVar('ErrorT', bound='Error[Context[Any]]') HookT = TypeVar('HookT', bound='Hook[Context[Any]]') diff --git a/discord/flags.py b/discord/flags.py index 140a63123..8472f5042 100644 --- a/discord/flags.py +++ b/discord/flags.py @@ -36,6 +36,7 @@ __all__ = ( 'SystemChannelFlags', 'MessageFlags', 'PublicUserFlags', + 'PrivateUserFlags', 'MemberCacheFlags', 'ApplicationFlags', 'ChannelFlags', diff --git a/discord/guild.py b/discord/guild.py index cf7abd727..b5be17ff9 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -615,6 +615,7 @@ class Guild(Hashable): @utils.cached_slot_property('_cs_joined') def joined(self) -> bool: """:class:`bool`: Returns whether you are a member of this guild. + May not be accurate for :class:`Guild`s fetched over HTTP. """ if self.me or self.joined_at: diff --git a/discord/settings.py b/discord/settings.py index 831b81fe8..da8178bd6 100644 --- a/discord/settings.py +++ b/discord/settings.py @@ -52,6 +52,7 @@ __all__ = ( 'ChannelSettings', 'GuildSettings', 'UserSettings', + 'MuteConfig', ) @@ -232,6 +233,8 @@ class UserSettings: native_phone_integration_enabled: :class:`bool` Whether or not to enable the new Discord mobile phone number friend requesting features. + passwordless: :class:`bool` + Unknown. render_embeds: :class:`bool` Whether or not to render embeds that are sent in the chat. render_reactions: :class:`bool` @@ -291,13 +294,13 @@ class UserSettings: @property def custom_activity(self) -> Optional[CustomActivity]: - """Optional[:class:`CustomActivity]: The set custom activity.""" + """Optional[:class:`CustomActivity`]: The set custom activity.""" return create_settings_activity(data=getattr(self, '_custom_status', None), state=self._state) @property def explicit_content_filter(self) -> UserContentFilter: """:class:`UserContentFilter`: The filter for explicit content in all messages.""" - return try_enum(UserContentFilter, getattr(self, '_explicit_content_filter', 1)) + return try_enum(UserContentFilter, getattr(self, '_explicit_content_filter', 0)) @property def friend_source_flags(self) -> FriendFlags: @@ -323,7 +326,7 @@ class UserSettings: @property def passwordless(self) -> bool: - """:class:`bool`: Whether the account is passwordless.""" + """:class:`bool`: Unknown.""" return getattr(self, '_passwordless', False) @property diff --git a/discord/state.py b/discord/state.py index bf9a510ee..17804a6b8 100644 --- a/discord/state.py +++ b/discord/state.py @@ -1192,21 +1192,28 @@ class ConnectionState: _log.debug('CHANNEL_UPDATE referencing an unknown guild ID: %s. Discarding.', guild_id) def parse_channel_create(self, data: gw.ChannelCreateEvent) -> None: - factory, _ = _channel_factory(data['type']) + factory, ch_type = _channel_factory(data['type']) if factory is None: _log.debug('CHANNEL_CREATE referencing an unknown channel type %s. Discarding.', data['type']) return - guild_id = utils._get_as_snowflake(data, 'guild_id') - guild = self._get_guild(guild_id) - if guild is not None: - # The factory can't be a DMChannel or GroupChannel here - channel = factory(guild=guild, state=self, data=data) # type: ignore - guild._add_channel(channel) # type: ignore - self.dispatch('guild_channel_create', channel) + if ch_type in (ChannelType.group, ChannelType.private): + channel_id = int(data['id']) + if self._get_private_channel(channel_id) is None: + channel = factory(me=self.user, data=data, state=self) # type: ignore # user is always present when logged in + self._add_private_channel(channel) # type: ignore # channel will always be a private channel + self.dispatch('private_channel_create', channel) else: - _log.debug('CHANNEL_CREATE referencing an unknown guild ID: %s. Discarding.', guild_id) - return + guild_id = utils._get_as_snowflake(data, 'guild_id') + guild = self._get_guild(guild_id) + if guild is not None: + # The factory can't be a DMChannel or GroupChannel here + channel = factory(guild=guild, state=self, data=data) # type: ignore + guild._add_channel(channel) # type: ignore + self.dispatch('guild_channel_create', channel) + else: + _log.debug('CHANNEL_CREATE referencing an unknown guild ID: %s. Discarding.', guild_id) + return def parse_channel_pins_update(self, data: gw.ChannelPinsUpdateEvent) -> None: channel_id = int(data['channel_id']) @@ -2100,8 +2107,9 @@ class ConnectionState: if call is None: _log.debug('CALL_UPDATE referencing unknown call (channel ID: %s). Discarding.', data['channel_id']) return + old_call = copy.copy(call) call._update(**data) - self.dispatch('call_update', call) + self.dispatch('call_update', old_call, call) def parse_call_delete(self, data) -> None: call = self._calls.pop(int(data['channel_id']), None) diff --git a/discord/team.py b/discord/team.py index 521438d42..0ce11b0aa 100644 --- a/discord/team.py +++ b/discord/team.py @@ -230,14 +230,14 @@ class Team(Hashable): discriminator: :class:`str` The discriminator of the user to invite. - More than 2 parameters or less than 1 parameter raises a :exc:`TypeError`. - Raises ------- Forbidden You do not have permissions to invite the user. - :exc:`.HTTPException` + HTTPException Inviting the user failed. + TypeError + More than 2 parameters or less than 1 parameter were passed. Returns ------- diff --git a/discord/user.py b/discord/user.py index f2083d3ed..63da96f96 100644 --- a/discord/user.py +++ b/discord/user.py @@ -502,8 +502,6 @@ class ClientUser(BaseUser): The user's discriminator. bio: Optional[:class:`str`] The user's "about me" field. Could be ``None``. - avatar: Optional[:class:`str`] - The avatar hash the user has. Could be ``None``. bot: :class:`bool` Specifies if the user is a bot account. system: :class:`bool`