From b716c4fe6792246c7bec3c06d8edd911b169f0ba Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sat, 20 Jan 2018 11:47:17 +0100 Subject: [PATCH] Several documentation enhancements and build warnings fixes - Made the documentation even more friendly towards newbies. - Eased the usage of methods like get history which now set a default empty message for message actions and vice versa. - Fixed some docstring documentations too. - Updated the old normal docs/ to link back and forth RTD. - Fixed the version of the documentation, now auto-loaded. --- docs/res/core.html | 78 +++++-------------- readthedocs/conf.py | 12 ++- .../advanced-usage/accessing-the-full-api.rst | 18 ++++- readthedocs/extra/basic/creating-a-client.rst | 2 + readthedocs/extra/basic/entities.rst | 53 ++++++++----- readthedocs/extra/basic/getting-started.rst | 35 +++++++-- readthedocs/extra/basic/installation.rst | 10 ++- readthedocs/extra/basic/telegram-client.rst | 31 ++++---- .../extra/basic/working-with-updates.rst | 6 ++ readthedocs/extra/examples/bots.rst | 5 ++ .../extra/examples/chats-and-channels.rst | 5 ++ .../extra/examples/working-with-messages.rst | 5 ++ readthedocs/index.rst | 15 ++-- readthedocs/telethon.rst | 13 +++- readthedocs/telethon.tl.rst | 16 ---- telethon/telegram_client.py | 6 +- telethon/tl/custom/dialog.py | 5 +- telethon/tl/custom/draft.py | 6 +- 18 files changed, 180 insertions(+), 141 deletions(-) diff --git a/docs/res/core.html b/docs/res/core.html index bc5c04b3..8c8bc9d8 100644 --- a/docs/res/core.html +++ b/docs/res/core.html @@ -44,8 +44,15 @@ page aims to provide easy access to all the available methods, their definition and parameters.

-

Although this documentation was generated for Telethon, it may - be useful for any other Telegram library out there.

+

Please note that when you see this:

+
---functions---
+users.getUsers#0d91a548 id:Vector<InputUser> = Vector<User>
+ +

This is not Python code. It's the "TL definition". It's + an easy-to-read line that gives a quick overview on the parameters + and its result. You don't need to worry about this. See + here + for more details on it.

Index

Full example

-

The following example demonstrates:

-
    -
  1. How to create a TelegramClient.
  2. -
  3. Connecting to the Telegram servers and authorizing an user.
  4. -
  5. Retrieving a list of chats (dialogs).
  6. -
  7. Invoking a request without the built-in methods.
  8. -
-
#!/usr/bin/python3
-from telethon import TelegramClient
-from telethon.tl.functions.messages import GetHistoryRequest
-
-# (1) Use your own values here
-api_id   = 12345
-api_hash = '0123456789abcdef0123456789abcdef'
-phone    = '+34600000000'
-
-# (2) Create the client and connect
-client = TelegramClient('username', api_id, api_hash)
-client.connect()
-
-# Ensure you're authorized
-if not client.is_user_authorized():
-    client.send_code_request(phone)
-    client.sign_in(phone, input('Enter the code: '))
-
-# (3) Using built-in methods
-dialogs, entities = client.get_dialogs(10)
-entity = entities[0]
-
-# (4) !! Invoking a request manually !!
-result = client(GetHistoryRequest(
-    entity,
-    limit=20,
-    offset_date=None,
-    offset_id=0,
-    max_id=0,
-    min_id=0,
-    add_offset=0
-))
-
-# Now you have access to the first 20 messages
-messages = result.messages
- -

As it can be seen, manually calling requests with - client(request) (or using the old way, by calling - client.invoke(request)) is way more verbose than using the - built-in methods (such as client.get_dialogs()).

- -

However, and - given that there are so many methods available, it's impossible to provide - a nice interface to things that may change over time. To get full access, - however, you're still able to invoke these methods manually.

+

Documentation for this is now + here. +

