From e2e7e631b524e7e438a9e5331acfaa112fb1c727 Mon Sep 17 00:00:00 2001
From: Lonami Exo <totufals@hotmail.com>
Date: Wed, 9 May 2018 10:19:45 +0200
Subject: [PATCH] Stop using *args when invoking many requests at once

---
 telethon/network/mtproto_sender.py | 11 +++--
 telethon/telegram_bare_client.py   | 66 +++++++++++++++++++-----------
 telethon/telegram_client.py        |  5 +--
 3 files changed, 49 insertions(+), 33 deletions(-)

diff --git a/telethon/network/mtproto_sender.py b/telethon/network/mtproto_sender.py
index b146a4e0..9616e5cc 100644
--- a/telethon/network/mtproto_sender.py
+++ b/telethon/network/mtproto_sender.py
@@ -5,7 +5,7 @@ encrypting every packet, and relies on a valid AuthKey in the used Session.
 import logging
 from threading import Lock
 
-from .. import helpers as utils
+from .. import helpers, utils
 from ..errors import (
     BadMessageError, InvalidChecksumError, BrokenAuthKeyError,
     rpc_message_to_error
@@ -84,7 +84,7 @@ class MtProtoSender:
 
     # region Send and receive
 
-    def send(self, *requests, ordered=False):
+    def send(self, requests, ordered=False):
         """
         Sends the specified TLObject(s) (which must be requests),
         and acknowledging any message which needed confirmation.
@@ -94,6 +94,9 @@ class MtProtoSender:
                         order in which they appear or they can be executed
                         in arbitrary order in the server.
         """
+        if not utils.is_list_like(requests):
+            requests = (requests,)
+
         if ordered:
             requests = iter(requests)
             messages = [TLMessage(self.session, next(requests))]
@@ -184,7 +187,7 @@ class MtProtoSender:
         :param message: the TLMessage to be sent.
         """
         with self._send_lock:
-            self.connection.send(utils.pack_message(self.session, message))
+            self.connection.send(helpers.pack_message(self.session, message))
 
     def _decode_msg(self, body):
         """
@@ -200,7 +203,7 @@ class MtProtoSender:
                 raise BufferError("Can't decode packet ({})".format(body))
 
         with BinaryReader(body) as reader:
-            return utils.unpack_message(self.session, reader)
+            return helpers.unpack_message(self.session, reader)
 
     def _process_msg(self, msg_id, sequence, reader, state):
         """
diff --git a/telethon/telegram_bare_client.py b/telethon/telegram_bare_client.py
index c343dbe4..0c27d050 100644
--- a/telethon/telegram_bare_client.py
+++ b/telethon/telegram_bare_client.py
@@ -429,32 +429,51 @@ class TelegramBareClient:
 
     # region Invoking Telegram requests
 
-    def __call__(self, *requests, retries=5, ordered=False):
-        """Invokes (sends) a MTProtoRequest and returns (receives) its result.
-
-           The invoke will be retried up to 'retries' times before raising
-           RuntimeError().
-
-           If more than one request is given and ordered is True, then the
-           requests will be invoked sequentially in the server (useful for
-           bursts of requests that need to be ordered).
+    def __call__(self, request, retries=5, ordered=False):
         """
+        Invokes (sends) one or more MTProtoRequests and returns (receives)
+        their result.
+
+        Args:
+            request (`TLObject` | `list`):
+                The request or requests to be invoked.
+
+            retries (`bool`, optional):
+                How many times the request should be retried automatically
+                in case it fails with a non-RPC error.
+
+               The invoke will be retried up to 'retries' times before raising
+               ``RuntimeError``.
+
+            ordered (`bool`, optional):
+                Whether the requests (if more than one was given) should be
+                executed sequentially on the server. They run in arbitrary
+                order by default.
+
+        Returns:
+            The result of the request (often a `TLObject`) or a list of
+            results if more than one request was given.
+        """
+        single = not utils.is_list_like(request)
+        if single:
+            request = (request,)
+
         if not all(isinstance(x, TLObject) and
-                   x.content_related for x in requests):
+                   x.content_related for x in request):
             raise TypeError('You can only invoke requests, not types!')
 
         if self._background_error:
             raise self._background_error
 
-        for request in requests:
-            request.resolve(self, utils)
+        for r in request:
+            r.resolve(self, utils)
 
         # For logging purposes
-        if len(requests) == 1:
-            which = type(requests[0]).__name__
+        if single:
+            which = type(request[0]).__name__
         else:
             which = '{} requests ({})'.format(
-                len(requests), [type(x).__name__ for x in requests])
+                len(request), [type(x).__name__ for x in request])
 
         # Determine the sender to be used (main or a new connection)
         __log__.debug('Invoking %s', which)
@@ -462,13 +481,13 @@ class TelegramBareClient:
             not self._idling.is_set() or self._reconnect_lock.locked()
 
         for retry in range(retries):
-            result = self._invoke(call_receive, *requests, ordered=ordered)
+            result = self._invoke(call_receive, request, ordered=ordered)
             if result is not None:
-                return result
+                return result[0] if single else result
 
             log = __log__.info if retry == 0 else __log__.warning
             log('Invoking %s failed %d times, connecting again and retrying',
-                [str(x) for x in requests], retry + 1)
+                which, retry + 1)
 
             sleep(1)
             # The ReadThread has priority when attempting reconnection,
@@ -479,13 +498,13 @@ class TelegramBareClient:
                     self._reconnect()
 
         raise RuntimeError('Number of retries reached 0 for {}.'.format(
-            [type(x).__name__ for x in requests]
+            which
         ))
 
     # Let people use client.invoke(SomeRequest()) instead client(...)
     invoke = __call__
 
-    def _invoke(self, call_receive, *requests, ordered=False):
+    def _invoke(self, call_receive, requests, ordered=False):
         try:
             # Ensure that we start with no previous errors (i.e. resending)
             for x in requests:
@@ -510,7 +529,7 @@ class TelegramBareClient:
                         self._wrap_init_connection(GetConfigRequest())
                     )
 
-            self._sender.send(*requests, ordered=ordered)
+            self._sender.send(requests, ordered=ordered)
 
             if not call_receive:
                 # TODO This will be slightly troublesome if we allow
@@ -566,10 +585,7 @@ class TelegramBareClient:
                 # rejected by the other party as a whole."
                 return None
 
-            if len(requests) == 1:
-                return requests[0].result
-            else:
-                return [x.result for x in requests]
+            return [x.result for x in requests]
 
         except (PhoneMigrateError, NetworkMigrateError,
                 UserMigrateError) as e:
diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py
index fb2a75d8..841b6fb7 100644
--- a/telethon/telegram_client.py
+++ b/telethon/telegram_client.py
@@ -1367,10 +1367,7 @@ class TelegramClient(TelegramBareClient):
                 if requests[0].offset > limit:
                     break
 
-                if len(requests) == 1:
-                    results = (self(requests[0]),)
-                else:
-                    results = self(*requests)
+                results = self(requests)
                 for i in reversed(range(len(requests))):
                     participants = results[i]
                     if not participants.users: