Browse Source

Add separate data class for Client.fetch_guilds(), add application_command_counts_update event, fix various guild issues

pull/10109/head
dolfies 2 years ago
parent
commit
07203e576f
  1. 26
      discord/client.py
  2. 2
      discord/emoji.py
  3. 211
      discord/guild.py
  4. 4
      discord/http.py
  5. 2
      discord/invite.py
  6. 2
      discord/role.py
  7. 49
      discord/state.py
  8. 7
      discord/types/gateway.py
  9. 23
      discord/types/guild.py
  10. 40
      docs/api.rst

26
discord/client.py

@ -51,7 +51,7 @@ from .user import _UserTag, User, ClientUser, Note
from .invite import Invite
from .template import Template
from .widget import Widget
from .guild import Guild
from .guild import Guild, UserGuild
from .emoji import Emoji
from .channel import _private_channel_factory, _threaded_channel_factory, GroupChannel, PartialMessageable
from .enums import ActivityType, ChannelType, ClientType, ConnectionType, EntitlementType, Status
@ -1597,19 +1597,18 @@ class Client:
# Guild stuff
async def fetch_guilds(self, *, with_counts: bool = True) -> List[Guild]:
async def fetch_guilds(self, *, with_counts: bool = True) -> List[UserGuild]:
"""|coro|
Retrieves all your your guilds.
Retrieves all your guilds.
.. note::
Using this, you will only receive :attr:`.Guild.owner`, :attr:`.Guild.icon`,
:attr:`.Guild.id`, and :attr:`.Guild.name` per :class:`.Guild`.
This method is an API call. For general usage, consider :attr:`guilds` instead.
.. note::
.. versionchanged:: 2.0
This method is an API call. For general usage, consider :attr:`guilds` instead.
This method now returns a list of :class:`.UserGuild` instead of :class:`.Guild`.
Parameters
-----------
@ -1623,15 +1622,12 @@ class Client:
Returns
--------
List[:class:`.Guild`]
List[:class:`.UserGuild`]
A list of all your guilds.
"""
state = self._connection
guilds = await state.http.get_guilds(with_counts)
guilds = [Guild(data=data, state=state) for data in guilds]
for guild in guilds:
guild._cs_joined = True
return guilds
return [UserGuild(data=data, state=state) for data in guilds]
async def fetch_template(self, code: Union[Template, str]) -> Template:
"""|coro|
@ -1664,10 +1660,6 @@ class Client:
Retrieves a :class:`.Guild` from an ID.
.. versionchanged:: 2.0
``guild_id`` parameter is now positional-only.
.. note::
Using this, you will **not** receive :attr:`.Guild.channels` and :attr:`.Guild.members`.
@ -1685,7 +1677,7 @@ class Client:
guild_id: :class:`int`
The guild's ID to fetch from.
with_counts: :class:`bool`
Whether to include count information in the guild. This fills the
Whether to include count information in the guild. This fills in
:attr:`.Guild.approximate_member_count` and :attr:`.Guild.approximate_presence_count`.
.. versionadded:: 2.0

2
discord/emoji.py

@ -188,7 +188,7 @@ class Emoji(_EmojiTag, AssetMixin):
return False
if not self._roles:
return True
emoji_roles, my_roles = self._roles, self.guild.me._roles
emoji_roles, my_roles = self._roles, self.guild.me._roles # type: ignore # Should just error ATP
return any(my_roles.has(role_id) for role_id in emoji_roles)
async def delete(self, *, reason: Optional[str] = None) -> None:

211
discord/guild.py

@ -104,6 +104,7 @@ if TYPE_CHECKING:
Guild as GuildPayload,
PartialGuild as PartialGuildPayload,
RolePositionUpdate as RolePositionUpdatePayload,
UserGuild as UserGuildPayload,
)
from .types.threads import (
Thread as ThreadPayload,
@ -139,11 +140,13 @@ MISSING = utils.MISSING
__all__ = (
'Guild',
'UserGuild',
'BanEntry',
'ApplicationCommandCounts',
)
class CommandCounts(NamedTuple):
class ApplicationCommandCounts(NamedTuple):
chat_input: int
user: int
message: int
@ -161,6 +164,103 @@ class _GuildLimit(NamedTuple):
filesize: int
class UserGuild(Hashable):
"""Represents a partial joined guild.
.. container:: operations
.. describe:: x == y
Checks if two guilds are equal.
.. describe:: x != y
Checks if two guilds are not equal.
.. describe:: hash(x)
Returns the guild's hash.
.. describe:: str(x)
Returns the guild's name.
.. versionadded:: 2.0
Attributes
----------
id: :class:`int`
The guild's ID.
name: :class:`str`
The guild name.
features: List[:class:`str`]
A list of features that the guild has. The features that a guild can have are
subject to arbitrary change by Discord.
owner: :class:`bool`
Whether the current user is the owner of the guild.
approximate_member_count: Optional[:class:`int`]
The approximate number of members in the guild. This is ``None`` unless the guild is obtained
using :meth:`Client.fetch_guilds` with ``with_counts=True``.
approximate_presence_count: Optional[:class:`int`]
The approximate number of members currently active in the guild.
Offline members are excluded. This is ``None`` unless the guild is obtained using
:meth:`Client.fetch_guilds` with ``with_counts=True``.
"""
__slots__ = (
'id',
'name',
'_icon',
'owner',
'_permissions',
'features',
'approximate_member_count',
'approximate_presence_count',
'_state',
)
def __init__(self, *, state: ConnectionState, data: UserGuildPayload):
self._state: ConnectionState = state
self.id: int = int(data['id'])
self.name: str = data['name']
self._icon: Optional[str] = data.get('icon')
self.owner: bool = data.get('owner', False)
self._permissions: int = int(data.get('permissions', 0))
self.features: List[str] = data.get('features', [])
self.approximate_member_count: Optional[int] = data.get('approximate_member_count')
self.approximate_presence_count: Optional[int] = data.get('approximate_presence_count')
def __str__(self) -> str:
return self.name or ''
def __repr__(self) -> str:
return f'<UserGuild id={self.id} name={self.name!r}>'
@property
def icon(self) -> Optional[Asset]:
"""Optional[:class:`Asset`]: Returns the guild's icon asset, if available."""
if self._icon is None:
return None
return Asset._from_guild_icon(self._state, self.id, self._icon)
@property
def permissions(self) -> Permissions:
""":class:`Permissions`: Returns the calculated permissions the current user has in the guild."""
return Permissions(self._permissions)
def is_joined(self) -> bool:
"""Returns whether you are a member of this guild.
Always returns ``True``.
Returns
-------
:class:`bool`
Whether you are a member of this guild.
"""
return True
class Guild(Hashable):
"""Represents a Discord guild.
@ -231,9 +331,6 @@ class Guild(Hashable):
features: List[:class:`str`]
A list of features that the guild has. The features that a guild can have are
subject to arbitrary change by Discord.
premium_tier: :class:`int`
The premium tier for this guild. Corresponds to "Server Boost Level" in the official UI.
The number goes from 0 to 3 inclusive.
premium_subscription_count: :class:`int`
The number of "boosts" this guild currently has.
preferred_locale: :class:`Locale`
@ -251,7 +348,10 @@ class Guild(Hashable):
.. versionchanged:: 2.0
This field is now an enum instead of an :class:`int`.
application_command_counts: Optional[:class:`ApplicationCommandCounts`]
A namedtuple representing the number of application commands in the guild, separated by type.
.. versionadded:: 2.0
approximate_member_count: Optional[:class:`int`]
The approximate number of members in the guild. This is ``None`` unless the guild is obtained
using :meth:`Client.fetch_guild` with ``with_counts=True``.
@ -264,15 +364,9 @@ class Guild(Hashable):
.. versionadded:: 2.0
premium_progress_bar_enabled: :class:`bool`
Indicates if the guild has premium AKA server boost level progress bar enabled.
Indicates if the guild has the premium (server boost) progress bar enabled.
.. versionadded:: 2.0
keywords: Optional[:class:`str`]
Discovery search keywords for the guild.
.. versionadded:: 2.0
primary_category_id: Optional[:class:`int`]
The ID of the primary discovery category for the guild.
widget_enabled: :class:`bool`
Indicates if the guild has widget enabled.
@ -295,14 +389,13 @@ class Guild(Hashable):
'max_presences',
'max_members',
'max_video_channel_users',
'premium_tier',
'_premium_tier',
'premium_subscription_count',
'preferred_locale',
'nsfw_level',
'mfa_level',
'vanity_url_code',
'owner_application_id',
'command_counts',
'widget_enabled',
'_widget_channel_id',
'_members',
@ -333,8 +426,7 @@ class Guild(Hashable):
'_member_list',
'keywords',
'primary_category_id',
'application_command_count',
'_load_id',
'application_command_counts',
'_joined_at',
'_cs_joined',
)
@ -359,9 +451,10 @@ class Guild(Hashable):
self._stage_instances: Dict[int, StageInstance] = {}
self._scheduled_events: Dict[int, ScheduledEvent] = {}
self._state: ConnectionState = state
self.command_counts: Optional[CommandCounts] = None
self._member_count: int = 0
self.application_command_counts: Optional[ApplicationCommandCounts] = None
self._member_count: Optional[int] = None
self._presence_count: Optional[int] = None
self._large: Optional[bool] = None
self._from_data(data)
def _add_channel(self, channel: GuildChannel, /) -> None:
@ -468,7 +561,7 @@ class Guild(Hashable):
def _from_data(self, guild: Union[GuildPayload, PartialGuildPayload]) -> None:
try:
self._member_count: int = guild['member_count'] # type: ignore # Handled below
self._member_count: Optional[int] = guild['member_count'] # type: ignore # Handled below
except KeyError:
pass
@ -481,6 +574,8 @@ class Guild(Hashable):
self.explicit_content_filter: ContentFilter = try_enum(ContentFilter, guild.get('explicit_content_filter', 0))
self.afk_timeout: int = guild.get('afk_timeout', 0)
self.unavailable: bool = guild.get('unavailable', False)
if self.unavailable:
self._member_count = 0
state = self._state # Speed up attribute access
@ -509,7 +604,6 @@ class Guild(Hashable):
map(lambda d: state.store_sticker(self, d), guild.get('stickers', []))
)
self.features: List[str] = guild.get('features', [])
self.keywords: List[str] = guild.get('keywords', [])
self._icon: Optional[str] = guild.get('icon')
self._banner: Optional[str] = guild.get('banner')
self._splash: Optional[str] = guild.get('splash')
@ -518,7 +612,7 @@ class Guild(Hashable):
self.max_presences: Optional[int] = guild.get('max_presences')
self.max_members: Optional[int] = guild.get('max_members')
self.max_video_channel_users: Optional[int] = guild.get('max_video_channel_users')
self.premium_tier: int = guild.get('premium_tier', 0)
self._premium_tier = guild.get('premium_tier')
self.premium_subscription_count: int = guild.get('premium_subscription_count') or 0
self.vanity_url_code: Optional[str] = guild.get('vanity_url_code')
self.widget_enabled: bool = guild.get('widget_enabled', False)
@ -536,15 +630,16 @@ class Guild(Hashable):
self.owner_id: Optional[int] = utils._get_as_snowflake(guild, 'owner_id')
self.owner_application_id: Optional[int] = utils._get_as_snowflake(guild, 'application_id')
self.premium_progress_bar_enabled: bool = guild.get('premium_progress_bar_enabled', False)
self.application_command_count: int = guild.get('application_command_count', 0)
self.primary_category_id: Optional[int] = guild.get('primary_category_id')
self._joined_at = guild.get('joined_at')
large = None if self._member_count == 0 else self._member_count >= 250
self._large: Optional[bool] = guild.get('large', large)
try:
self._large = guild['large'] # type: ignore
except KeyError:
pass
if (counts := guild.get('application_command_counts')) is not None:
self.command_counts = CommandCounts(counts.get(0, 0), counts.get(1, 0), counts.get(2, 0))
counts = guild.get('application_command_counts')
if counts:
self.application_command_counts = ApplicationCommandCounts(counts.get(1, 0), counts.get(2, 0), counts.get(3, 0))
for vs in guild.get('voice_states', []):
self._update_voice_state(vs, int(vs['channel_id']))
@ -588,7 +683,7 @@ class Guild(Hashable):
@property
def _offline_members_hidden(self) -> bool:
return self._member_count > 1000
return (self._member_count or 0) > 1000
@property
def voice_channels(self) -> List[VoiceChannel]:
@ -613,12 +708,17 @@ class Guild(Hashable):
return r
@property
def me(self) -> Member:
""":class:`Member`: Similar to :attr:`Client.user` except an instance of :class:`Member`.
def me(self) -> Optional[Member]:
"""Optional[:class:`Member`]: Similar to :attr:`Client.user` except an instance of :class:`Member`.
This is essentially used to get the member version of yourself.
.. versionchanged:: 2.0
The type has been updated to be optional, which properly reflects cases where the current user
is not a member of the guild, or the current user's member object is not cached.
"""
self_id = self._state.self_id
return self.get_member(self_id) # type: ignore # The self member is *always* cached
return self.get_member(self_id) # type: ignore
def is_joined(self) -> bool:
"""Returns whether you are a member of this guild.
@ -927,6 +1027,28 @@ class Guild(Hashable):
"""
return self._members.get(user_id)
@property
def premium_tier(self) -> int:
""":class:`int`: The premium tier for this guild. Corresponds to "Server Boost Level" in the official UI.
The number goes from 0 to 3 inclusive.
"""
tier = self._premium_tier
if tier is not None:
return tier
if 'PREMIUM_TIER_3_OVERRIDE' in self.features:
return 3
# Fallback to calculating by the number of boosts
count = self.premium_subscription_count
if count < 2:
return 0
elif count < 7:
return 1
elif count < 14:
return 2
else:
return 3
@property
def premium_subscribers(self) -> List[Member]:
"""List[:class:`Member`]: A list of members who have subscribed to (boosted) this guild."""
@ -1068,32 +1190,30 @@ class Guild(Hashable):
.. warning::
Due to a Discord limitation, this may not always be up-to-date and accurate.
.. versionchanged:: 2.0
Now returns an ``Optional[int]``.
"""
return self._member_count
return self._member_count if self._member_count is not None else self.approximate_member_count
@property
def online_count(self) -> Optional[int]:
"""Optional[:class:`int`]: Returns the online member count.
This is not always populated.
.. versionadded:: 1.9
This is an alias of :attr:`presence_count`.
.. warning::
Due to a Discord limitation, this may not always be up-to-date and accurate.
"""
return self._presence_count
@property
def presence_count(self) -> Optional[int]:
"""Optional[:class:`int`]: Returns the online member count.
This is not always populated.
def application_command_count(self) -> Optional[int]:
"""Optional[:class:`int`]: Returns the application command count if available.
There is an alias of this called :attr:`online_count`.
.. versionadded:: 2.0
"""
return self._presence_count
counts = self.application_command_counts
if counts:
sum(counts)
@property
def chunked(self) -> bool:
@ -4132,8 +4252,9 @@ class Guild(Hashable):
if not subscription_slots:
return []
data = await self._state.http.apply_guild_subscription_slots(self.id, [slot.id for slot in subscription_slots])
return [PremiumGuildSubscription(state=self._state, data=sub) for sub in data]
state = self._state
data = await state.http.apply_guild_subscription_slots(self.id, [slot.id for slot in subscription_slots])
return [PremiumGuildSubscription(state=state, data=sub) for sub in data]
async def entitlements(
self, *, with_sku: bool = True, with_application: bool = True, exclude_deleted: bool = False

4
discord/http.py

@ -1646,9 +1646,8 @@ class HTTPClient:
# Guild management
def get_guilds(self, with_counts: bool = True) -> Response[List[guild.Guild]]:
def get_guilds(self, with_counts: bool = True) -> Response[List[guild.UserGuild]]:
params = {'with_counts': str(with_counts).lower()}
return self.request(Route('GET', '/users/@me/guilds'), params=params, super_properties_to_track=True)
def join_guild(
@ -1686,7 +1685,6 @@ class HTTPClient:
def get_guild(self, guild_id: Snowflake, with_counts: bool = True) -> Response[guild.Guild]:
params = {'with_counts': str(with_counts).lower()}
return self.request(Route('GET', '/guilds/{guild_id}', guild_id=guild_id), params=params)
def get_guild_preview(self, guild_id: Snowflake) -> Response[guild.GuildPreview]:

2
discord/invite.py

@ -526,7 +526,7 @@ class Invite(Hashable):
channel_data = data.get('channel')
if channel_data and channel_data.get('type') == ChannelType.private.value:
channel_data['recipients'] = [data['inviter']] if 'inviter' in data else [] # type: ignore
channel_data['recipients'] = [data['inviter']] if 'inviter' in data else []
channel = PartialInviteChannel(channel_data, state)
channel = state.get_channel(getattr(channel, 'id', None)) or channel

2
discord/role.py

@ -319,7 +319,7 @@ class Role(Hashable):
.. versionadded:: 2.0
"""
me = self.guild.me
return not self.is_default() and not self.managed and (me.top_role > self or me.id == self.guild.owner_id)
return not self.is_default() and not self.managed and (me.top_role > self or me.id == self.guild.owner_id) # type: ignore # Should just error ATP
@property
def permissions(self) -> Permissions:

49
discord/state.py

@ -52,7 +52,7 @@ from math import ceil
from discord_protos import UserSettingsType
from .errors import ClientException, InvalidData, NotFound
from .guild import CommandCounts, Guild
from .guild import ApplicationCommandCounts, Guild
from .activity import BaseActivity, create_activity, Session
from .user import User, ClientUser
from .emoji import Emoji
@ -216,7 +216,7 @@ class MemberSidebar:
@property
def safe(self):
return self.safe_override or self.guild._member_count >= 75000
return self.safe_override or (self.guild._member_count or 0) >= 75000
@staticmethod
def amalgamate(original: Tuple[int, int], value: Tuple[int, int]) -> Tuple[int, int]:
@ -269,7 +269,7 @@ class MemberSidebar:
channels = [
channel
for channel in self.guild.channels
if channel.type != ChannelType.stage_voice and channel.permissions_for(guild.me).read_messages
if channel.type != ChannelType.stage_voice and channel.permissions_for(guild.me).read_messages # type: ignore
]
if guild.rules_channel is not None:
channels.insert(0, guild.rules_channel)
@ -755,12 +755,16 @@ class ConnectionState:
def store_emoji(self, guild: Guild, data: EmojiPayload) -> Emoji:
# The id will be present here
emoji_id = int(data['id']) # type: ignore
self._emojis[emoji_id] = emoji = Emoji(guild=guild, state=self, data=data)
emoji = Emoji(guild=guild, state=self, data=data)
if not self.is_guild_evicted(guild):
self._emojis[emoji_id] = emoji
return emoji
def store_sticker(self, guild: Guild, data: GuildStickerPayload) -> GuildSticker:
sticker_id = int(data['id'])
self._stickers[sticker_id] = sticker = GuildSticker(state=self, data=data)
sticker = GuildSticker(state=self, data=data)
if not self.is_guild_evicted(guild):
self._stickers[sticker_id] = sticker
return sticker
@property
@ -936,7 +940,7 @@ class ConnectionState:
try:
await asyncio.wait_for(future, timeout=10)
except asyncio.TimeoutError:
_log.warning('Timed out waiting for chunks for guild_id %s.', guild.id)
_log.warning('Timed out waiting for member list subscriptions for guild_id %s.', guild.id)
except (ClientException, InvalidData):
pass
except asyncio.CancelledError:
@ -1685,7 +1689,7 @@ class ConnectionState:
continue
# channel will be the correct type here
message = Message(channel=channel, data=message, state=self) # type: ignore
message = Message(channel=channel, data=message, state=self)
if self._messages is not None:
self._messages.append(message)
@ -1974,17 +1978,20 @@ class ConnectionState:
for member in actually_add:
self.dispatch('member_join', member)
def parse_guild_application_command_counts_update(self, data) -> None:
def parse_guild_application_command_index_update(self, data: gw.GuildApplicationCommandIndexUpdateEvent) -> None:
guild = self._get_guild(int(data['guild_id']))
if guild is None:
_log.debug(
'GUILD_APPLICATION_COMMAND_COUNTS_UPDATE referencing an unknown guild ID: %s. Discarding.', data['guild_id']
'GUILD_APPLICATION_COMMAND_INDEX_UPDATE referencing an unknown guild ID: %s. Discarding.', data['guild_id']
)
return
guild.command_counts = CommandCounts(data.get(0, 0), data.get(1, 0), data.get(2, 0))
parse_guild_application_command_index_update = parse_guild_application_command_counts_update
counts = data['application_command_counts']
old_counts = guild.application_command_counts or ApplicationCommandCounts(0, 0, 0)
guild.application_command_counts = new_counts = ApplicationCommandCounts(
counts.get(1, 0), counts.get(2, 0), counts.get(3, 0)
)
self.dispatch('application_command_counts_update', guild, old_counts, new_counts)
def parse_guild_emojis_update(self, data: gw.GuildEmojisUpdateEvent) -> None:
guild = self._get_guild(int(data['guild_id']))
@ -2083,7 +2090,7 @@ class ConnectionState:
ws = self.ws
channel = None
for channel in guild.channels:
if channel.permissions_for(guild.me).read_messages and channel.type != ChannelType.stage_voice:
if channel.permissions_for(guild.me).read_messages and channel.type != ChannelType.stage_voice: # type: ignore
break
else:
raise RuntimeError('No channels viewable')
@ -2143,12 +2150,16 @@ class ConnectionState:
if not guild.me:
await guild.query_members(user_ids=[self.self_id], cache=True) # type: ignore # self_id is always present here
if not force_scraping and any(
{
guild.me.guild_permissions.kick_members,
guild.me.guild_permissions.ban_members,
guild.me.guild_permissions.manage_roles,
}
if (
not force_scraping
and guild.me
and any(
{
guild.me.guild_permissions.kick_members,
guild.me.guild_permissions.ban_members,
guild.me.guild_permissions.manage_roles,
}
)
):
request = self._chunk_requests.get(guild.id)
if request is None:

7
discord/types/gateway.py

@ -39,7 +39,7 @@ from .snowflake import Snowflake
from .message import Message
from .sticker import GuildSticker
from .application import BaseAchievement, PartialApplication
from .guild import Guild, UnavailableGuild, SupplementalGuild
from .guild import ApplicationCommandCounts, Guild, UnavailableGuild, SupplementalGuild
from .user import Connection, User, PartialUser, ProtoSettingsType, Relationship, RelationshipType
from .threads import Thread, ThreadMember
from .scheduled_event import GuildScheduledEvent
@ -498,3 +498,8 @@ class PassiveUpdateEvent(TypedDict):
channels: List[PartialUpdateChannel]
voice_states: NotRequired[List[GuildVoiceState]]
members: NotRequired[List[MemberWithUser]]
class GuildApplicationCommandIndexUpdateEvent(TypedDict):
guild_id: Snowflake
application_command_counts: ApplicationCommandCounts

23
discord/types/guild.py

@ -22,7 +22,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
from typing import List, Literal, Optional, TypedDict
from typing import Dict, List, Literal, Optional, TypedDict
from typing_extensions import NotRequired
from .scheduled_event import GuildScheduledEvent
@ -55,9 +55,17 @@ MFALevel = Literal[0, 1]
VerificationLevel = Literal[0, 1, 2, 3, 4]
NSFWLevel = Literal[0, 1, 2, 3]
PremiumTier = Literal[0, 1, 2, 3]
ApplicationCommandCounts = Dict[Literal[1, 2, 3], int]
class PartialGuild(UnavailableGuild):
class BaseGuild(TypedDict):
id: Snowflake
name: str
icon: Optional[str]
features: List[str]
class PartialGuild(BaseGuild):
name: str
icon: Optional[str]
splash: Optional[str]
@ -77,7 +85,7 @@ class GuildPreview(PartialGuild, _GuildPreviewUnique):
...
class Guild(PartialGuild):
class Guild(UnavailableGuild, PartialGuild):
owner_id: Snowflake
region: str
afk_channel_id: Optional[Snowflake]
@ -100,7 +108,6 @@ class Guild(PartialGuild):
stickers: List[GuildSticker]
stage_instances: List[StageInstance]
guild_scheduled_events: List[GuildScheduledEvent]
icon_hash: NotRequired[Optional[str]]
owner: NotRequired[bool]
permissions: NotRequired[str]
widget_enabled: NotRequired[bool]
@ -117,6 +124,14 @@ class Guild(PartialGuild):
max_members: NotRequired[int]
premium_subscription_count: NotRequired[int]
max_video_channel_users: NotRequired[int]
application_command_counts: ApplicationCommandCounts
class UserGuild(BaseGuild):
owner: bool
permissions: str
approximate_member_count: NotRequired[int]
approximate_presence_count: NotRequired[int]
class InviteGuild(Guild, total=False):

40
docs/api.rst

@ -760,6 +760,19 @@ Guilds
:param after: A list of stickers after the update.
:type after: Sequence[:class:`GuildSticker`]
.. function:: on_application_command_counts_update(guild, before, after)
Called when a :class:`Guild`\'s application command counts are updated.
.. versionadded:: 2.0
:param guild: The guild who got their application command counts updated.
:type guild: :class:`Guild`
:param before: A namedtuple of application command counts before the update.
:type before: :class:`ApplicationCommandCounts`
:param after: A namedtuple of application command counts after the update.
:type after: :class:`ApplicationCommandCounts`
.. function:: on_audit_log_entry_create(entry)
Called when a :class:`Guild` gets a new audit log entry.
@ -6750,6 +6763,11 @@ Guild
:members:
:inherited-members:
.. attributetable:: UserGuild
.. autoclass:: UserGuild()
:members:
.. class:: BanEntry
A namedtuple which represents a ban returned from :meth:`~Guild.bans`.
@ -6765,6 +6783,28 @@ Guild
:type: :class:`User`
.. class:: ApplicationCommandCounts
A namedtuple which represents the application command counts for a guild.
.. attribute:: chat_input
The number of chat input (slash) commands.
:type: :class:`int`
.. attribute:: user
The number of user commands.
:type: :class:`int`
.. attribute:: message
The number of message commands.
:type: :class:`int`
Role
~~~~~

Loading…
Cancel
Save