Browse Source

Expose Metadata

Added access to:
* `/users/@me/guilds`
* `/guilds/{guild_id}`
* `/guilds/{guild_id}/members/{member_id}`

BREAKING CHANGE:
* `get_user_info` -> `fetch_user_info` to match naming scheme.

Remove useless note

Remove `reverse` and corresponding documentation

Update documentation to reflect #1988

Rename `get_` HTTP functions to `fetch_`

Breaking Changes:
* `get_message` -> `fetch_message`
* `get_invite` -> `fetch_invite`
* `get_user_profile` -> `fetch_user_profile`
* `get_webhook_info` -> `fetch_webhook`
* `get_ban` -> `fetch_ban`

Fix InviteConverter, update migrating.rst

Rename get_message to fetch_message
pull/2014/head
NCPlayz 6 years ago
committed by Rapptz
parent
commit
f507f508a2
  1. 2
      discord/abc.py
  2. 81
      discord/client.py
  3. 4
      discord/ext/commands/converter.py
  4. 27
      discord/guild.py
  5. 18
      discord/http.py
  6. 132
      discord/iterators.py
  7. 6
      docs/migrating.rst

2
discord/abc.py

@ -816,7 +816,7 @@ class Messageable(metaclass=abc.ABCMeta):
""" """
return Typing(self) return Typing(self)
async def get_message(self, id): async def fetch_message(self, id):
"""|coro| """|coro|
Retrieves a single :class:`.Message` from the destination. Retrieves a single :class:`.Message` from the destination.

81
discord/client.py

@ -39,6 +39,7 @@ from .user import User, Profile
from .invite import Invite from .invite import Invite
from .object import Object from .object import Object
from .guild import Guild from .guild import Guild
from .member import Member
from .errors import * from .errors import *
from .enums import Status, VoiceRegion from .enums import Status, VoiceRegion
from .gateway import * from .gateway import *
@ -49,6 +50,7 @@ from .state import ConnectionState
from . import utils from . import utils
from .backoff import ExponentialBackoff from .backoff import ExponentialBackoff
from .webhook import Webhook from .webhook import Webhook
from .iterators import GuildIterator
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -841,6 +843,77 @@ class Client:
# Guild stuff # Guild stuff
def fetch_guilds(self, *, limit=100, before=None, after=None):
"""|coro|
Retreives an :class:`AsyncIterator` that enables receiving your guilds.
All parameters are optional.
Parameters
-----------
limit: Optional[:class:`int`]
The number of guilds to retrieve.
If ``None``, it retrieves every guild you have access to. Note, however,
that this would make it a slow operation.
Defaults to 100.
before: :class:`Snowflake` or `datetime`
Retrieves guilds before this date or object.
If a date is provided it must be a timezone-naive datetime representing UTC time.
after: :class:`Snowflake` or `datetime`
Retrieve guilds after this date or object.
If a date is provided it must be a timezone-naive datetime representing UTC time.
Raises
------
HTTPException
Getting the guilds failed.
Yields
--------
:class:`Guild`
The guild with the guild data parsed.
Examples
---------
Usage ::
async for guild in client.fetch_guilds(limit=150):
print(guild.name)
Flattening into a list ::
guilds = await client.fetch_guilds(limit=150).flatten()
# guilds is now a list of Guild...
"""
return GuildIterator(self, limit=limit, before=before, after=after)
async def fetch_guild(self, guild_id):
"""|coro|
Retreives a :class:`Guild` from an ID.
Parameters
-----------
guild_id: :class:`int`
The guild's ID to fetch from.
Raises
------
Forbidden
You do not have access to the guild.
HTTPException
Getting the guild failed.
Returns
--------
:class:`Guild`
The guild from the ID.
"""
data = await self.http.get_guild(guild_id)
return Guild(data=data, state=self._connection)
async def create_guild(self, name, region=None, icon=None): async def create_guild(self, name, region=None, icon=None):
"""|coro| """|coro|
@ -885,7 +958,7 @@ class Client:
# Invite management # Invite management
async def get_invite(self, url, *, with_counts=True): async def fetch_invite(self, url, *, with_counts=True):
"""|coro| """|coro|
Gets an :class:`Invite` from a discord.gg URL or ID. Gets an :class:`Invite` from a discord.gg URL or ID.
@ -974,7 +1047,7 @@ class Client:
bot_require_code_grant=data['bot_require_code_grant'], bot_require_code_grant=data['bot_require_code_grant'],
owner=User(state=self._connection, data=data['owner'])) owner=User(state=self._connection, data=data['owner']))
async def get_user_info(self, user_id): async def fetch_user(self, user_id):
"""|coro| """|coro|
Retrieves a :class:`User` based on their ID. This can only Retrieves a :class:`User` based on their ID. This can only
@ -1002,7 +1075,7 @@ class Client:
data = await self.http.get_user_info(user_id) data = await self.http.get_user_info(user_id)
return User(state=self._connection, data=data) return User(state=self._connection, data=data)
async def get_user_profile(self, user_id): async def fetch_user_profile(self, user_id):
"""|coro| """|coro|
Gets an arbitrary user's profile. This can only be used by non-bot accounts. Gets an arbitrary user's profile. This can only be used by non-bot accounts.
@ -1040,7 +1113,7 @@ class Client:
user=User(data=user, state=state), user=User(data=user, state=state),
connected_accounts=data['connected_accounts']) connected_accounts=data['connected_accounts'])
async def get_webhook_info(self, webhook_id): async def fetch_webhook(self, webhook_id):
"""|coro| """|coro|
Retrieves a :class:`Webhook` with the specified ID. Retrieves a :class:`Webhook` with the specified ID.

4
discord/ext/commands/converter.py

@ -336,11 +336,11 @@ class GameConverter(Converter):
class InviteConverter(Converter): class InviteConverter(Converter):
"""Converts to a :class:`Invite`. """Converts to a :class:`Invite`.
This is done via an HTTP request using :meth:`.Bot.get_invite`. This is done via an HTTP request using :meth:`.Bot.fetch_invite`.
""" """
async def convert(self, ctx, argument): async def convert(self, ctx, argument):
try: try:
invite = await ctx.bot.get_invite(argument) invite = await ctx.bot.fetch_invite(argument)
return invite return invite
except Exception as exc: except Exception as exc:
raise BadArgument('Invite is invalid or expired') from exc raise BadArgument('Invite is invalid or expired') from exc

27
discord/guild.py

@ -944,7 +944,32 @@ class Guild(Hashable):
fields['explicit_content_filter'] = explicit_content_filter.value fields['explicit_content_filter'] = explicit_content_filter.value
await http.edit_guild(self.id, reason=reason, **fields) await http.edit_guild(self.id, reason=reason, **fields)
async def get_ban(self, user): async def fetch_member(self, member_id):
"""|coro|
Retreives a :class:`Member` from a guild ID, and a member ID.
Parameters
-----------
member_id: :class:`int`
The member's ID to fetch from.
Raises
-------
Forbidden
You do not have access to the guild.
HTTPException
Getting the guild failed.
Returns
--------
:class:`Member`
The member from the member ID.
"""
data = await self._state.http.get_member(self.id, member_id)
return Member(data=data, state=self._state, guild=self)
async def fetch_ban(self, user):
"""|coro| """|coro|
Retrieves the :class:`BanEntry` for a user, which is a namedtuple Retrieves the :class:`BanEntry` for a user, which is a namedtuple

18
discord/http.py

