aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2019-02-12 20:21:29 -0500
committerRapptz <[email protected]>2019-02-12 20:22:47 -0500
commit5d78f43e558cdd55e22eb12a090d3d75fd258a8e (patch)
tree9485cf47c706eef9eb315c897e589702423a697a
parentBump aiohttp requirement and fix AsyncWebhookAdapter (diff)
downloaddiscord.py-5d78f43e558cdd55e22eb12a090d3d75fd258a8e.tar.xz
discord.py-5d78f43e558cdd55e22eb12a090d3d75fd258a8e.zip
Expose more information from partial invites, along with counts.
This adds the following information. * `PartialInviteGuild` to replace `Object` patching * `PartialInviteChannel` to replace `Object` patching * Invite.approximate_member_count and Invite.approximate_presence_count The new partial objects provide better documentation on what is expected when you fetch random invites. Fixes #1830
-rw-r--r--discord/__init__.py2
-rw-r--r--discord/client.py14
-rw-r--r--discord/guild.py10
-rw-r--r--discord/http.py7
-rw-r--r--discord/invite.py170
-rw-r--r--docs/api.rst11
6 files changed, 187 insertions, 27 deletions
diff --git a/discord/__init__.py b/discord/__init__.py
index a982cadd..b4e749c2 100644
--- a/discord/__init__.py
+++ b/discord/__init__.py
@@ -35,7 +35,7 @@ from .permissions import Permissions, PermissionOverwrite
from .role import Role
from .file import File
from .colour import Color, Colour
-from .invite import Invite
+from .invite import Invite, PartialInviteChannel, PartialInviteGuild
from .object import Object
from .reaction import Reaction
from . import utils, opus, abc
diff --git a/discord/client.py b/discord/client.py
index f832efcc..26e22df9 100644
--- a/discord/client.py
+++ b/discord/client.py
@@ -882,7 +882,7 @@ class Client:
# Invite management
- async def get_invite(self, url):
+ async def get_invite(self, url, *, with_counts=True):
"""|coro|
Gets an :class:`Invite` from a discord.gg URL or ID.
@@ -890,13 +890,17 @@ class Client:
Note
------
If the invite is for a guild you have not joined, the guild and channel
- attributes of the returned invite will be :class:`Object` with the names
- patched in.
+ attributes of the returned :class:`Invite` will be :class:`PartialInviteGuild` and
+ :class:`PartialInviteChannel` respectively.
Parameters
-----------
- url : str
+ url: :class:`str`
The discord invite ID or URL (must be a discord.gg URL).
+ with_counts: :class:`bool`
+ Whether to include count information in the invite. This fills the
+ :attr:`Invite.approximate_member_count` and :attr:`Invite.approximate_presence_count`
+ fields.
Raises
-------
@@ -912,7 +916,7 @@ class Client:
"""
invite_id = self._resolve_invite(url)
- data = await self.http.get_invite(invite_id)
+ data = await self.http.get_invite(invite_id, with_counts=with_counts)
return Invite.from_incomplete(state=self._connection, data=data)
async def delete_invite(self, invite):
diff --git a/discord/guild.py b/discord/guild.py
index 97247666..7777f0eb 100644
--- a/discord/guild.py
+++ b/discord/guild.py
@@ -83,7 +83,7 @@ class Guild(Hashable):
The timeout to get sent to the AFK channel.
afk_channel: Optional[:class:`VoiceChannel`]
The channel that denotes the AFK channel. None if it doesn't exist.
- icon: :class:`str`
+ icon: Optional[:class:`str`]
The guild's icon.
id: :class:`int`
The guild's ID.
@@ -114,7 +114,7 @@ class Guild(Hashable):
- ``VERIFIED``: Guild is a "verified" server.
- ``MORE_EMOJI``: Guild is allowed to have more than 50 custom emoji.
- splash: :class:`str`
+ splash: Optional[:class:`str`]
The guild's invite splash.
"""
@@ -601,7 +601,7 @@ class Guild(Hashable):
channel upon creation. This parameter expects a :class:`dict` of
overwrites with the target (either a :class:`Member` or a :class:`Role`)
as the key and a :class:`PermissionOverwrite` as the value.
-
+
Note
--------
Creating a channel of a specified position will not update the position of
@@ -641,7 +641,7 @@ class Guild(Hashable):
The permissions will be automatically synced to category if no
overwrites are provided.
position: :class:`int`
- The position in the channel list. This is a number that starts
+ The position in the channel list. This is a number that starts
at 0. e.g. the top channel is position 0.
topic: Optional[:class:`str`]
The new channel's topic.
@@ -679,7 +679,7 @@ class Guild(Hashable):
This is similar to :meth:`create_text_channel` except makes a :class:`VoiceChannel` instead, in addition
to having the following new parameters.
-
+
Parameters
-----------
bitrate: :class:`int`
diff --git a/discord/http.py b/discord/http.py
index 75c02457..cde1a373 100644
--- a/discord/http.py
+++ b/discord/http.py
@@ -647,8 +647,11 @@ class HTTPClient:
return self.request(r, reason=reason, json=payload)
- def get_invite(self, invite_id):
- return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id))
+ def get_invite(self, invite_id, *, with_counts=True):
+ params = {
+ 'with_counts': int(with_counts)
+ }
+ return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id), params=params)
def invites_from(self, guild_id):
return self.request(Route('GET', '/guilds/{guild_id}/invites', guild_id=guild_id))
diff --git a/discord/invite.py b/discord/invite.py
index 80483ab1..6b1a575a 100644
--- a/discord/invite.py
+++ b/discord/invite.py
@@ -27,6 +27,141 @@ DEALINGS IN THE SOFTWARE.
from .utils import parse_time
from .mixins import Hashable
from .object import Object
+from .enums import ChannelType, VerificationLevel, try_enum
+from collections import namedtuple
+
+class PartialInviteChannel(namedtuple('PartialInviteChannel', 'id name type')):
+ """Represents a "partial" invite channel.
+
+ This model will be given when the user is not part of the
+ guild the :class:`Invite` resolves to.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two partial channels are the same.
+
+ .. describe:: x != y
+
+ Checks if two partial channels are not the same.
+
+ .. describe:: hash(x)
+
+ Return the partial channel's hash.
+
+ .. describe:: str(x)
+
+ Returns the partial channel's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The partial channel's name.
+ id: :class:`int`
+ The partial channel's ID.
+ type: :class:`ChannelType`
+ The partial channel's type.
+ """
+
+ __slots__ = ()
+
+ def __str__(self):
+ return self.name
+
+ @property
+ def mention(self):
+ """:class:`str` : The string that allows you to mention the channel."""
+ return '<#%s>' % self.id
+
+ @property
+ def created_at(self):
+ """Returns the channel's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+class PartialInviteGuild(namedtuple('PartialInviteGuild', 'features icon id name splash verification_level')):
+ """Represents a "partial" invite guild.
+
+ This model will be given when the user is not part of the
+ guild the :class:`Invite` resolves to.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two partial guilds are the same.
+
+ .. describe:: x != y
+
+ Checks if two partial guilds are not the same.
+
+ .. describe:: hash(x)
+
+ Return the partial guild's hash.
+
+ .. describe:: str(x)
+
+ Returns the partial guild's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The partial guild's name.
+ id: :class:`int`
+ The partial guild's ID.
+ verification_level: :class:`VerificationLevel`
+ The partial guild's verification level.
+ features: List[:class:`str`]
+ A list of features the guild has. See :attr:`Guild.features` for more information.
+ icon: Optional[:class:`str`]
+ The partial guild's icon.
+ splash: Optional[:class:`str`]
+ The partial guild's invite splash.
+ """
+
+ __slots__ = ()
+
+ def __str__(self):
+ return self.name
+
+ @property
+ def created_at(self):
+ """Returns the guild's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ @property
+ def icon_url(self):
+ """Returns the URL version of the guild's icon. Returns an empty string if it has no icon."""
+ return self.icon_url_as()
+
+ def icon_url_as(self, *, format='webp', size=1024):
+ """:class:`str`: The same operation as :meth:`Guild.icon_url_as`."""
+ if not valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 2048")
+ if format not in VALID_ICON_FORMATS:
+ raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
+
+ if self.icon is None:
+ return ''
+
+ return 'https://cdn.discordapp.com/icons/{0.id}/{0.icon}.{1}?size={2}'.format(self, format, size)
+
+ @property
+ def splash_url(self):
+ """Returns the URL version of the guild's invite splash. Returns an empty string if it has no splash."""
+ return self.splash_url_as()
+
+ def splash_url_as(self, *, format='webp', size=2048):
+ """:class:`str`: The same operation as :meth:`Guild.splash_url_as`."""
+ if not valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 2048")
+ if format not in VALID_ICON_FORMATS:
+ raise InvalidArgument("format must be one of {}".format(VALID_ICON_FORMATS))
+
+ if self.splash is None:
+ return ''
+
+ return 'https://cdn.discordapp.com/splashes/{0.id}/{0.splash}.{1}?size={2}'.format(self, format, size)
class Invite(Hashable):
"""Represents a Discord :class:`Guild` or :class:`abc.GuildChannel` invite.
@@ -58,7 +193,7 @@ class Invite(Hashable):
How long the before the invite expires in seconds. A value of 0 indicates that it doesn't expire.
code: :class:`str`
The URL fragment used for the invite.
- guild: :class:`Guild`
+ guild: Union[:class:`Guild`, :class:`PartialInviteGuild`]
The guild the invite is for.
revoked: :class:`bool`
Indicates if the invite has been revoked.
@@ -73,13 +208,19 @@ class Invite(Hashable):
How many times the invite can be used.
inviter: :class:`User`
The user who created the invite.
- channel: :class:`abc.GuildChannel`
+ approximate_member_count: Optional[:class:`int`]
+ The approximate number of members in the guild.
+ approximate_presence_count: Optional[:class:`int`]
+ The approximate number of members currently active in the guild.
+ This includes idle, dnd, online, and invisible members. Offline members are excluded.
+ channel: Union[:class:`abc.GuildChannel`, :class:`PartialInviteChannel`]
The channel the invite is for.
"""
__slots__ = ('max_age', 'code', 'guild', 'revoked', 'created_at', 'uses',
- 'temporary', 'max_uses', 'inviter', 'channel', '_state')
+ 'temporary', 'max_uses', 'inviter', 'channel', '_state',
+ 'approximate_member_count', 'approximate_presence_count' )
def __init__(self, *, state, data):
self._state = state
@@ -91,6 +232,8 @@ class Invite(Hashable):
self.temporary = data.get('temporary')
self.uses = data.get('uses')
self.max_uses = data.get('max_uses')
+ self.approximate_presence_count = data.get('approximate_presence_count')
+ self.approximate_member_count = data.get('approximate_member_count')
inviter_data = data.get('inviter')
self.inviter = None if inviter_data is None else self._state.store_user(inviter_data)
@@ -104,17 +247,16 @@ class Invite(Hashable):
if guild is not None:
channel = guild.get_channel(channel_id)
else:
- guild = Object(id=guild_id)
- channel = Object(id=channel_id)
- guild.name = data['guild']['name']
-
- guild.splash = data['guild']['splash']
- guild.splash_url = ''
- if guild.splash:
- guild.splash_url = 'https://cdn.discordapp.com/splashes/{0.id}/{0.splash}.jpg?size=2048'.format(guild)
-
- channel.name = data['channel']['name']
-
+ channel_data = data['channel']
+ guild_data = data['guild']
+ channel_type = try_enum(ChannelType, channel_data['type'])
+ channel = PartialInviteChannel(id=channel_id, name=channel_data['name'], type=channel_type)
+ guild = PartialInviteGuild(id=guild_id,
+ name=guild_data['name'],
+ features=guild_data.get('features', []),
+ icon=guild_data.get('icon'),
+ splash=guild_data.get('splash'),
+ verification_level=try_enum(VerificationLevel, guild_data.get('verification_level')))
data['guild'] = guild
data['channel'] = channel
return cls(state=state, data=data)
diff --git a/docs/api.rst b/docs/api.rst
index bdb57780..5816f60f 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -2035,6 +2035,17 @@ GroupChannel
.. autocomethod:: typing
:async-with:
+PartialInviteGuild
+~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: PartialInviteGuild()
+ :members:
+
+PartialInviteChannel
+~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: PartialInviteChannel()
+ :members:
Invite
~~~~~~~