From af81899bdc206596a9492df893e97255c918d0fb Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sat, 18 Sep 2021 13:30:39 +0200 Subject: [PATCH] Don't automatically start the client via async-with --- readthedocs/misc/v2-migration-guide.rst | 32 +++++++++++++++++++++++++ telethon/_client/auth.py | 23 +++++++++++++++--- telethon/_client/telegramclient.py | 16 ++++++------- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/readthedocs/misc/v2-migration-guide.rst b/readthedocs/misc/v2-migration-guide.rst index 514aa8b8..8c014498 100644 --- a/readthedocs/misc/v2-migration-guide.rst +++ b/readthedocs/misc/v2-migration-guide.rst @@ -178,6 +178,38 @@ The following modules have been moved inside ``_misc``: // TODO review telethon/__init__.py isn't exposing more than it should +Using the client in a context-manager no longer calls start automatically +------------------------------------------------------------------------- + + +The following code no longer automatically calls ``client.start()``: + +.. code-block:: python + + async with TelegramClient(...) as client: + ... + + # or + + async with client: + ... + + +This means the context-manager will only call ``client.connect()`` and ``client.disconnect()``. +The rationale for this change is that it could be strange for this to ask for the login code if +the session ever was invalid. If you want the old behaviour, you now need to be explicit: + + +.. code-block:: python + + async with TelegramClient(...).start() as client: + ... # ++++++++ + + +Note that you do not need to ``await`` the call to ``.start()`` if you are going to use the result +in a context-manager (but it's okay if you put the ``await``). + + Support for bot-API style file_id has been removed -------------------------------------------------- diff --git a/telethon/_client/auth.py b/telethon/_client/auth.py index 992d44e1..27ef4767 100644 --- a/telethon/_client/auth.py +++ b/telethon/_client/auth.py @@ -4,6 +4,7 @@ import os import sys import typing import warnings +import functools from .._misc import utils, helpers, password as pwd_mod from .. import errors, _tl @@ -13,7 +14,23 @@ if typing.TYPE_CHECKING: from .telegramclient import TelegramClient -async def start( +class StartingClient: + def __init__(self, client, start_fn): + self.client = client + self.start_fn = start_fn + + async def __aenter__(self): + await self.start_fn() + return self.client + + async def __aexit__(self, *args): + await self.client.__aexit__(*args) + + def __await__(self): + return self.__aenter__().__await__() + + +def start( self: 'TelegramClient', phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '), password: typing.Callable[[], str] = lambda: getpass.getpass('Please enter your password: '), @@ -40,7 +57,7 @@ async def start( raise ValueError('Both a phone and a bot token provided, ' 'must only provide one of either') - return await _start( + return StartingClient(self, functools.partial(_start, self=self, phone=phone, password=password, @@ -50,7 +67,7 @@ async def start( first_name=first_name, last_name=last_name, max_attempts=max_attempts - ) + )) async def _start( self: 'TelegramClient', phone, password, bot_token, force_sms, diff --git a/telethon/_client/telegramclient.py b/telethon/_client/telegramclient.py index b83369e9..b1c07a35 100644 --- a/telethon/_client/telegramclient.py +++ b/telethon/_client/telegramclient.py @@ -281,7 +281,7 @@ class TelegramClient: # region Auth - async def start( + def start( self: 'TelegramClient', phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '), password: typing.Callable[[], str] = lambda: getpass.getpass('Please enter your password: '), @@ -304,9 +304,8 @@ class TelegramClient: will be banned otherwise.** See https://telegram.org/tos and https://core.telegram.org/api/terms. - If the event loop is already running, this method returns a - coroutine that you should await on your own code; otherwise - the loop is ran until said coroutine completes. + Even though this method is not marked as ``async``, you still need to + ``await`` its result for it to do anything useful. Arguments phone (`str` | `int` | `callable`): @@ -363,11 +362,11 @@ class TelegramClient: # Please enter your password: ******* # (You are now logged in) - # Starting using a context manager (this calls start()): - with client: + # Starting using a context manager (note the lack of await): + async with client.start(): pass """ - return await auth.start(**locals()) + return auth.start(**locals()) async def sign_in( self: 'TelegramClient', @@ -621,7 +620,8 @@ class TelegramClient: return await auth.edit_2fa(**locals()) async def __aenter__(self): - return await self.start() + await self.connect() + return self async def __aexit__(self, *args): await self.disconnect()