Get rid of client.loop

Instead, use the asyncio-intended way of implicit loop.
This commit is contained in:
Lonami Exo
2022-01-16 13:51:23 +01:00
parent 6eadc8aed8
commit a62627534e
19 changed files with 140 additions and 177 deletions

View File

@@ -132,7 +132,7 @@ class App(tkinter.Tk):
command=self.send_message).grid(row=3, column=2)
# Post-init (async, connect client)
self.cl.loop.create_task(self.post_init())
asyncio.create_task(self.post_init())
async def post_init(self):
"""
@@ -369,10 +369,4 @@ async def main(interval=0.05):
if __name__ == "__main__":
# Some boilerplate code to set up the main method
aio_loop = asyncio.get_event_loop()
try:
aio_loop.run_until_complete(main())
finally:
if not aio_loop.is_closed():
aio_loop.close()
asyncio.run(main())

View File

@@ -9,9 +9,6 @@ from telethon.errors import SessionPasswordNeededError
from telethon.network import ConnectionTcpAbridged
from telethon.utils import get_display_name
# Create a global variable to hold the loop we will be using
loop = asyncio.get_event_loop()
def sprint(string, *args, **kwargs):
"""Safe Print (handle UnicodeEncodeErrors on some terminals)"""
@@ -50,7 +47,7 @@ async def async_input(prompt):
let the loop run while we wait for input.
"""
print(prompt, end='', flush=True)
return (await loop.run_in_executor(None, sys.stdin.readline)).rstrip()
return (await asyncio.get_running_loop().run_in_executor(None, sys.stdin.readline)).rstrip()
def get_env(name, message, cast=str):
@@ -109,34 +106,34 @@ class InteractiveTelegramClient(TelegramClient):
# media known the message ID, for every message having media.
self.found_media = {}
async def init(self):
# Calling .connect() may raise a connection error False, so you need
# to except those before continuing. Otherwise you may want to retry
# as done here.
print('Connecting to Telegram servers...')
try:
loop.run_until_complete(self.connect())
await self.connect()
except IOError:
# We handle IOError and not ConnectionError because
# PySocks' errors do not subclass ConnectionError
# (so this will work with and without proxies).
print('Initial connection failed. Retrying...')
loop.run_until_complete(self.connect())
await self.connect()
# If the user hasn't called .sign_in() or .sign_up() yet, they won't
# be authorized. The first thing you must do is authorize. Calling
# .sign_in() should only be done once as the information is saved on
# the *.session file so you don't need to enter the code every time.
if not loop.run_until_complete(self.is_user_authorized()):
if not await self.is_user_authorized():
print('First run. Sending code request...')
user_phone = input('Enter your phone: ')
loop.run_until_complete(self.sign_in(user_phone))
await self.sign_in(user_phone)
self_user = None
while self_user is None:
code = input('Enter the code you just received: ')
try:
self_user =\
loop.run_until_complete(self.sign_in(code=code))
self_user = await self.sign_in(code=code)
# Two-step verification may be enabled, and .sign_in will
# raise this error. If that's the case ask for the password.
@@ -146,8 +143,7 @@ class InteractiveTelegramClient(TelegramClient):
pw = getpass('Two step verification is enabled. '
'Please enter your password: ')
self_user =\
loop.run_until_complete(self.sign_in(password=pw))
self_user = await self.sign_in(password=pw)
async def run(self):
"""Main loop of the TelegramClient, will wait for user action"""
@@ -397,9 +393,13 @@ class InteractiveTelegramClient(TelegramClient):
))
if __name__ == '__main__':
async def main():
SESSION = os.environ.get('TG_SESSION', 'interactive')
API_ID = get_env('TG_API_ID', 'Enter your API ID: ', int)
API_HASH = get_env('TG_API_HASH', 'Enter your API hash: ')
client = InteractiveTelegramClient(SESSION, API_ID, API_HASH)
loop.run_until_complete(client.run())
client = await InteractiveTelegramClient(SESSION, API_ID, API_HASH).init()
await client.run()
if __name__ == '__main__':
asyncio.run(main())

View File

@@ -7,8 +7,6 @@ import os
import time
import sys
loop = asyncio.get_event_loop()
"""
Provider token can be obtained via @BotFather. more info at https://core.telegram.org/bots/payments#getting-a-token
@@ -180,4 +178,4 @@ if __name__ == '__main__':
if not provider_token:
logger.error("No provider token supplied.")
exit(1)
loop.run_until_complete(main())
asyncio.run(main())

View File

@@ -134,12 +134,13 @@ async def main():
# By default, `Quart.run` uses `asyncio.run()`, which creates a new asyncio
# event loop. If we create the `TelegramClient` before, `telethon` will
# use `asyncio.get_event_loop()`, which is the implicit loop in the main
# thread. These two loops are different, and it won't work.
# event loop. Instead, we use `asyncio.run()` manually in order to make this
# explicit, as the client cannot be "transferred" between loops while
# connected due to the need to schedule work within an event loop.
#
# So, we have to manually pass the same `loop` to both applications to
# make 100% sure it works and to avoid headaches.
# In essence one needs to be careful to avoid mixing event loops, but this is
# simple, as `asyncio.run` is generally only used in the entry-point of the
# program.
#
# To run Quart inside `async def`, we must use `hypercorn.asyncio.serve()`
# directly.
@@ -149,4 +150,4 @@ async def main():
# won't have to worry about any of this, but it's still good to be
# explicit about the event loop.
if __name__ == '__main__':
client.loop.run_until_complete(main())
asyncio.run(main())