.. _compatibility-and-convenience: ============================= Compatibility and Convenience ============================= Telethon is an ``asyncio`` library. Compatibility is an important concern, and while it can't always be kept and mistakes happens, the :ref:`changelog` is there to tell you when these important changes happen. .. contents:: Compatibility ************* Some decisions when developing will inevitable be proven wrong in the future. One of these decisions was using threads. Now that Python 3.4 is reaching EOL and using ``asyncio`` is usable as of Python 3.5 it makes sense for a library like Telethon to make a good use of it. If you have old code, **just use old versions** of the library! There is nothing wrong with that other than not getting new updates or fixes, but using a fixed version with ``pip install telethon==0.19.1.6`` is easy enough to do. You might want to consider using `Virtual Environments `_ in your projects. There's no point in maintaining a synchronous version because the whole point is that people don't have time to upgrade, and there has been several changes and clean-ups. Using an older version is the right way to go. Sometimes, other small decisions are made. These all will be reflected in the :ref:`changelog` which you should read when upgrading. If you want to jump the ``asyncio`` boat, here are some of the things you will need to start migrating really old code: .. code-block:: python # 1. Import the client from telethon.sync from telethon.sync import TelegramClient # 2. Change this monster... try: assert client.connect() if not client.is_user_authorized(): client.send_code_request(phone_number) me = client.sign_in(phone_number, input('Enter code: ')) ... # REST OF YOUR CODE finally: client.disconnect() # ...for this: with client: ... # REST OF YOUR CODE # 3. client.idle() no longer exists. # Change this... client.idle() # ...to this: client.run_until_disconnected() # 4. client.add_update_handler no longer exists. # Change this... client.add_update_handler(handler) # ...to this: client.add_event_handler(handler) In addition, all the update handlers must be ``async def``, and you need to ``await`` method calls that rely on network requests, such as getting the chat or sender. If you don't use updates, you're done! Convenience *********** .. note:: The entire documentation assumes you have done one of the following: .. code-block:: python from telethon import TelegramClient, sync # or from telethon.sync import TelegramClient This makes the examples shorter and easier to think about. For quick scripts that don't need updates, it's a lot more convenient to forget about ``asyncio`` and just work with sequential code. This can prove to be a powerful hybrid for running under the Python REPL too. .. code-block:: python from telethon.sync import TelegramClient # ^~~~~ note this part; it will manage the asyncio loop for you with TelegramClient(...) as client: print(client.get_me().username) # ^ notice the lack of await, or loop.run_until_complete(). # Since there is no loop running, this is done behind the scenes. # message = client.send_message('me', 'Hi!') import time time.sleep(5) message.delete() # You can also have an hybrid between a synchronous # part and asynchronous event handlers. # from telethon import events @client.on(events.NewMessage(pattern='(?i)hi|hello')) async def handler(event): await event.reply('hey') client.run_until_disconnected() Some methods, such as ``with``, ``start``, ``disconnect`` and ``run_until_disconnected`` work both in synchronous and asynchronous contexts by default for convenience, and to avoid the little overhead it has when using methods like sending a message, getting messages, etc. This keeps the best of both worlds as a sane default. .. note:: As a rule of thumb, if you're inside an ``async def`` and you need the client, you need to ``await`` calls to the API. If you call other functions that also need API calls, make them ``async def`` and ``await`` them too. Otherwise, there is no need to do so with this mode. Speed ***** When you're ready to micro-optimize your application, or if you simply don't need to call any non-basic methods from a synchronous context, just get rid of ``telethon.sync`` and work inside an ``async def``: .. code-block:: python import asyncio from telethon import TelegramClient, events async def main(): async with TelegramClient(...) as client: print((await client.get_me()).username) # ^_____________________^ notice these parenthesis # You want to ``await`` the call, not the username. # message = await client.send_message('me', 'Hi!') await asyncio.sleep(5) await message.delete() @client.on(events.NewMessage(pattern='(?i)hi|hello')) async def handler(event): await event.reply('hey') await client.run_until_disconnected() loop = asyncio.get_event_loop() loop.run_until_complete(main()) The ``telethon.sync`` magic module simply wraps every method behind: .. code-block:: python loop = asyncio.get_event_loop() loop.run_until_complete(main()) So that you don't have to write it yourself every time. That's the overhead you pay if you import it, and what you save if you don't. Learning ******** You know the library uses ``asyncio`` everywhere, and you want to learn how to do things right. Even though ``asyncio`` is its own topic, the documentation wants you to learn how to use Telethon correctly, and for that, you need to use ``asyncio`` correctly too. For this reason, there is a section called :ref:`mastering-asyncio` that will introduce you to the ``asyncio`` world, with links to more resources for learning how to use it. Feel free to check that section out once you have read the rest.