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)
|
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:
|
class HistoryIterator:
|
||||||
"""Iterator for receiving a channel's message history.
|
"""Iterator for receiving a channel's message history.
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from .user import User
|
from .iterators import ReactionIterator
|
||||||
|
|
||||||
class Reaction:
|
class Reaction:
|
||||||
"""Represents a reaction to a message.
|
"""Represents a reaction to a message.
|
||||||
@ -86,11 +86,11 @@ class Reaction:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Reaction emoji={0.emoji!r} me={0.me} count={0.count}>'.format(self)
|
return '<Reaction emoji={0.emoji!r} me={0.me} count={0.count}>'.format(self)
|
||||||
|
|
||||||
@asyncio.coroutine
|
def users(self, limit=None, after=None):
|
||||||
def users(self, limit=100, after=None):
|
|
||||||
"""|coro|
|
"""|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
|
The ``after`` parameter must represent a member
|
||||||
and meet the :class:`abc.Snowflake` abc.
|
and meet the :class:`abc.Snowflake` abc.
|
||||||
@ -99,6 +99,8 @@ class Reaction:
|
|||||||
------------
|
------------
|
||||||
limit: int
|
limit: int
|
||||||
The maximum number of results to return.
|
The maximum number of results to return.
|
||||||
|
If not provided, returns all the users who
|
||||||
|
reacted to the message.
|
||||||
after: :class:`abc.Snowflake`
|
after: :class:`abc.Snowflake`
|
||||||
For pagination, reactions are sorted by member.
|
For pagination, reactions are sorted by member.
|
||||||
|
|
||||||
@ -107,23 +109,48 @@ class Reaction:
|
|||||||
HTTPException
|
HTTPException
|
||||||
Getting the users for the reaction failed.
|
Getting the users for the reaction failed.
|
||||||
|
|
||||||
Returns
|
Examples
|
||||||
--------
|
---------
|
||||||
List[:class:`User`]
|
|
||||||
A list of users who reacted to the message.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 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:
|
if self.custom_emoji:
|
||||||
emoji = '{0.name}:{0.id}'.format(self.emoji)
|
emoji = '{0.name}:{0.id}'.format(self.emoji)
|
||||||
else:
|
else:
|
||||||
emoji = self.emoji
|
emoji = self.emoji
|
||||||
|
|
||||||
if after:
|
if limit is None:
|
||||||
after = after.id
|
limit = self.count
|
||||||
|
|
||||||
msg = self.message
|
return ReactionIterator(self.message, emoji, limit, after)
|
||||||
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]
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user