Make Reaction.users return an async iterator.
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user