diff --git a/telethon/_client/downloads.py b/telethon/_client/downloads.py index 4500df33..aa8ed59a 100644 --- a/telethon/_client/downloads.py +++ b/telethon/_client/downloads.py @@ -195,43 +195,6 @@ async def download_profile_photo( file: 'hints.FileLike' = None, *, download_big: bool = True) -> typing.Optional[str]: - """ - Downloads the profile photo from the given user, chat or channel. - - Arguments - entity (`entity`): - From who the photo will be downloaded. - - .. note:: - - This method expects the full entity (which has the data - to download the photo), not an input variant. - - It's possible that sometimes you can't fetch the entity - from its input (since you can get errors like - ``ChannelPrivateError``) but you already have it through - another call, like getting a forwarded message from it. - - file (`str` | `file`, optional): - The output file path, directory, or stream-like object. - If the path exists and is a file, it will be overwritten. - If file is the type `bytes`, it will be downloaded in-memory - as a bytestring (e.g. ``file=bytes``). - - download_big (`bool`, optional): - Whether to use the big version of the available photos. - - Returns - `None` if no photo was provided, or if it was Empty. On success - the file path is returned since it may differ from the one given. - - Example - .. code-block:: python - - # Download your own profile photo - path = await client.download_profile_photo('me') - print(path) - """ # hex(crc32(x.encode('ascii'))) for x in # ('User', 'Chat', 'UserFull', 'ChatFull') ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697) @@ -307,73 +270,6 @@ async def download_media( *, thumb: 'typing.Union[int, types.TypePhotoSize]' = None, progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]: - """ - Downloads the given media from a message object. - - Note that if the download is too slow, you should consider installing - ``cryptg`` (through ``pip install cryptg``) so that decrypting the - received data is done in C instead of Python (much faster). - - See also `Message.download_media() `. - - Arguments - message (`Message ` | :tl:`Media`): - The media or message containing the media that will be downloaded. - - file (`str` | `file`, optional): - The output file path, directory, or stream-like object. - If the path exists and is a file, it will be overwritten. - If file is the type `bytes`, it will be downloaded in-memory - as a bytestring (e.g. ``file=bytes``). - - progress_callback (`callable`, optional): - A callback function accepting two parameters: - ``(received bytes, total)``. - - thumb (`int` | :tl:`PhotoSize`, optional): - Which thumbnail size from the document or photo to download, - instead of downloading the document or photo itself. - - If it's specified but the file does not have a thumbnail, - this method will return `None`. - - The parameter should be an integer index between ``0`` and - ``len(sizes)``. ``0`` will download the smallest thumbnail, - and ``len(sizes) - 1`` will download the largest thumbnail. - You can also use negative indices, which work the same as - they do in Python's `list`. - - You can also pass the :tl:`PhotoSize` instance to use. - Alternatively, the thumb size type `str` may be used. - - In short, use ``thumb=0`` if you want the smallest thumbnail - and ``thumb=-1`` if you want the largest thumbnail. - - .. note:: - The largest thumbnail may be a video instead of a photo, - as they are available since layer 116 and are bigger than - any of the photos. - - Returns - `None` if no media was provided, or if it was Empty. On success - the file path is returned since it may differ from the one given. - - Example - .. code-block:: python - - path = await client.download_media(message) - await client.download_media(message, filename) - # or - path = await message.download_media() - await message.download_media(filename) - - # Printing download progress - def callback(current, total): - print('Downloaded', current, 'out of', total, - 'bytes: {:.2%}'.format(current / total)) - - await client.download_media(message, progress_callback=callback) - """ # Downloading large documents may be slow enough to require a new file reference # to be obtained mid-download. Store (input chat, message id) so that the message # can be re-fetched. @@ -428,58 +324,6 @@ async def download_file( dc_id: int = None, key: bytes = None, iv: bytes = None) -> typing.Optional[bytes]: - """ - Low-level method to download files from their input location. - - .. note:: - - Generally, you should instead use `download_media`. - This method is intended to be a bit more low-level. - - Arguments - input_location (:tl:`InputFileLocation`): - The file location from which the file will be downloaded. - See `telethon.utils.get_input_location` source for a complete - list of supported types. - - file (`str` | `file`, optional): - The output file path, directory, or stream-like object. - If the path exists and is a file, it will be overwritten. - - If the file path is `None` or `bytes`, then the result - will be saved in memory and returned as `bytes`. - - part_size_kb (`int`, optional): - Chunk size when downloading files. The larger, the less - requests will be made (up to 512KB maximum). - - file_size (`int`, optional): - The file size that is about to be downloaded, if known. - Only used if ``progress_callback`` is specified. - - progress_callback (`callable`, optional): - A callback function accepting two parameters: - ``(downloaded bytes, total)``. Note that the - ``total`` is the provided ``file_size``. - - dc_id (`int`, optional): - The data center the library should connect to in order - to download the file. You shouldn't worry about this. - - key ('bytes', optional): - In case of an encrypted upload (secret chats) a key is supplied - - iv ('bytes', optional): - In case of an encrypted upload (secret chats) an iv is supplied - - - Example - .. code-block:: python - - # Download a file and print its header - data = await client.download_file(input_file, bytes) - print(data[:16]) - """ return await self._download_file( input_location, file, @@ -563,89 +407,6 @@ def iter_download( file_size: int = None, dc_id: int = None ): - """ - Iterates over a file download, yielding chunks of the file. - - This method can be used to stream files in a more convenient - way, since it offers more control (pausing, resuming, etc.) - - .. note:: - - Using a value for `offset` or `stride` which is not a multiple - of the minimum allowed `request_size`, or if `chunk_size` is - different from `request_size`, the library will need to do a - bit more work to fetch the data in the way you intend it to. - - You normally shouldn't worry about this. - - Arguments - file (`hints.FileLike`): - The file of which contents you want to iterate over. - - offset (`int`, optional): - The offset in bytes into the file from where the - download should start. For example, if a file is - 1024KB long and you just want the last 512KB, you - would use ``offset=512 * 1024``. - - stride (`int`, optional): - The stride of each chunk (how much the offset should - advance between reading each chunk). This parameter - should only be used for more advanced use cases. - - It must be bigger than or equal to the `chunk_size`. - - limit (`int`, optional): - The limit for how many *chunks* will be yielded at most. - - chunk_size (`int`, optional): - The maximum size of the chunks that will be yielded. - Note that the last chunk may be less than this value. - By default, it equals to `request_size`. - - request_size (`int`, optional): - How many bytes will be requested to Telegram when more - data is required. By default, as many bytes as possible - are requested. If you would like to request data in - smaller sizes, adjust this parameter. - - Note that values outside the valid range will be clamped, - and the final value will also be a multiple of the minimum - allowed size. - - file_size (`int`, optional): - If the file size is known beforehand, you should set - this parameter to said value. Depending on the type of - the input file passed, this may be set automatically. - - dc_id (`int`, optional): - The data center the library should connect to in order - to download the file. You shouldn't worry about this. - - Yields - - `bytes` objects representing the chunks of the file if the - right conditions are met, or `memoryview` objects instead. - - Example - .. code-block:: python - - # Streaming `media` to an output file - # After the iteration ends, the sender is cleaned up - with open('photo.jpg', 'wb') as fd: - async for chunk in client.iter_download(media): - fd.write(chunk) - - # Fetching only the header of a file (32 bytes) - # You should manually close the iterator in this case. - # - # "stream" is a common name for asynchronous generators, - # and iter_download will yield `bytes` (chunks of the file). - stream = client.iter_download(media, request_size=32) - header = await stream.__anext__() # "manual" version of `async for` - await stream.close() - assert len(header) == 32 - """ return self._iter_download( file, offset=offset, diff --git a/telethon/_client/messageparse.py b/telethon/_client/messageparse.py index 72b121a9..0cbdb40c 100644 --- a/telethon/_client/messageparse.py +++ b/telethon/_client/messageparse.py @@ -10,38 +10,6 @@ if typing.TYPE_CHECKING: def get_parse_mode(self: 'TelegramClient'): - """ - This property is the default parse mode used when sending messages. - Defaults to `telethon.extensions.markdown`. It will always - be either `None` or an object with ``parse`` and ``unparse`` - methods. - - When setting a different value it should be one of: - - * Object with ``parse`` and ``unparse`` methods. - * A ``callable`` to act as the parse method. - * A `str` indicating the ``parse_mode``. For Markdown ``'md'`` - or ``'markdown'`` may be used. For HTML, ``'htm'`` or ``'html'`` - may be used. - - The ``parse`` method should be a function accepting a single - parameter, the text to parse, and returning a tuple consisting - of ``(parsed message str, [MessageEntity instances])``. - - The ``unparse`` method should be the inverse of ``parse`` such - that ``assert text == unparse(*parse(text))``. - - See :tl:`MessageEntity` for allowed message entities. - - Example - .. code-block:: python - - # Disabling default formatting - client.parse_mode = None - - # Enabling HTML as the default format - client.parse_mode = 'html' - """ return self._parse_mode def set_parse_mode(self: 'TelegramClient', mode: str): diff --git a/telethon/_client/updates.py b/telethon/_client/updates.py index c5d04ade..89816530 100644 --- a/telethon/_client/updates.py +++ b/telethon/_client/updates.py @@ -30,74 +30,14 @@ async def _run_until_disconnected(self: 'TelegramClient'): await self.disconnect() async def set_receive_updates(self: 'TelegramClient', receive_updates): - """ - Change the value of `receive_updates`. - - This is an `async` method, because in order for Telegram to start - sending updates again, a request must be made. - """ self._no_updates = not receive_updates if receive_updates: await self(functions.updates.GetStateRequest()) async def run_until_disconnected(self: 'TelegramClient'): - """ - Runs the event loop until the library is disconnected. - - It also notifies Telegram that we want to receive updates - as described in https://core.telegram.org/api/updates. - - Manual disconnections can be made by calling `disconnect() - ` - or sending a ``KeyboardInterrupt`` (e.g. by pressing ``Ctrl+C`` on - the console window running the script). - - If a disconnection error occurs (i.e. the library fails to reconnect - automatically), said error will be raised through here, so you have a - chance to ``except`` it on your own code. - - If the loop is already running, this method returns a coroutine - that you should await on your own code. - - .. note:: - - If you want to handle ``KeyboardInterrupt`` in your code, - simply run the event loop in your code too in any way, such as - ``loop.run_forever()`` or ``await client.disconnected`` (e.g. - ``loop.run_until_complete(client.disconnected)``). - - Example - .. code-block:: python - - # Blocks the current task here until a disconnection occurs. - # - # You will still receive updates, since this prevents the - # script from exiting. - await client.run_until_disconnected() - """ return await self._run_until_disconnected() def on(self: 'TelegramClient', event: EventBuilder): - """ - Decorator used to `add_event_handler` more conveniently. - - - Arguments - event (`_EventBuilder` | `type`): - The event builder class or instance to be used, - for instance ``events.NewMessage``. - - Example - .. code-block:: python - - from telethon import TelegramClient, events - client = TelegramClient(...) - - # Here we use client.on - @client.on(events.NewMessage) - async def handler(event): - ... - """ def decorator(f): self.add_event_handler(f, event) return f @@ -108,38 +48,6 @@ def add_event_handler( self: 'TelegramClient', callback: Callback, event: EventBuilder = None): - """ - Registers a new event handler callback. - - The callback will be called when the specified event occurs. - - Arguments - callback (`callable`): - The callable function accepting one parameter to be used. - - Note that if you have used `telethon.events.register` in - the callback, ``event`` will be ignored, and instead the - events you previously registered will be used. - - event (`_EventBuilder` | `type`, optional): - The event builder class or instance to be used, - for instance ``events.NewMessage``. - - If left unspecified, `telethon.events.raw.Raw` (the - :tl:`Update` objects with no further processing) will - be passed instead. - - Example - .. code-block:: python - - from telethon import TelegramClient, events - client = TelegramClient(...) - - async def handler(event): - ... - - client.add_event_handler(handler, events.NewMessage) - """ builders = events._get_handlers(callback) if builders is not None: for event in builders: @@ -157,27 +65,6 @@ def remove_event_handler( self: 'TelegramClient', callback: Callback, event: EventBuilder = None) -> int: - """ - Inverse operation of `add_event_handler()`. - - If no event is given, all events for this callback are removed. - Returns how many callbacks were removed. - - Example - .. code-block:: python - - @client.on(events.Raw) - @client.on(events.NewMessage) - async def handler(event): - ... - - # Removes only the "Raw" handling - # "handler" will still receive "events.NewMessage" - client.remove_event_handler(handler, events.Raw) - - # "handler" will stop receiving anything - client.remove_event_handler(handler) - """ found = 0 if event and not isinstance(event, type): event = type(event) @@ -194,38 +81,9 @@ def remove_event_handler( def list_event_handlers(self: 'TelegramClient')\ -> 'typing.Sequence[typing.Tuple[Callback, EventBuilder]]': - """ - Lists all registered event handlers. - - Returns - A list of pairs consisting of ``(callback, event)``. - - Example - .. code-block:: python - - @client.on(events.NewMessage(pattern='hello')) - async def on_greeting(event): - '''Greets someone''' - await event.reply('Hi') - - for callback, event in client.list_event_handlers(): - print(id(callback), type(event)) - """ return [(callback, event) for event, callback in self._event_builders] async def catch_up(self: 'TelegramClient'): - """ - "Catches up" on the missed updates while the client was offline. - You should call this method after registering the event handlers - so that the updates it loads can by processed by your script. - - This can also be used to forcibly fetch new updates if there are any. - - Example - .. code-block:: python - - await client.catch_up() - """ pts, date = self._state_cache[None] if not pts: return diff --git a/telethon/_client/users.py b/telethon/_client/users.py index e6964e55..0d871878 100644 --- a/telethon/_client/users.py +++ b/telethon/_client/users.py @@ -129,26 +129,6 @@ async def call(self: 'TelegramClient', sender, request, ordered=False, flood_sle async def get_me(self: 'TelegramClient', input_peer: bool = False) \ -> 'typing.Union[types.User, types.InputPeerUser]': - """ - Gets "me", the current :tl:`User` who is logged in. - - If the user has not logged in yet, this method returns `None`. - - Arguments - input_peer (`bool`, optional): - Whether to return the :tl:`InputPeerUser` version or the normal - :tl:`User`. This can be useful if you just need to know the ID - of yourself. - - Returns - Your own :tl:`User`. - - Example - .. code-block:: python - - me = await client.get_me() - print(me.username) - """ if input_peer and self._self_input_peer: return self._self_input_peer @@ -176,34 +156,12 @@ def _self_id(self: 'TelegramClient') -> typing.Optional[int]: return self._self_input_peer.user_id if self._self_input_peer else None async def is_bot(self: 'TelegramClient') -> bool: - """ - Return `True` if the signed-in user is a bot, `False` otherwise. - - Example - .. code-block:: python - - if await client.is_bot(): - print('Beep') - else: - print('Hello') - """ if self._bot is None: self._bot = (await self.get_me()).bot return self._bot async def is_user_authorized(self: 'TelegramClient') -> bool: - """ - Returns `True` if the user is authorized (logged in). - - Example - .. code-block:: python - - if not await client.is_user_authorized(): - await client.send_code_request(phone) - code = input('enter code: ') - await client.sign_in(phone, code) - """ if self._authorized is None: try: # Any request that requires authorization will work @@ -217,59 +175,6 @@ async def is_user_authorized(self: 'TelegramClient') -> bool: async def get_entity( self: 'TelegramClient', entity: 'hints.EntitiesLike') -> 'hints.Entity': - """ - Turns the given entity into a valid Telegram :tl:`User`, :tl:`Chat` - or :tl:`Channel`. You can also pass a list or iterable of entities, - and they will be efficiently fetched from the network. - - Arguments - entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`): - If a username is given, **the username will be resolved** making - an API call every time. Resolving usernames is an expensive - operation and will start hitting flood waits around 50 usernames - in a short period of time. - - If you want to get the entity for a *cached* username, you should - first `get_input_entity(username) ` which will - use the cache), and then use `get_entity` with the result of the - previous call. - - Similar limits apply to invite links, and you should use their - ID instead. - - Using phone numbers (from people in your contact list), exact - names, integer IDs or :tl:`Peer` rely on a `get_input_entity` - first, which in turn needs the entity to be in cache, unless - a :tl:`InputPeer` was passed. - - Unsupported types will raise ``TypeError``. - - If the entity can't be found, ``ValueError`` will be raised. - - Returns - :tl:`User`, :tl:`Chat` or :tl:`Channel` corresponding to the - input entity. A list will be returned if more than one was given. - - Example - .. code-block:: python - - from telethon import utils - - me = await client.get_entity('me') - print(utils.get_display_name(me)) - - chat = await client.get_input_entity('username') - async for message in client.iter_messages(chat): - ... - - # Note that you could have used the username directly, but it's - # good to use get_input_entity if you will reuse it a lot. - async for message in client.iter_messages('username'): - ... - - # Note that for this to work the phone number must be in your contacts - some_id = await client.get_peer_id('+34123456789') - """ single = not utils.is_list_like(entity) if single: entity = (entity,) @@ -340,67 +245,6 @@ async def get_entity( async def get_input_entity( self: 'TelegramClient', peer: 'hints.EntityLike') -> 'types.TypeInputPeer': - """ - Turns the given entity into its input entity version. - - Most requests use this kind of :tl:`InputPeer`, so this is the most - suitable call to make for those cases. **Generally you should let the - library do its job** and don't worry about getting the input entity - first, but if you're going to use an entity often, consider making the - call: - - Arguments - entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`): - If a username or invite link is given, **the library will - use the cache**. This means that it's possible to be using - a username that *changed* or an old invite link (this only - happens if an invite link for a small group chat is used - after it was upgraded to a mega-group). - - If the username or ID from the invite link is not found in - the cache, it will be fetched. The same rules apply to phone - numbers (``'+34 123456789'``) from people in your contact list. - - If an exact name is given, it must be in the cache too. This - is not reliable as different people can share the same name - and which entity is returned is arbitrary, and should be used - only for quick tests. - - If a positive integer ID is given, the entity will be searched - in cached users, chats or channels, without making any call. - - If a negative integer ID is given, the entity will be searched - exactly as either a chat (prefixed with ``-``) or as a channel - (prefixed with ``-100``). - - If a :tl:`Peer` is given, it will be searched exactly in the - cache as either a user, chat or channel. - - If the given object can be turned into an input entity directly, - said operation will be done. - - Unsupported types will raise ``TypeError``. - - If the entity can't be found, ``ValueError`` will be raised. - - Returns - :tl:`InputPeerUser`, :tl:`InputPeerChat` or :tl:`InputPeerChannel` - or :tl:`InputPeerSelf` if the parameter is ``'me'`` or ``'self'``. - - If you need to get the ID of yourself, you should use - `get_me` with ``input_peer=True``) instead. - - Example - .. code-block:: python - - # If you're going to use "username" often in your code - # (make a lot of calls), consider getting its input entity - # once, and then using the "user" everywhere instead. - user = await client.get_input_entity('username') - - # The same applies to IDs, chats or channels. - chat = await client.get_input_entity(-123456789) - """ # Short-circuit if the input parameter directly maps to an InputPeer try: return utils.get_input_peer(peer) @@ -472,20 +316,6 @@ async def get_peer_id( self: 'TelegramClient', peer: 'hints.EntityLike', add_mark: bool = True) -> int: - """ - Gets the ID for the given entity. - - This method needs to be ``async`` because `peer` supports usernames, - invite-links, phone numbers (from people in your contact list), etc. - - If ``add_mark is False``, then a positive ID will be returned - instead. By default, bot-API style IDs (signed) are returned. - - Example - .. code-block:: python - - print(await client.get_peer_id('me')) - """ if isinstance(peer, int): return utils.get_peer_id(peer, add_mark=add_mark)