diff --git a/readthedocs/conf.py b/readthedocs/conf.py index 18ff1a17..efb14992 100644 --- a/readthedocs/conf.py +++ b/readthedocs/conf.py @@ -20,6 +20,11 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) +import os +import re + + +root = os.path.abspath(os.path.join(__file__, os.path.pardir, os.path.pardir)) # -- General configuration ------------------------------------------------ @@ -55,9 +60,12 @@ author = 'Lonami' # built documents. # # The short X.Y version. -version = '0.15' +with open(os.path.join(root, 'telethon', 'version.py')) as f: + version = re.search(r"^__version__\s+=\s+'(.*)'$", + f.read(), flags=re.MULTILINE).group(1) + # The full version, including alpha/beta/rc tags. -release = '0.15.5' +release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/readthedocs/extra/advanced-usage/accessing-the-full-api.rst b/readthedocs/extra/advanced-usage/accessing-the-full-api.rst index 04659bdb..7276aa43 100644 --- a/readthedocs/extra/advanced-usage/accessing-the-full-api.rst +++ b/readthedocs/extra/advanced-usage/accessing-the-full-api.rst @@ -14,8 +14,10 @@ through a sorted list of everything you can do. .. note:: - Removing the hand crafted documentation for methods is still - a work in progress! + The reason to keep both https://lonamiwebs.github.io/Telethon and this + documentation alive is that the former allows instant search results + as you type, and a "Copy import" button. If you like namespaces, you + can also do ``from telethon.tl import types, functions``. Both work. You should also refer to the documentation to see what the objects @@ -39,8 +41,8 @@ If you're going to use a lot of these, you may do: .. code-block:: python - import telethon.tl.functions as tl - # We now have access to 'tl.messages.SendMessageRequest' + from telethon.tl import types, functions + # We now have access to 'functions.messages.SendMessageRequest' We see that this request must take at least two parameters, a ``peer`` of type `InputPeer`__, and a ``message`` which is just a Python @@ -82,6 +84,14 @@ every time its used, simply call ``.get_input_peer``: from telethon import utils peer = utils.get_input_user(entity) + +.. note:: + + Since ``v0.16.2`` this is further simplified. The ``Request`` itself + will call ``client.get_input_entity()`` for you when required, but + it's good to remember what's happening. + + After this small parenthesis about ``.get_entity`` versus ``.get_input_entity``, we have everything we need. To ``.invoke()`` our request we do: diff --git a/readthedocs/extra/basic/creating-a-client.rst b/readthedocs/extra/basic/creating-a-client.rst index 10ae5f60..bf565bb0 100644 --- a/readthedocs/extra/basic/creating-a-client.rst +++ b/readthedocs/extra/basic/creating-a-client.rst @@ -93,6 +93,8 @@ method also accepts a ``phone=`` and ``bot_token`` parameters. You can use either, as both will work. Determining which is just a matter of taste, and how much control you need. +Remember that you can get yourself at any time with ``client.get_me()``. + .. note:: If you want to use a **proxy**, you have to `install PySocks`__ diff --git a/readthedocs/extra/basic/entities.rst b/readthedocs/extra/basic/entities.rst index bc87539a..472942a7 100644 --- a/readthedocs/extra/basic/entities.rst +++ b/readthedocs/extra/basic/entities.rst @@ -10,21 +10,6 @@ The library widely uses the concept of "entities". An entity will refer to any ``User``, ``Chat`` or ``Channel`` object that the API may return in response to certain methods, such as ``GetUsersRequest``. -To save bandwidth, the API also makes use of their "input" versions. -The input version of an entity (e.g. ``InputPeerUser``, ``InputChat``, -etc.) only contains the minimum required information that's required -for Telegram to be able to identify who you're referring to: their ID -and hash. This ID/hash pair is unique per user, so if you use the pair -given by another user **or bot** it will **not** work. - -To save *even more* bandwidth, the API also makes use of the ``Peer`` -versions, which just have an ID. This serves to identify them, but -peers alone are not enough to use them. You need to know their hash -before you can "use them". - -Luckily, the library tries to simplify this mess the best it can. - - Getting entities **************** @@ -58,8 +43,8 @@ you're able to just do this: my_channel = client.get_entity(PeerChannel(some_id)) -All methods in the :ref:`telegram-client` call ``.get_entity()`` to further -save you from the hassle of doing so manually, so doing things like +All methods in the :ref:`telegram-client` call ``.get_input_entity()`` to +further save you from the hassle of doing so manually, so doing things like ``client.send_message('lonami', 'hi!')`` is possible. Every entity the library "sees" (in any response to any call) will by @@ -72,7 +57,27 @@ made to obtain the required information. Entities vs. Input Entities *************************** -As we mentioned before, API calls don't need to know the whole information +.. note:: + + Don't worry if you don't understand this section, just remember some + of the details listed here are important. When you're calling a method, + don't call ``.get_entity()`` before, just use the username or phone, + or the entity retrieved by other means like ``.get_dialogs()``. + + +To save bandwidth, the API also makes use of their "input" versions. +The input version of an entity (e.g. ``InputPeerUser``, ``InputChat``, +etc.) only contains the minimum required information that's required +for Telegram to be able to identify who you're referring to: their ID +and hash. This ID/hash pair is unique per user, so if you use the pair +given by another user **or bot** it will **not** work. + +To save *even more* bandwidth, the API also makes use of the ``Peer`` +versions, which just have an ID. This serves to identify them, but +peers alone are not enough to use them. You need to know their hash +before you can "use them". + +As we just mentioned, API calls don't need to know the whole information about the entities, only their ID and hash. For this reason, another method, ``.get_input_entity()`` is available. This will always use the cache while possible, making zero API calls most of the time. When a request is made, @@ -85,3 +90,15 @@ the most recent information about said entity, but invoking requests don't need this information, just the ``InputPeer``. Only use ``.get_entity()`` if you need to get actual information, like the username, name, title, etc. of the entity. + +To further simplify the workflow, since the version ``0.16.2`` of the +library, the raw requests you make to the API are also able to call +``.get_input_entity`` wherever needed, so you can even do things like: + + .. code-block:: python + + client(SendMessageRequest('username', 'hello')) + +The library will call the ``.resolve()`` method of the request, which will +resolve ``'username'`` with the appropriated ``InputPeer``. Don't worry if +you don't get this yet, but remember some of the details here are important. diff --git a/readthedocs/extra/basic/getting-started.rst b/readthedocs/extra/basic/getting-started.rst index e69cc3ef..87c142e9 100644 --- a/readthedocs/extra/basic/getting-started.rst +++ b/readthedocs/extra/basic/getting-started.rst @@ -1,7 +1,5 @@ -.. Telethon documentation master file, created by - sphinx-quickstart on Fri Nov 17 15:36:11 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. _getting-started: + =============== Getting Started @@ -39,13 +37,36 @@ Basic Usage .. code-block:: python - print(me.stringify()) + # Getting information about yourself + print(client.get_me().stringify()) - client.send_message('username', 'Hello! Talking to you from Telethon') + # Sending a message (you can use 'me' or 'self' to message yourself) + client.send_message('username', 'Hello World from Telethon!') + + # Sending a file client.send_file('username', '/home/myself/Pictures/holidays.jpg') - client.download_profile_photo(me) + # Retrieving messages from a chat + from telethon import utils + for message in client.get_message_history('username', limit=10): + print(utils.get_display_name(message.sender), message.message) + + # Listing all the dialogs (conversations you have open) + for dialog in client.get_dialogs(limit=10): + print(utils.get_display_name(dialog.entity), dialog.draft.message) + + # Downloading profile photos (default path is the working directory) + client.download_profile_photo('username') + + # Once you have a message with .media (if message.media) + # you can download it using client.download_media(): messages = client.get_message_history('username') client.download_media(messages[0]) **More details**: :ref:`telegram-client` + + +---------- + +You can continue by clicking on the "More details" link below each +snippet of code or the "Next" button at the bottom of the page. diff --git a/readthedocs/extra/basic/installation.rst b/readthedocs/extra/basic/installation.rst index 945576d0..e74cdae6 100644 --- a/readthedocs/extra/basic/installation.rst +++ b/readthedocs/extra/basic/installation.rst @@ -29,7 +29,9 @@ You can also install the library directly from GitHub or a fork: $ cd Telethon/ # pip install -Ue . -If you don't have root access, simply pass the ``--user`` flag to the pip command. +If you don't have root access, simply pass the ``--user`` flag to the pip +command. If you want to install a specific branch, append ``@branch`` to +the end of the first install command. Manual Installation @@ -49,7 +51,8 @@ Manual Installation 5. Done! -To generate the documentation, ``cd docs`` and then ``python3 generate.py``. +To generate the `method documentation`__, ``cd docs`` and then +``python3 generate.py`` (if some pages render bad do it twice). Optional dependencies @@ -62,5 +65,6 @@ will also work without it. __ https://github.com/ricmoo/pyaes __ https://pypi.python.org/pypi/pyaes -__ https://github.com/sybrenstuvel/python-rsa/ +__ https://github.com/sybrenstuvel/python-rsa __ https://pypi.python.org/pypi/rsa/3.4.2 +__ https://lonamiwebs.github.io/Telethon diff --git a/readthedocs/extra/basic/telegram-client.rst b/readthedocs/extra/basic/telegram-client.rst index 5663f533..d3375200 100644 --- a/readthedocs/extra/basic/telegram-client.rst +++ b/readthedocs/extra/basic/telegram-client.rst @@ -43,30 +43,29 @@ how the library refers to either of these: lonami = client.get_entity('lonami') The so called "entities" are another important whole concept on its own, -and you should -Note that saving and using these entities will be more important when -Accessing the Full API. For now, this is a good way to get information -about an user or chat. +but for now you don't need to worry about it. Simply know that they are +a good way to get information about an user, chat or channel. -Other common methods for quick scripts are also available: +Many other common methods for quick scripts are also available: .. code-block:: python - # Sending a message (use an entity/username/etc) - client.send_message('TheAyyBot', 'ayy') + # Note that you can use 'me' or 'self' to message yourself + client.send_message('username', 'Hello World from Telethon!') - # Sending a photo, or a file - client.send_file(myself, '/path/to/the/file.jpg', force_document=True) + client.send_file('username', '/home/myself/Pictures/holidays.jpg') - # Downloading someone's profile photo. File is saved to 'where' - where = client.download_profile_photo(someone) + # The utils package has some goodies, like .get_display_name() + from telethon import utils + for message in client.get_message_history('username', limit=10): + print(utils.get_display_name(message.sender), message.message) - # Retrieving the message history - messages = client.get_message_history(someone) + # Dialogs are the conversations you have open + for dialog in client.get_dialogs(limit=10): + print(utils.get_display_name(dialog.entity), dialog.draft.message) - # Downloading the media from a specific message - # You can specify either a directory, a filename, or nothing at all - where = client.download_media(message, '/path/to/output') + # Default path is the working directory + client.download_profile_photo('username') # Call .disconnect() when you're done client.disconnect() diff --git a/readthedocs/extra/basic/working-with-updates.rst b/readthedocs/extra/basic/working-with-updates.rst index bb78eb97..72155d86 100644 --- a/readthedocs/extra/basic/working-with-updates.rst +++ b/readthedocs/extra/basic/working-with-updates.rst @@ -4,6 +4,12 @@ Working with Updates ==================== + +.. note:: + + There are plans to make working with updates more friendly. Stay tuned! + + .. contents:: diff --git a/readthedocs/extra/examples/bots.rst b/readthedocs/extra/examples/bots.rst index b231e200..fd4d54de 100644 --- a/readthedocs/extra/examples/bots.rst +++ b/readthedocs/extra/examples/bots.rst @@ -3,6 +3,11 @@ Bots ==== +.. note:: + + These examples assume you have read :ref:`accessing-the-full-api`. + + Talking to Inline Bots ********************** diff --git a/readthedocs/extra/examples/chats-and-channels.rst b/readthedocs/extra/examples/chats-and-channels.rst index 99ce235f..be836b16 100644 --- a/readthedocs/extra/examples/chats-and-channels.rst +++ b/readthedocs/extra/examples/chats-and-channels.rst @@ -3,6 +3,11 @@ Working with Chats and Channels =============================== +.. note:: + + These examples assume you have read :ref:`accessing-the-full-api`. + + Joining a chat or channel ************************* diff --git a/readthedocs/extra/examples/working-with-messages.rst b/readthedocs/extra/examples/working-with-messages.rst index 880bac6f..43492605 100644 --- a/readthedocs/extra/examples/working-with-messages.rst +++ b/readthedocs/extra/examples/working-with-messages.rst @@ -3,6 +3,11 @@ Working with messages ===================== +.. note:: + + These examples assume you have read :ref:`accessing-the-full-api`. + + Forwarding messages ******************* diff --git a/readthedocs/index.rst b/readthedocs/index.rst index cae75541..74c3b8e6 100644 --- a/readthedocs/index.rst +++ b/readthedocs/index.rst @@ -10,8 +10,12 @@ Welcome to Telethon's documentation! Pure Python 3 Telegram client library. Official Site `here `_. -Please follow the links below to get you started, and remember -to read the :ref:`changelog` when you upgrade! +Please follow the links on the index below to navigate from here, +or use the menu on the left. Remember to read the :ref:`changelog` +when you upgrade! + +.. important:: + If you're new here, you want to read :ref:`getting-started`. What is this? @@ -85,19 +89,20 @@ heavy job for you, so you can focus on developing an application. extra/developing/telegram-api-in-other-languages.rst -.. _Wall-of-shame: +.. _More: .. toctree:: :maxdepth: 2 - :caption: Wall of Shame + :caption: More + extra/changelog extra/wall-of-shame.rst .. toctree:: :caption: Telethon modules - telethon + modules Indices and tables diff --git a/readthedocs/telethon.rst b/readthedocs/telethon.rst index 2d3c269c..e7a30c42 100644 --- a/readthedocs/telethon.rst +++ b/readthedocs/telethon.rst @@ -42,6 +42,13 @@ telethon\.utils module :undoc-members: :show-inheritance: +telethon\.session module +------------------------ + +.. automodule:: telethon.session + :members: + :undoc-members: + :show-inheritance: telethon\.cryto package ------------------------ @@ -58,21 +65,21 @@ telethon\.errors package telethon.errors telethon\.extensions package ------------------------- +---------------------------- .. toctree:: telethon.extensions telethon\.network package ------------------------- +------------------------- .. toctree:: telethon.network telethon\.tl package ------------------------- +-------------------- .. toctree:: diff --git a/readthedocs/telethon.tl.rst b/readthedocs/telethon.tl.rst index 6fbb1f00..a10ecc68 100644 --- a/readthedocs/telethon.tl.rst +++ b/readthedocs/telethon.tl.rst @@ -7,14 +7,6 @@ telethon\.tl package telethon.tl.custom -telethon\.tl\.entity\_database module -------------------------------------- - -.. automodule:: telethon.tl.entity_database - :members: - :undoc-members: - :show-inheritance: - telethon\.tl\.gzip\_packed module --------------------------------- @@ -31,14 +23,6 @@ telethon\.tl\.message\_container module :undoc-members: :show-inheritance: -telethon\.tl\.session module ----------------------------- - -.. automodule:: telethon.tl.session - :members: - :undoc-members: - :show-inheritance: - telethon\.tl\.tl\_message module -------------------------------- diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index f09a62fa..5fe186f3 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -406,7 +406,7 @@ class TelegramClient(TelegramBareClient): def log_out(self): """ - Logs out Telegram and deletes the current *.session file. + Logs out Telegram and deletes the current ``*.session`` file. Returns: True if the operation was successful. @@ -742,6 +742,10 @@ class TelegramClient(TelegramBareClient): # Add a few extra attributes to the Message to make it friendlier. messages.total = total_messages for m in messages: + # To make messages more friendly, always add message + # to service messages, and action to normal messages. + m.message = getattr(m, 'message', None) + m.action = getattr(m, 'action', None) m.sender = (None if not m.from_id else entities[utils.get_peer_id(m.from_id)]) diff --git a/telethon/tl/custom/dialog.py b/telethon/tl/custom/dialog.py index fd36ba8f..366a19bf 100644 --- a/telethon/tl/custom/dialog.py +++ b/telethon/tl/custom/dialog.py @@ -24,10 +24,7 @@ class Dialog: self.unread_count = dialog.unread_count self.unread_mentions_count = dialog.unread_mentions_count - if dialog.draft: - self.draft = Draft(client, dialog.peer, dialog.draft) - else: - self.draft = None + self.draft = Draft(client, dialog.peer, dialog.draft) def send_message(self, *args, **kwargs): """ diff --git a/telethon/tl/custom/draft.py b/telethon/tl/custom/draft.py index abf84548..ae08403a 100644 --- a/telethon/tl/custom/draft.py +++ b/telethon/tl/custom/draft.py @@ -1,16 +1,18 @@ from ..functions.messages import SaveDraftRequest -from ..types import UpdateDraftMessage +from ..types import UpdateDraftMessage, DraftMessage class Draft: """ Custom class that encapsulates a draft on the Telegram servers, providing an abstraction to change the message conveniently. The library will return - instances of this class when calling `client.get_drafts()`. + instances of this class when calling ``client.get_drafts()``. """ def __init__(self, client, peer, draft): self._client = client self._peer = peer + if not draft: + draft = DraftMessage('', None, None, None, None) self.text = draft.message self.date = draft.date