mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-10 19:46:36 +03:00
Update to v1.0
This commit is contained in:
parent
a1799ee74b
commit
72835dfb44
|
@ -26,7 +26,7 @@ Installing
|
|||
|
||||
.. code:: sh
|
||||
|
||||
pip3 install telethon-aio
|
||||
pip3 install telethon
|
||||
|
||||
|
||||
Creating a client
|
||||
|
|
|
@ -13,9 +13,9 @@ Magic with asyncio
|
|||
|
||||
import telethon.sync
|
||||
|
||||
At the beginning of your main script and you will be good. If you
|
||||
do use updates or events, keep reading, or use `a simpler version
|
||||
<https://github.com/LonamiWebs/Telethon/tree/sync>`_ (discouraged).
|
||||
At the beginning of your main script and you will be good. If you do use
|
||||
updates or events, keep reading, or install the latest version using
|
||||
threads and Python 3.4 support with ``pip install telethon==0.19.1.6``.
|
||||
|
||||
You might also want to check the :ref:`changelog`.
|
||||
|
||||
|
@ -120,7 +120,7 @@ way, since your event handlers will be ``async def`` too.
|
|||
|
||||
There are two exceptions. Both `client.run_until_disconnected()
|
||||
<telethon.client.updates.UpdateMethods.run_until_disconnected>` and
|
||||
`client.start() <telethon.client.updates.UpdateMethods.start>` work in
|
||||
`client.start() <telethon.client.auth.AuthMethods.start>` work in
|
||||
and outside of ``async def`` for convenience without importing the
|
||||
magic module. The rest of methods remain ``async`` unless you import it.
|
||||
|
||||
|
|
|
@ -14,6 +14,131 @@ it can take advantage of new goodies!
|
|||
.. contents:: List of All Versions
|
||||
|
||||
|
||||
Synchronous magic (v1.0)
|
||||
========================
|
||||
|
||||
.. important::
|
||||
|
||||
If you come from Telethon pre-1.0 you **really** want to read
|
||||
:ref:`asyncio-magic` to port your scripts to the new version.
|
||||
|
||||
If you're not ready for this, you can ``pip install telethon==0.19.1.6``.
|
||||
It's the latest version of the library using threads for Python 3.4+.
|
||||
|
||||
If you're interested in maintaining a Telethon version that supports
|
||||
Python 3.4 and uses threads, please open an issue and let me know.
|
||||
|
||||
The library has been around for well over a year. A lot of improvements have
|
||||
been made, a lot of user complaints have been fixed, and a lot of user desires
|
||||
have been implemented. It's time to consider the public API as stable, and
|
||||
remove some of the old methods that were around until now for compatibility
|
||||
reasons. But there's one more surprise!
|
||||
|
||||
There is a new magic ``telethon.sync`` module to let you use **all** the
|
||||
methods in the :ref:`TelegramClient <telethon-client>` (and the types returned
|
||||
from its functions) in a synchronous way, while using ``asyncio`` behind
|
||||
the scenes! This means you're now able to do both of the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
|
||||
async def main():
|
||||
await client.send_message('me', 'Hello!')
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(main())
|
||||
|
||||
# ...can be rewritten as:
|
||||
|
||||
from telethon import sync
|
||||
client.send_message('me', 'Hello!')
|
||||
|
||||
Both ways can coexist (you need to ``await`` if the loop is running).
|
||||
|
||||
You can also use the magic ``sync`` module in your own classes, and call
|
||||
``sync.syncify(cls)`` to convert all their ``async def`` into magic variants.
|
||||
|
||||
|
||||
|
||||
Breaking Changes
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
- ``message.get_fwd_sender`` is now in `message.forward
|
||||
<telethon.tl.custom.message.Message.forward>`.
|
||||
- ``client.add_update_handler`` is now `client.add_event_handler
|
||||
<telethon.client.updates.UpdateMethods.add_event_handler>`
|
||||
- ``client.remove_update_handler`` is now `client.remove_event_handler
|
||||
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
||||
- ``client.list_update_handlers`` is now `client.list_event_handlers
|
||||
<telethon.client.updates.UpdateMethods.list_event_handlers>`
|
||||
- ``client.get_message_history`` is now `client.get_messages
|
||||
<telethon.client.messages.MessageMethods.get_messages>`
|
||||
- ``client.send_voice_note`` is now `client.send_file
|
||||
<telethon.client.uploads.UploadMethods.send_file>` with ``is_voice=True``.
|
||||
- ``client.invoke()`` is now ``client(...)``.
|
||||
- ``report_errors`` has been removed since it's currently not used,
|
||||
and ``flood_sleep_threshold`` is now part of the client.
|
||||
- Methods with a lot of arguments can no longer be used without specifying
|
||||
their argument. Instead you need to use named arguments. This improves
|
||||
readability and not needing to learn the order of the arguments, which
|
||||
can also change.
|
||||
|
||||
|
||||
Additions
|
||||
~~~~~~~~~
|
||||
|
||||
- `client.send_file <telethon.client.uploads.UploadMethods.send_file>` now
|
||||
accepts external ``http://`` and ``https://`` URLs.
|
||||
- You can use the :ref:`TelegramClient <telethon-client>` inside of ``with``
|
||||
blocks, which will `client.start() <telethon.client.auth.AuthMethods.start>`
|
||||
and `disconnect() <telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`
|
||||
the client for you:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from telethon import TelegramClient, sync
|
||||
|
||||
with TelegramClient(name, api_id, api_hash) as client:
|
||||
client.send_message('me', 'Hello!')
|
||||
|
||||
Convenience at its maximum! You can even chain the `.start()
|
||||
<telethon.client.auth.AuthMethods.start>` method since
|
||||
it returns the instance of the client:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
with TelegramClient(name, api_id, api_hash).star(bot_token=token) as bot:
|
||||
bot.send_message(chat, 'Hello!')
|
||||
|
||||
|
||||
Bug fixes
|
||||
~~~~~~~~~
|
||||
|
||||
- There were some ``@property async def`` left, and some ``await property``.
|
||||
- "User joined" event was being treated as "User was invited".
|
||||
- SQLite's cursor should not be closed properly after usage.
|
||||
- ``await`` the updates task upon disconnection.
|
||||
- Some bug in Python 3.5.2's ``asyncio`` causing 100% CPU load if you
|
||||
forgot to call `client.disconnect()
|
||||
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnect>`.
|
||||
The method is called for you on object destruction, but you still should
|
||||
disconnect manually or use a ``with`` block.
|
||||
- Some fixes regarding disconnecting on client deletion and properly
|
||||
saving the authorization key.
|
||||
- Passing a class to `message.get_entities_text
|
||||
<telethon.tl.custom.message.Message.get_entities_text>` now works properly.
|
||||
- Iterating messages from a specific user in private messages now works.
|
||||
|
||||
Enhancements
|
||||
~~~~~~~~~~~~
|
||||
|
||||
- Both `client.start() <telethon.client.auth.AuthMethods.start>` and
|
||||
`client.run_until_disconnected()
|
||||
<telethon.client.updates.UpdateMethods.run_until_disconnected>` can
|
||||
be ran in both a synchronous way (without starting the loop manually)
|
||||
or from an ``async def`` where they need to have an ``await``.
|
||||
|
||||
|
||||
Core Rewrite in asyncio (v1.0-rc1)
|
||||
==================================
|
||||
|
||||
|
|
4
setup.py
4
setup.py
|
@ -183,7 +183,7 @@ def main():
|
|||
version = re.search(r"^__version__\s*=\s*'(.*)'.*$",
|
||||
f.read(), flags=re.MULTILINE).group(1)
|
||||
setup(
|
||||
name='Telethon-aio',
|
||||
name='Telethon',
|
||||
version=version,
|
||||
description="Full-featured Telegram client library for Python 3",
|
||||
long_description=long_description,
|
||||
|
@ -206,7 +206,7 @@ def main():
|
|||
# 3 - Alpha
|
||||
# 4 - Beta
|
||||
# 5 - Production/Stable
|
||||
'Development Status :: 3 - Alpha',
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
|
||||
'Intended Audience :: Developers',
|
||||
'Topic :: Communications :: Chat',
|
||||
|
|
|
@ -17,6 +17,7 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
|||
self,
|
||||
phone=lambda: input('Please enter your phone: '),
|
||||
password=lambda: getpass.getpass('Please enter your password: '),
|
||||
*,
|
||||
bot_token=None, force_sms=False, code_callback=None,
|
||||
first_name='New User', last_name='', max_attempts=3):
|
||||
"""
|
||||
|
@ -193,7 +194,7 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
|||
return self
|
||||
|
||||
async def sign_in(
|
||||
self, phone=None, code=None, password=None,
|
||||
self, phone=None, *, code=None, password=None,
|
||||
bot_token=None, phone_code_hash=None):
|
||||
"""
|
||||
Starts or completes the sign in process with the given phone number
|
||||
|
@ -325,7 +326,7 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
|||
self._authorized = True
|
||||
return result.user
|
||||
|
||||
async def send_code_request(self, phone, force_sms=False):
|
||||
async def send_code_request(self, phone, *, force_sms=False):
|
||||
"""
|
||||
Sends a code request to the specified phone number.
|
||||
|
||||
|
@ -382,8 +383,8 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
|||
return True
|
||||
|
||||
async def edit_2fa(
|
||||
self, current_password=None, new_password=None, hint='',
|
||||
email=None):
|
||||
self, current_password=None, new_password=None,
|
||||
*, hint='', email=None):
|
||||
"""
|
||||
Changes the 2FA settings of the logged in user, according to the
|
||||
passed parameters. Take note of the parameter explanations.
|
||||
|
|
|
@ -13,7 +13,7 @@ class ChatMethods(UserMethods):
|
|||
|
||||
@async_generator
|
||||
async def iter_participants(
|
||||
self, entity, limit=None, search='',
|
||||
self, entity, limit=None, *, search='',
|
||||
filter=None, aggressive=False, _total=None):
|
||||
"""
|
||||
Iterator over the participants belonging to the specified chat.
|
||||
|
|
|
@ -14,7 +14,7 @@ class DialogMethods(UserMethods):
|
|||
|
||||
@async_generator
|
||||
async def iter_dialogs(
|
||||
self, limit=None, offset_date=None, offset_id=0,
|
||||
self, limit=None, *, offset_date=None, offset_id=0,
|
||||
offset_peer=types.InputPeerEmpty(), ignore_migrated=False,
|
||||
_total=None):
|
||||
"""
|
||||
|
|
|
@ -16,7 +16,7 @@ class DownloadMethods(UserMethods):
|
|||
# region Public methods
|
||||
|
||||
async def download_profile_photo(
|
||||
self, entity, file=None, download_big=True):
|
||||
self, entity, file=None, *, download_big=True):
|
||||
"""
|
||||
Downloads the profile photo of the given entity (user/chat/channel).
|
||||
|
||||
|
@ -91,7 +91,8 @@ class DownloadMethods(UserMethods):
|
|||
# Until there's a report for chats, no need to.
|
||||
return None
|
||||
|
||||
async def download_media(self, message, file=None, progress_callback=None):
|
||||
async def download_media(self, message, file=None,
|
||||
*, progress_callback=None):
|
||||
"""
|
||||
Downloads the given media, or the media from a specified Message.
|
||||
|
||||
|
@ -141,7 +142,7 @@ class DownloadMethods(UserMethods):
|
|||
)
|
||||
|
||||
async def download_file(
|
||||
self, input_location, file=None, part_size_kb=None,
|
||||
self, input_location, file=None, *, part_size_kb=None,
|
||||
file_size=None, progress_callback=None):
|
||||
"""
|
||||
Downloads the given input location to a file.
|
||||
|
|
|
@ -22,7 +22,7 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
|
||||
@async_generator
|
||||
async def iter_messages(
|
||||
self, entity, limit=None, offset_date=None, offset_id=0,
|
||||
self, entity, limit=None, *, offset_date=None, offset_id=0,
|
||||
max_id=0, min_id=0, add_offset=0, search=None, filter=None,
|
||||
from_user=None, batch_size=100, wait_time=None, ids=None,
|
||||
_total=None):
|
||||
|
@ -285,7 +285,7 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
# region Message sending/editing/deleting
|
||||
|
||||
async def send_message(
|
||||
self, entity, message='', reply_to=None,
|
||||
self, entity, message='', *, reply_to=None,
|
||||
parse_mode=utils.Default, link_preview=True, file=None,
|
||||
force_document=False, clear_draft=False):
|
||||
"""
|
||||
|
@ -403,7 +403,7 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
|
||||
return self._get_response_message(request, result, entity)
|
||||
|
||||
async def forward_messages(self, entity, messages, from_peer=None):
|
||||
async def forward_messages(self, entity, messages, *, from_peer=None):
|
||||
"""
|
||||
Forwards the given message(s) to the specified entity.
|
||||
|
||||
|
@ -469,8 +469,8 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
return result[0] if single else result
|
||||
|
||||
async def edit_message(
|
||||
self, entity, message=None, text=None, parse_mode=utils.Default,
|
||||
link_preview=True, file=None):
|
||||
self, entity, message=None, text=None,
|
||||
*, parse_mode=utils.Default, link_preview=True, file=None):
|
||||
"""
|
||||
Edits the given message ID (to change its contents or disable preview).
|
||||
|
||||
|
@ -542,7 +542,7 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
self._cache_media(msg, file, file_handle)
|
||||
return msg
|
||||
|
||||
async def delete_messages(self, entity, message_ids, revoke=True):
|
||||
async def delete_messages(self, entity, message_ids, *, revoke=True):
|
||||
"""
|
||||
Deletes a message from a chat, optionally "for everyone".
|
||||
|
||||
|
@ -586,8 +586,8 @@ class MessageMethods(UploadMethods, MessageParseMethods):
|
|||
|
||||
# region Miscellaneous
|
||||
|
||||
async def send_read_acknowledge(self, entity, message=None, max_id=None,
|
||||
clear_mentions=False):
|
||||
async def send_read_acknowledge(
|
||||
self, entity, message=None, *, max_id=None, clear_mentions=False):
|
||||
"""
|
||||
Sends a "read acknowledge" (i.e., notifying the given peer that we've
|
||||
read their messages, also known as the "double check").
|
||||
|
|
|
@ -27,7 +27,7 @@ class UploadMethods(MessageParseMethods, UserMethods):
|
|||
# region Public methods
|
||||
|
||||
async def send_file(
|
||||
self, entity, file, caption='', force_document=False,
|
||||
self, entity, file, *, caption='', force_document=False,
|
||||
progress_callback=None, reply_to=None, attributes=None,
|
||||
thumb=None, allow_cache=True, parse_mode=utils.Default,
|
||||
voice_note=False, video_note=False, **kwargs):
|
||||
|
@ -221,7 +221,7 @@ class UploadMethods(MessageParseMethods, UserMethods):
|
|||
]
|
||||
|
||||
async def upload_file(
|
||||
self, file, part_size_kb=None, file_name=None, use_cache=None,
|
||||
self, file, *, part_size_kb=None, file_name=None, use_cache=None,
|
||||
progress_callback=None):
|
||||
"""
|
||||
Uploads the specified file and returns a handle (an instance of
|
||||
|
|
|
@ -14,7 +14,7 @@ class MessageRead(EventBuilder):
|
|||
messages the event will be fired. By default (``False``) only
|
||||
when messages you sent are read by someone else will fire it.
|
||||
"""
|
||||
def __init__(self, inbox=False, chats=None, blacklist_chats=None):
|
||||
def __init__(self, chats=None, *, blacklist_chats=None, inbox=False):
|
||||
super().__init__(chats, blacklist_chats)
|
||||
self.inbox = inbox
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class UserUpdate(EventBuilder):
|
|||
contact (`bool`):
|
||||
``True`` if what's being uploaded (selected) is a contact.
|
||||
"""
|
||||
def __init__(self, user_id, status=None, typing=None):
|
||||
def __init__(self, user_id, *, status=None, typing=None):
|
||||
super().__init__(types.PeerUser(user_id))
|
||||
|
||||
self.online = None if status is None else \
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Versions should comply with PEP440.
|
||||
# This line is parsed in setup.py:
|
||||
__version__ = '1.0-rc1'
|
||||
__version__ = '1.0'
|
||||
|
|
Loading…
Reference in New Issue
Block a user