diff --git a/telethon/client/users.py b/telethon/client/users.py index f72eac1b..c7740f9e 100644 --- a/telethon/client/users.py +++ b/telethon/client/users.py @@ -6,6 +6,7 @@ import time from .telegrambaseclient import TelegramBaseClient from .. import errors, utils from ..tl import TLObject, TLRequest, types, functions +from ..errors import MultiError, RPCError __log__ = logging.getLogger(__name__) _NOT_A_REQUEST = TypeError('You can only invoke requests, not types!') @@ -13,7 +14,8 @@ _NOT_A_REQUEST = TypeError('You can only invoke requests, not types!') class UserMethods(TelegramBaseClient): async def __call__(self, request, ordered=False): - for r in (request if utils.is_list_like(request) else (request,)): + requests = (request if utils.is_list_like(request) else (request,)) + for r in requests: if not isinstance(r, TLRequest): raise _NOT_A_REQUEST await r.resolve(self, utils) @@ -38,12 +40,22 @@ class UserMethods(TelegramBaseClient): future = self._sender.send(request, ordered=ordered) if isinstance(future, list): results = [] + exceptions = [] for f in future: - result = await f + try: + result = await f + except RPCError as e: + exceptions.append(e) + results.append(None) + continue self.session.process_entities(result) + exceptions.append(None) results.append(result) request_index += 1 - return results + if exceptions: + raise MultiError(exceptions, results, requests) + else: + return results else: result = await future self.session.process_entities(result) diff --git a/telethon/errors/__init__.py b/telethon/errors/__init__.py index 0d101eeb..e3106631 100644 --- a/telethon/errors/__init__.py +++ b/telethon/errors/__init__.py @@ -8,7 +8,7 @@ from threading import Thread from .common import ( ReadCancelledError, TypeNotFoundError, InvalidChecksumError, - BrokenAuthKeyError, SecurityError, CdnFileTamperedError + BrokenAuthKeyError, SecurityError, CdnFileTamperedError, MultiError ) # This imports the base errors too, as they're imported there diff --git a/telethon/errors/common.py b/telethon/errors/common.py index f8b479e7..b81caecc 100644 --- a/telethon/errors/common.py +++ b/telethon/errors/common.py @@ -1,4 +1,5 @@ """Errors not related to the Telegram API itself""" +from ..tl import TLRequest class ReadCancelledError(Exception): @@ -67,3 +68,29 @@ class CdnFileTamperedError(SecurityError): super().__init__( 'The CDN file has been altered and its download cancelled.' ) + + +class MultiError(Exception): + """Exception container for multiple `TLRequest`'s.""" + + def __new__(cls, exceptions, result, requests): + if len(result) != len(exceptions) != len(requests): + raise ValueError( + 'Need result, exception and request for each error') + for e, req in zip(exceptions, requests): + if not isinstance(e, BaseException): + raise TypeError( + 'Expected and exception object, not %r' % e + ) + if not isinstance(req, TLRequest): + raise TypeError( + 'Expected TLRequest object, not %r' % req + ) + + if len(exceptions) == 1: + return exceptions[0] + self = BaseException.__new__(cls) + self.exceptions = list(exceptions) + self.results = list(result) + self.requests = list(requests) + return self