Repository: alexander-akhmetov/python-telegram

Issue:
Client wait for result forever  if result update have only @type='ok'
Hello,

I play with master branch of python-telegram and found a bug. When I try to set  my first/last name then AsyncResult wait forever. It happens because Event self._ready.set() in the AsyncResult is set only if update `@type != 'ok'`.
I guess it was made for login purposes where result `@type='ok' `is not means that result is ready.

This is my code:
```...
   tg.login()

    result = tg.get_me()
    result.wait()
    print(result.update)

    logger.debug("Setting name")
    result = tg.call_method('setName', params={'first_name': 'First', 'last_name': 'Last'})
    result.wait() # there it waits forever
    print(result.update)
```

I changed the  `parse_update` method of AsyncResult as follows by adding condition `if self.id != 'updateAuthorizationState'` and it start working. 
```
    def parse_update(self, update: Dict[Any, Any]) -> None:
        if update.get('@type') == 'ok':
            self.ok_received = True
            # added following 3 lines
            if self.id != 'updateAuthorizationState':
                self._ready.set()
                return True
            return False

        if update.get('@type') == 'error':
            self.error = True
            self.error_info = update
        else:
            self.update = update

        self._ready.set()

        return True
```
But I not 100% sure that my way is correct, I just started to play with Telegram lib a day ago.. 


Discussion:

Patch:
diff --git a/telegram/utils.py b/telegram/utils.py
index 4e3100c..0f55d3b 100644
--- a/telegram/utils.py
+++ b/telegram/utils.py
@@ -1,11 +1,15 @@
 import uuid
 import threading
+import logging
 from typing import TYPE_CHECKING, Any, Dict, Optional
 
 if TYPE_CHECKING:
     from telegram.client import Telegram  # noqa  pylint: disable=cyclic-import
 
 
+logger = logging.getLogger(__name__)
+
+
 class AsyncResult:
     """
     tdlib is asynchronous, and this class helps you get results back.
@@ -41,12 +45,18 @@ class AsyncResult:
             raise RuntimeError(f'Telegram error: {self.error_info}')
 
     def parse_update(self, update: Dict[Any, Any]) -> None:
-        if update.get('@type') == 'ok':
-            self.ok_received = True
-            self._ready.set()
-            return False
+        update_type = update.get('@type')
 
-        if update.get('@type') == 'error':
+        logger.debug('update id=%s type=%s received', self.id, update_type)
+
+        if update_type == 'ok':
+            self.ok_received = True
+            if self.id == 'updateAuthorizationState':
+                # For updateAuthorizationState commands tdlib sends
+                # @type: ok responses
+                # but we want to wait longer to receive the new authorization state
+                return False
+        elif update_type == 'error':
             self.error = True
             self.error_info = update
         else:


Test patch:
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 7d9b765..f0dcef5 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -36,6 +36,7 @@ class TestAsyncResult:
         assert async_result.error_info == update
         assert async_result.update is None
         assert async_result.ok_received is False
+        assert async_result._ready.is_set() is True
 
     def test_parse_update_ok(self):
         async_result = AsyncResult(client=None)
@@ -47,6 +48,27 @@ class TestAsyncResult:
         assert async_result.error_info is None
         assert async_result.update is None
         assert async_result.ok_received is True
+        assert async_result._ready.is_set() is True
+
+    def test_parse_update_authorization_state_ok(self):
+        # when id=updateAuthorizationState
+        # and @type=ok
+        # it should not set async_result._ready
+        # because for updateAuthorizationState we want to wait for the
+        # next message with result_id=updateAuthorizationState
+        async_result = AsyncResult(
+            client=None,
+            result_id='updateAuthorizationState',
+        )
+        update = {'@type': 'ok', 'some': 'data'}
+
+        async_result.parse_update(update)
+
+        assert async_result.error is False
+        assert async_result.error_info is None
+        assert async_result.update is None
+        assert async_result.ok_received is True
+        assert async_result._ready.is_set() is False
 
     def test_parse_update(self):
         async_result = AsyncResult(client=None)
@@ -58,6 +80,7 @@ class TestAsyncResult:
         assert async_result.error_info is None
         assert async_result.update == update
         assert async_result.ok_received is False
+        assert async_result._ready.is_set() is True
 
     def test_wait_with_timeout(self):
         async_result = AsyncResult(client=None)