mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-04-22 16:51:59 +00:00
Make Reaction.users return an async iterator.
This commit is contained in:
parent
b9b9d8c4d0
commit
ae6fb54b1b
@ -35,6 +35,81 @@ from .object import Object
|
||||
|
||||
PY35 = sys.version_info >= (3, 5)
|
||||
|
||||
class ReactionIterator:
|
||||
def __init__(self, message, emoji, limit=100, after=None):
|
||||
self.message = message
|
||||
self.limit = limit
|
||||
self.after = after
|
||||
state = message._state
|
||||
self.getter = state.http.get_reaction_users
|
||||
self.state = state
|
||||
self.emoji = emoji
|
||||
self.guild = message.guild
|
||||
self.channel_id = message.channel.id
|
||||
self.users = asyncio.Queue(loop=state.loop)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get(self):
|
||||
if self.users.empty():
|
||||
yield from self.fill_users()
|
||||
|
||||
try:
|
||||
return self.users.get_nowait()
|
||||
except asyncio.QueueEmpty:
|
||||
raise NoMoreItems()
|
||||
|
||||
@asyncio.coroutine
|
||||
def fill_users(self):
|
||||
# this is a hack because >circular imports<
|
||||
from .user import User
|
||||
|
||||
if self.limit > 0:
|
||||
retrieve = self.limit if self.limit <= 100 else 100
|
||||
|
||||
after = self.after.id if self.after else None
|
||||
data = yield from self.getter(self.message.id, self.channel_id, self.emoji, retrieve, after=after)
|
||||
|
||||
if data:
|
||||
self.limit -= retrieve
|
||||
self.after = Object(id=int(data[0]['id']))
|
||||
|
||||
if self.guild is None:
|
||||
for element in reversed(data):
|
||||
yield from self.users.put(User(state=self.state, data=element))
|
||||
else:
|
||||
for element in reversed(data):
|
||||
member_id = int(element['id'])
|
||||
member = self.guild.get_member(member_id)
|
||||
if member is not None:
|
||||
yield from self.users.put(member)
|
||||
else:
|
||||
yield from self.users.put(User(state=self.state, data=element))
|
||||
|
||||
@asyncio.coroutine
|
||||
def flatten(self):
|
||||
ret = []
|
||||
while True:
|
||||
try:
|
||||
user = yield from self.get()
|
||||
except NoMoreItems:
|
||||
return ret
|
||||
else:
|
||||
ret.append(user)
|
||||
|
||||
if PY35:
|
||||
@asyncio.coroutine
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
@asyncio.coroutine
|
||||
def __anext__(self):
|
||||
try:
|
||||
msg = yield from self.get()
|
||||
except NoMoreItems:
|
||||
raise StopAsyncIteration()
|
||||
else:
|
||||
return msg
|
||||
|
||||
class HistoryIterator:
|
||||
"""Iterator for receiving a channel's message history.
|
||||
|
||||
|
@ -26,7 +26,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import asyncio
|
||||
|
||||
from .user import User
|
||||
from .iterators import ReactionIterator
|
||||
|
||||
class Reaction:
|
||||
"""Represents a reaction to a message.
|
||||
@ -86,11 +86,11 @@ class Reaction:
|
||||
def __repr__(self):
|
||||
return '<Reaction emoji={0.emoji!r} me={0.me} count={0.count}>'.format(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def users(self, limit=100, after=None):
|
||||
def users(self, limit=None, after=None):
|
||||
"""|coro|
|
||||
|
||||
Get the users that added this reaction.
|
||||
Returns an asynchronous iterator representing the
|
||||
users that have reacted to the message.
|
||||
|
||||
The ``after`` parameter must represent a member
|
||||
and meet the :class:`abc.Snowflake` abc.
|
||||
@ -99,6 +99,8 @@ class Reaction:
|
||||
------------
|
||||
limit: int
|
||||
The maximum number of results to return.
|
||||
If not provided, returns all the users who
|
||||
reacted to the message.
|
||||
after: :class:`abc.Snowflake`
|
||||
For pagination, reactions are sorted by member.
|
||||
|
||||
@ -107,23 +109,48 @@ class Reaction:
|
||||
HTTPException
|
||||
Getting the users for the reaction failed.
|
||||
|
||||
Returns
|
||||
--------
|
||||
List[:class:`User`]
|
||||
A list of users who reacted to the message.
|
||||
"""
|
||||
Examples
|
||||
---------
|
||||
|
||||
# TODO: Return an iterator a la `Messageable.history`?
|
||||
Usage ::
|
||||
|
||||
# I do not actually recommend doing this.
|
||||
async for user in reaction.users():
|
||||
await channel.send('{0} has reacted with {1.emoji}!'.format(user, reaction))
|
||||
|
||||
Flattening into a list: ::
|
||||
|
||||
users = await reaction.users().flatten()
|
||||
# users is now a list...
|
||||
winner = random.choice(users)
|
||||
await channel.send('{} has won the raffle.'.format(winner))
|
||||
|
||||
Python 3.4 Usage ::
|
||||
|
||||
iterator = reaction.users()
|
||||
while True:
|
||||
try:
|
||||
user = yield from iterator.get()
|
||||
except discord.NoMoreItems:
|
||||
break
|
||||
else:
|
||||
await channel.send('{0} has reacted with {1.emoji}!'.format(user, reaction))
|
||||
|
||||
Yields
|
||||
--------
|
||||
Union[:class:`User`, :class:`Member`]
|
||||
The member (if retrievable) or the user that has reacted
|
||||
to this message. The case where it can be a :class:`Member` is
|
||||
in a guild message context. Sometimes it can be a :class:`User`
|
||||
if the member has left the guild.
|
||||
"""
|
||||
|
||||
if self.custom_emoji:
|
||||
emoji = '{0.name}:{0.id}'.format(self.emoji)
|
||||
else:
|
||||
emoji = self.emoji
|
||||
|
||||
if after:
|
||||
after = after.id
|
||||
if limit is None:
|
||||
limit = self.count
|
||||
|
||||
msg = self.message
|
||||
state = msg._state
|
||||
data = yield from state.http.get_reaction_users(msg.id, msg.channel.id, emoji, limit, after=after)
|
||||
return [User(state=state, data=user) for user in data]
|
||||
return ReactionIterator(self.message, emoji, limit, after)
|
||||
|
Loading…
x
Reference in New Issue
Block a user