3434 AsyncIterator ,
3535 Callable ,
3636 Dict ,
37+ Generator ,
3738 Iterable ,
3839 List ,
40+ Literal ,
3941 Optional ,
4042 TYPE_CHECKING ,
4143 Protocol ,
6163from .sticker import GuildSticker , StickerItem
6264from . import utils
6365from .flags import InviteFlags
66+ import warnings
6467
6568__all__ = (
6669 'Snowflake' ,
114117 MessageableChannel = Union [PartialMessageableChannel , GroupChannel ]
115118 SnowflakeTime = Union ["Snowflake" , datetime ]
116119
120+ class PinnedMessage (Message ):
121+ pinned_at : datetime
122+ pinned : Literal [True ]
123+
124+
117125MISSING = utils .MISSING
118126
119127
@@ -125,6 +133,26 @@ def __repr__(self) -> str:
125133_undefined : Any = _Undefined ()
126134
127135
136+ class _PinsIterator :
137+ def __init__ (self , iterator : AsyncIterator [PinnedMessage ]) -> None :
138+ self .__iterator : AsyncIterator [PinnedMessage ] = iterator
139+
140+ def __await__ (self ) -> Generator [Any , None , List [PinnedMessage ]]:
141+ warnings .warn (
142+ "`await <channel>.pins()` is deprecated; use `async for message in <channel>.pins()` instead." ,
143+ DeprecationWarning ,
144+ stacklevel = 2 ,
145+ )
146+
147+ async def gather () -> List [PinnedMessage ]:
148+ return [msg async for msg in self .__iterator ]
149+
150+ return gather ().__await__ ()
151+
152+ def __aiter__ (self ) -> AsyncIterator [PinnedMessage ]:
153+ return self .__iterator
154+
155+
128156async def _single_delete_strategy (messages : Iterable [Message ], * , reason : Optional [str ] = None ):
129157 for m in messages :
130158 try :
@@ -1756,34 +1784,132 @@ async def fetch_message(self, id: int, /) -> Message:
17561784 data = await self ._state .http .get_message (channel .id , id )
17571785 return self ._state .create_message (channel = channel , data = data )
17581786
1759- async def pins (self ) -> List [Message ]:
1760- """|coro|
1787+ async def __pins (
1788+ self ,
1789+ * ,
1790+ limit : Optional [int ] = 50 ,
1791+ before : Optional [SnowflakeTime ] = None ,
1792+ oldest_first : bool = False ,
1793+ ) -> AsyncIterator [PinnedMessage ]:
1794+ channel = await self ._get_channel ()
1795+ state = self ._state
1796+ max_limit : int = 50
1797+
1798+ time : Optional [str ] = (
1799+ (before if isinstance (before , datetime ) else utils .snowflake_time (before .id )).isoformat ()
1800+ if before is not None
1801+ else None
1802+ )
1803+
1804+ while True :
1805+ retrieve = max_limit if limit is None else min (limit , max_limit )
1806+ if retrieve < 1 :
1807+ break
1808+
1809+ data = await self ._state .http .pins_from (
1810+ channel_id = channel .id ,
1811+ limit = retrieve ,
1812+ before = time ,
1813+ )
1814+
1815+ items = data and data ['items' ]
1816+ if items :
1817+ if limit is not None :
1818+ limit -= len (items )
1819+
1820+ time = items [- 1 ]['pinned_at' ]
1821+
1822+ # Terminate loop on next iteration; there's no data left after this
1823+ if len (items ) < max_limit or not data ['has_more' ]:
1824+ limit = 0
1825+
1826+ if oldest_first :
1827+ items = reversed (items )
1828+
1829+ count = 0
1830+ for count , m in enumerate (items , start = 1 ):
1831+ message : Message = state .create_message (channel = channel , data = m ['message' ])
1832+ message ._pinned_at = utils .parse_time (m ['pinned_at' ])
1833+ yield message # pyright: ignore[reportReturnType]
1834+
1835+ if count < max_limit :
1836+ break
1837+
1838+ def pins (
1839+ self ,
1840+ * ,
1841+ limit : Optional [int ] = 50 ,
1842+ before : Optional [SnowflakeTime ] = None ,
1843+ oldest_first : bool = False ,
1844+ ) -> _PinsIterator :
1845+ """Retrieves an :term:`asynchronous iterator` of the pinned messages in the channel.
17611846
1762- Retrieves all messages that are currently pinned in the channel.
1847+ You must have :attr:`~discord.Permissions.view_channel` and
1848+ :attr:`~discord.Permissions.read_message_history` in order to use this.
1849+
1850+ .. versionchanged:: 2.6
1851+
1852+ Due to a change in Discord's API, this now returns a paginated iterator instead of a list.
1853+
1854+ For backwards compatibility, you can still retrieve a list of pinned messages by
1855+ using ``await`` on the returned object. This is however deprecated.
17631856
17641857 .. note::
17651858
17661859 Due to a limitation with the Discord API, the :class:`.Message`
1767- objects returned by this method do not contain complete
1860+ object returned by this method does not contain complete
17681861 :attr:`.Message.reactions` data.
17691862
1863+ Examples
1864+ ---------
1865+
1866+ Usage ::
1867+
1868+ counter = 0
1869+ async for message in channel.pins(limit=250):
1870+ counter += 1
1871+
1872+ Flattening into a list: ::
1873+
1874+ messages = [message async for message in channel.pins(limit=50)]
1875+ # messages is now a list of Message...
1876+
1877+ All parameters are optional.
1878+
1879+ Parameters
1880+ -----------
1881+ limit: Optional[int]
1882+ The number of pinned messages to retrieve. If ``None``, it retrieves
1883+ every pinned message in the channel. Note, however, that this would
1884+ make it a slow operation.
1885+ Defaults to ``50``.
1886+
1887+ .. versionadded:: 2.6
1888+ before: Optional[Union[:class:`datetime.datetime`, :class:`.abc.Snowflake`]]
1889+ Retrieve pinned messages before this time or snowflake.
1890+ If a datetime is provided, it is recommended to use a UTC aware datetime.
1891+ If the datetime is naive, it is assumed to be local time.
1892+
1893+ .. versionadded:: 2.6
1894+ oldest_first: :class:`bool`
1895+ If set to ``True``, return messages in oldest pin->newest pin order.
1896+ Defaults to ``False``.
1897+
1898+ .. versionadded:: 2.6
1899+
17701900 Raises
17711901 -------
17721902 ~discord.Forbidden
17731903 You do not have the permission to retrieve pinned messages.
17741904 ~discord.HTTPException
17751905 Retrieving the pinned messages failed.
17761906
1777- Returns
1778- --------
1779- List[ :class:`~discord.Message`]
1780- The messages that are currently pinned .
1907+ Yields
1908+ -------
1909+ :class:`~discord.Message`
1910+ The pinned message with :attr:`.Message.pinned_at` set .
17811911 """
1782-
1783- channel = await self ._get_channel ()
1784- state = self ._state
1785- data = await state .http .pins_from (channel .id )
1786- return [state .create_message (channel = channel , data = m ) for m in data ]
1912+ return _PinsIterator (self .__pins (limit = limit , before = before , oldest_first = oldest_first ))
17871913
17881914 async def history (
17891915 self ,
0 commit comments