Don't automatically start the client via async-with

This commit is contained in:
Lonami Exo 2021-09-18 13:30:39 +02:00
parent ba8cdc80da
commit af81899bdc
3 changed files with 60 additions and 11 deletions

View File

@ -178,6 +178,38 @@ The following modules have been moved inside ``_misc``:
// TODO review telethon/__init__.py isn't exposing more than it should // 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 Support for bot-API style file_id has been removed
-------------------------------------------------- --------------------------------------------------

View File

@ -4,6 +4,7 @@ import os
import sys import sys
import typing import typing
import warnings import warnings
import functools
from .._misc import utils, helpers, password as pwd_mod from .._misc import utils, helpers, password as pwd_mod
from .. import errors, _tl from .. import errors, _tl
@ -13,7 +14,23 @@ if typing.TYPE_CHECKING:
from .telegramclient import TelegramClient 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', self: 'TelegramClient',
phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '), phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '),
password: typing.Callable[[], str] = lambda: getpass.getpass('Please enter your password: '), 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, ' raise ValueError('Both a phone and a bot token provided, '
'must only provide one of either') 'must only provide one of either')
return await _start( return StartingClient(self, functools.partial(_start,
self=self, self=self,
phone=phone, phone=phone,
password=password, password=password,
@ -50,7 +67,7 @@ async def start(
first_name=first_name, first_name=first_name,
last_name=last_name, last_name=last_name,
max_attempts=max_attempts max_attempts=max_attempts
) ))
async def _start( async def _start(
self: 'TelegramClient', phone, password, bot_token, force_sms, self: 'TelegramClient', phone, password, bot_token, force_sms,

View File

@ -281,7 +281,7 @@ class TelegramClient:
# region Auth # region Auth
async def start( def start(
self: 'TelegramClient', self: 'TelegramClient',
phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '), phone: typing.Callable[[], str] = lambda: input('Please enter your phone (or bot token): '),
password: typing.Callable[[], str] = lambda: getpass.getpass('Please enter your password: '), 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 will be banned otherwise.** See https://telegram.org/tos
and https://core.telegram.org/api/terms. and https://core.telegram.org/api/terms.
If the event loop is already running, this method returns a Even though this method is not marked as ``async``, you still need to
coroutine that you should await on your own code; otherwise ``await`` its result for it to do anything useful.
the loop is ran until said coroutine completes.
Arguments Arguments
phone (`str` | `int` | `callable`): phone (`str` | `int` | `callable`):
@ -363,11 +362,11 @@ class TelegramClient:
# Please enter your password: ******* # Please enter your password: *******
# (You are now logged in) # (You are now logged in)
# Starting using a context manager (this calls start()): # Starting using a context manager (note the lack of await):
with client: async with client.start():
pass pass
""" """
return await auth.start(**locals()) return auth.start(**locals())
async def sign_in( async def sign_in(
self: 'TelegramClient', self: 'TelegramClient',
@ -621,7 +620,8 @@ class TelegramClient:
return await auth.edit_2fa(**locals()) return await auth.edit_2fa(**locals())
async def __aenter__(self): async def __aenter__(self):
return await self.start() await self.connect()
return self
async def __aexit__(self, *args): async def __aexit__(self, *args):
await self.disconnect() await self.disconnect()