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
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
--------------------------------------------------

View File

@ -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,

View File

@ -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()