From 73f337d709e6a180d51e4332ea79a6eb0394f724 Mon Sep 17 00:00:00 2001 From: dolfies Date: Mon, 12 Sep 2022 17:35:44 -0400 Subject: [PATCH] Raise the original error instead of a proxy in member list errors --- discord/guild.py | 8 ++++---- discord/state.py | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/discord/guild.py b/discord/guild.py index 100111c73..eb7da48e8 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -3576,6 +3576,8 @@ class Guild(Hashable): ClientException This guild cannot be chunked or chunking failed. Guild is no longer available. + InvalidData + Did not receive a response from the gateway. Returns -------- @@ -3588,8 +3590,6 @@ class Guild(Hashable): raise ClientException('This guild is no longer available') members = await self._state.chunk_guild(self, channels=[channel] if channel else []) - if members is None: - raise ClientException('Chunking failed') return members async def fetch_members( @@ -3633,6 +3633,8 @@ class Guild(Hashable): ClientException Fetching members failed. Guild is no longer available. + InvalidData + Did not receive a response from the gateway. Returns -------- @@ -3645,8 +3647,6 @@ class Guild(Hashable): members = await self._state.scrape_guild( self, cache=cache, force_scraping=force_scraping, delay=delay, channels=channels ) - if members is None: - raise ClientException('Fetching members failed') return members async def query_members( diff --git a/discord/state.py b/discord/state.py index e3a3dea45..baada58a0 100644 --- a/discord/state.py +++ b/discord/state.py @@ -48,7 +48,7 @@ import weakref import inspect from math import ceil -from .errors import NotFound +from .errors import ClientException, InvalidData, NotFound from .guild import CommandCounts, Guild from .activity import BaseActivity from .user import User, ClientUser @@ -175,7 +175,8 @@ class MemberSidebar: self.channels = [str(channel.id) for channel in (channels or self.get_channels(1 if chunk else 5))] self.ranges = self.get_ranges() self.subscribing: bool = False - self.buffer: Optional[List[Member]] = [] + self.buffer: List[Member] = [] + self.exception: Optional[Exception] = None self.waiters: List[asyncio.Future[Optional[List[Member]]]] = [] def __bool__(self) -> bool: @@ -281,7 +282,7 @@ class MemberSidebar: for member in members: guild._add_member(member) - async def wait(self) -> Optional[List[Member]]: + async def wait(self) -> List[Member]: future = self.loop.create_future() self.waiters.append(future) try: @@ -289,7 +290,7 @@ class MemberSidebar: finally: self.waiters.remove(future) - def get_future(self) -> asyncio.Future[Optional[List[Member]]]: + def get_future(self) -> asyncio.Future[List[Member]]: future = self.loop.create_future() self.waiters.append(future) return future @@ -297,7 +298,10 @@ class MemberSidebar: def done(self) -> None: for future in self.waiters: if not future.done(): - future.set_result(self.buffer) + if self.exception: + future.set_exception(self.exception) + else: + future.set_result(self.buffer) try: del self.state._scrape_requests[self.guild.id] @@ -310,11 +314,11 @@ class MemberSidebar: async def wrapper(self): try: await self.scrape() - except RuntimeError as exc: - _log.warning('Member list scraping failed for %s (%s).', self.guild.id, exc) - self.buffer = None except asyncio.CancelledError: pass + except Exception as exc: + _log.warning('Member list scraping failed for %s (%s).', self.guild.id, exc) + self.exception = exc finally: self.done() @@ -337,7 +341,7 @@ class MemberSidebar: break if not requests: - raise RuntimeError('failed to choose channels or ranges') + raise ClientException('Failed to automatically choose channels; please specify them manually') def predicate(data): return int(data['guild_id']) == guild.id and any(op['op'] == 'SYNC' for op in data['ops']) @@ -352,7 +356,7 @@ class MemberSidebar: self.subscribing = False break else: - raise RuntimeError('timeout: no response from gateway') + raise InvalidData('Did not receive a response from Discord') await asyncio.sleep(delay) @@ -790,6 +794,8 @@ class ConnectionState: await asyncio.wait_for(future, timeout=10) except asyncio.TimeoutError: _log.warning('Timed out waiting for chunks for guild_id %s.', guild.id) + except (ClientException, InvalidData): + pass except asyncio.CancelledError: pass else: @@ -891,7 +897,7 @@ class ConnectionState: self.session_type = data.get('session_type', 'normal') self.connections = {c['id']: Connection(state=self, data=c) for c in data.get('connected_accounts', [])} - if 'required_action' in data: # Locked more than likely + if 'required_action' in data: self.parse_user_required_action_update(data) if 'sessions' in data: @@ -1720,7 +1726,7 @@ class ConnectionState: force_scraping: bool = ..., channels: List[abcSnowflake] = ..., delay: Union[int, float] = ..., - ) -> Optional[List[Member]]: + ) -> List[Member]: ... @overload @@ -1733,7 +1739,7 @@ class ConnectionState: force_scraping: bool = ..., channels: List[abcSnowflake] = ..., delay: Union[int, float] = ..., - ) -> asyncio.Future[Optional[List[Member]]]: + ) -> asyncio.Future[List[Member]]: ... async def scrape_guild( @@ -1745,7 +1751,7 @@ class ConnectionState: force_scraping: bool = False, channels: List[abcSnowflake] = MISSING, delay: Union[int, float] = MISSING, - ) -> Union[Optional[List[Member]], asyncio.Future[Optional[List[Member]]]]: + ) -> Union[List[Member], asyncio.Future[List[Member]]]: if not guild.me: await guild.query_members(user_ids=[self.self_id], cache=True) # type: ignore # self_id is always present here @@ -1773,18 +1779,18 @@ class ConnectionState: if wait: return await request.wait() - return request.get_future() # type: ignore # Honestly, I'm confused too + return request.get_future() @overload async def chunk_guild( self, guild: Guild, *, wait: Literal[True] = ..., channels: List[abcSnowflake] = ... - ) -> Optional[List[Member]]: + ) -> List[Member]: ... @overload async def chunk_guild( self, guild: Guild, *, wait: Literal[False] = ..., channels: List[abcSnowflake] = ... - ) -> asyncio.Future[Optional[List[Member]]]: + ) -> asyncio.Future[List[Member]]: ... async def chunk_guild( @@ -1793,7 +1799,7 @@ class ConnectionState: *, wait: bool = True, channels: List[abcSnowflake] = MISSING, - ) -> Union[asyncio.Future[Optional[List[Member]]], Optional[List[Member]]]: + ) -> Union[asyncio.Future[List[Member]], List[Member]]: if not guild.me: await guild.query_members(user_ids=[self.self_id], cache=True) # type: ignore # self_id is always present here @@ -1816,6 +1822,8 @@ class ConnectionState: await asyncio.wait_for(self.chunk_guild(guild), timeout=10) except asyncio.TimeoutError: _log.info('Somehow timed out waiting for chunks for guild %s.', guild.id) + except (ClientException, InvalidData): + pass self._queued_guilds.pop(guild.id)