@ -553,9 +553,24 @@ class HTTPClient:
# Guild management # Guild management
def get_guilds(self, limit, before=None, after=None):
params = {
'limit': limit
}
if before:
params['before'] = before
if after:
params['after'] = after
return self.request(Route('GET', '/users/@me/guilds'), params=params)
def leave_guild(self, guild_id): def leave_guild(self, guild_id):
return self.request(Route('DELETE', '/users/@me/guilds/{guild_id}', guild_id=guild_id)) return self.request(Route('DELETE', '/users/@me/guilds/{guild_id}', guild_id=guild_id))
def get_guild(self, guild_id):
return self.request(Route('GET', '/guilds/{guild_id}', guild_id=guild_id))
def delete_guild(self, guild_id): def delete_guild(self, guild_id):
return self.request(Route('DELETE', '/guilds/{guild_id}', guild_id=guild_id)) return self.request(Route('DELETE', '/guilds/{guild_id}', guild_id=guild_id))
@ -593,6 +608,9 @@ class HTTPClient:
payload = {'code': code} payload = {'code': code}
return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload, reason=reason) return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload, reason=reason)
def get_member(self, guild_id, member_id):
return self.request(Route('GET', '/guilds/{guild_id}/members/{member_id}', guild_id=guild_id, member_id=member_id))
def prune_members(self, guild_id, days, *, reason=None): def prune_members(self, guild_id, days, *, reason=None):
params = { params = {
'days': days 'days': days

132
discord/iterators.py

@ -237,7 +237,7 @@ class HistoryIterator(_AsyncIterator):
elif self.limit == 101: elif self.limit == 101:
self.limit = 100 # Thanks discord self.limit = 100 # Thanks discord
elif self.limit == 1: elif self.limit == 1:
raise ValueError("Use get_message.") raise ValueError("Use fetch_message.")
self._retrieve_messages = self._retrieve_messages_around_strategy self._retrieve_messages = self._retrieve_messages_around_strategy
if self.before and self.after: if self.before and self.after:
@ -459,3 +459,133 @@ class AuditLogIterator(_AsyncIterator):
continue continue
await self.entries.put(AuditLogEntry(data=element, users=self._users, guild=self.guild)) await self.entries.put(AuditLogEntry(data=element, users=self._users, guild=self.guild))
class GuildIterator(_AsyncIterator):
"""Iterator for receiving the client's guilds.
The guilds endpoint has the same two behaviours as described
in :class:`HistoryIterator`:
If `before` is specified, the guilds endpoint returns the `limit`
newest guilds before `before`, sorted with newest first. For filling over
100 guilds, update the `before` parameter to the oldest guild received.
Guilds will be returned in order by time.
If `after` is specified, it returns the `limit` oldest guilds after `after`,
sorted with newest first. For filling over 100 guilds, update the `after`
parameter to the newest guild received, If guilds are not reversed, they
will be out of order (99-0, 199-100, so on)
Not that if both before and after are specified, before is ignored by the
guilds endpoint.
Parameters
-----------
bot: :class:`discord.Client`
The client to retrieve the guilds from.
limit: :class:`int`
Maximum number of guilds to retrieve.
before: :class:`Snowflake`
Object before which all guilds must be.
after: :class:`Snowflake`
Object after which all guilds must be.
"""
def __init__(self, bot, limit, before=None, after=None):
if isinstance(before, datetime.datetime):
before = Object(id=time_snowflake(before, high=False))
if isinstance(after, datetime.datetime):
after = Object(id=time_snowflake(after, high=True))
self.bot = bot
self.limit = limit
self.before = before
self.after = after
self._filter = None
self.state = self.bot._connection
self.get_guilds = self.bot.http.get_guilds
self.guilds = asyncio.Queue(loop=self.state.loop)
if self.before and self.after:
self._retrieve_guilds = self._retrieve_guilds_before_strategy
self._filter = lambda m: int(m['id']) > self.after.id
elif self.after:
self._retrieve_guilds = self._retrieve_guilds_after_strategy
else:
self._retrieve_guilds = self._retrieve_guilds_before_strategy
async def next(self):
if self.guilds.empty():
await self.fill_guilds()
try:
return self.guilds.get_nowait()
except asyncio.QueueEmpty:
raise NoMoreItems()
def _get_retrieve(self):
l = self.limit
if l is None:
r = 100
elif l <= 100:
r = l
else:
r = 100
self.retrieve = r
return r > 0
def create_guild(self, data):
from .guild import Guild
return Guild(state=self.state, data=data)
async def flatten(self):
result = []
while self._get_retrieve():
data = await self._retrieve_guilds(self.retrieve)
if len(data) < 100:
self.limit = 0
if self._filter:
data = filter(self._filter, data)
for element in data:
result.append(self.create_guild(element))
return result
async def fill_guilds(self):
if self._get_retrieve():
data = await self._retrieve_guilds(self.retrieve)
if self.limit is None or len(data) < 100:
self.limit = 0
if self._filter:
data = filter(self._filter, data)
for element in data:
await self.guilds.put(self.create_guild(element))
async def _retrieve_guilds(self, retrieve):
"""Retrieve guilds and update next parameters."""
pass
async def _retrieve_guilds_before_strategy(self, retrieve):
"""Retrieve guilds using before parameter."""
before = self.before.id if self.before else None
data = await self.get_guilds(retrieve, before=before)
if len(data):
if self.limit is not None:
self.limit -= retrieve
self.before = Object(id=int(data[-1]['id']))
return data
async def _retrieve_guilds_after_strategy(self, retrieve):
"""Retrieve guilds using after parameter."""
after = self.after.id if self.after else None
data = await self.get_guilds(retrieve, after=after)
if len(data):
if self.limit is not None:
self.limit -= retrieve
self.after = Object(id=int(data[0]['id']))
return data

6
docs/migrating.rst

@ -148,10 +148,14 @@ A list of these changes is enumerated below.
+---------------------------------------+------------------------------------------------------------------------------+ +---------------------------------------+------------------------------------------------------------------------------+
| ``Client.get_bans`` | :meth:`Guild.bans` | | ``Client.get_bans`` | :meth:`Guild.bans` |
+---------------------------------------+------------------------------------------------------------------------------+ +---------------------------------------+------------------------------------------------------------------------------+
| ``Client.get_message`` | :meth:`abc.Messageable.get_message` | | ``Client.get_invite`` | :meth:`Client.fetch_invite` |
+---------------------------------------+------------------------------------------------------------------------------+
| ``Client.get_message`` | :meth:`abc.Messageable.fetch_message` |
+---------------------------------------+------------------------------------------------------------------------------+ +---------------------------------------+------------------------------------------------------------------------------+
| ``Client.get_reaction_users`` | :meth:`Reaction.users` | | ``Client.get_reaction_users`` | :meth:`Reaction.users` |
+---------------------------------------+------------------------------------------------------------------------------+ +---------------------------------------+------------------------------------------------------------------------------+
| ``Client.get_user_info`` | :meth:`Client.fetch_user` |
+---------------------------------------+------------------------------------------------------------------------------+
| ``Client.invites_from`` | :meth:`abc.GuildChannel.invites` or :meth:`Guild.invites` | | ``Client.invites_from`` | :meth:`abc.GuildChannel.invites` or :meth:`Guild.invites` |
+---------------------------------------+------------------------------------------------------------------------------+ +---------------------------------------+------------------------------------------------------------------------------+
| ``Client.join_voice_channel`` | :meth:`VoiceChannel.connect` (see :ref:`migrating_1_0_voice`) | | ``Client.join_voice_channel`` | :meth:`VoiceChannel.connect` (see :ref:`migrating_1_0_voice`) |

Loading…
Cancel
Save