diff --git a/readthedocs/basic/installation.rst b/readthedocs/basic/installation.rst
new file mode 100644
index 00000000..96f529a9
--- /dev/null
+++ b/readthedocs/basic/installation.rst
@@ -0,0 +1,77 @@
+.. _installation:
+
+============
+Installation
+============
+
+Telethon is a Python library, which means you need to download and install
+Python from https://www.python.org/downloads/ if you haven't already. Once
+you have Python installed, run:
+
+.. code-block:: sh
+
+ pip3 install -U telethon --user
+
+To install or upgrade the library to the latest version.
+
+
+Installing Development Versions
+===============================
+
+If you want the *latest* unreleased changes,
+you can run the following command instead:
+
+.. code-block:: sh
+
+ pip3 install -U https://github.com/LonamiWebs/Telethon/archive/master.zip --user
+
+.. note::
+
+ The development version may have bugs and is not recommended for production
+ use. However, when you are `reporting a library bug`__, you should try if the
+ bug still occurs in this version.
+
+.. __: https://github.com/LonamiWebs/Telethon/issues/
+
+
+Verification
+============
+
+To verify that the library is installed correctly, run the following command:
+
+.. code-block:: sh
+
+ python3 -c 'import telethon; print(telethon.__version__)'
+
+The version number of the library should show in the output.
+
+
+Optional Dependencies
+=====================
+
+If cryptg_ is installed, **the library will work a lot faster**, since
+encryption and decryption will be made in C instead of Python. If your
+code deals with a lot of updates or you are downloading/uploading a lot
+of files, you will notice a considerable speed-up (from a hundred kilobytes
+per second to several megabytes per second, if your connection allows it).
+If it's not installed, pyaes_ will be used (which is pure Python, so it's
+much slower).
+
+If pillow_ is installed, large images will be automatically resized when
+sending photos to prevent Telegram from failing with "invalid image".
+Official clients also do this.
+
+If aiohttp_ is installed, the library will be able to download
+:tl:`WebDocument` media files (otherwise you will get an error).
+
+If hachoir_ is installed, it will be used to extract metadata from files
+when sending documents. Telegram uses this information to show the song's
+performer, artist, title, duration, and for videos too (including size).
+Otherwise, they will default to empty values, and you can set the attributes
+manually.
+
+.. _cryptg: https://github.com/Lonami/cryptg
+.. _pyaes: https://github.com/ricmoo/pyaes
+.. _pillow: https://python-pillow.org
+.. _aiohttp: https://docs.aiohttp.org
+.. _hachoir: https://hachoir.readthedocs.io
diff --git a/readthedocs/basic/next-steps.rst b/readthedocs/basic/next-steps.rst
new file mode 100644
index 00000000..7cecdc9a
--- /dev/null
+++ b/readthedocs/basic/next-steps.rst
@@ -0,0 +1,22 @@
+==========
+Next Steps
+==========
+
+These basic first steps should have gotten you started with the library.
+
+By now, you should know how to call friendly methods and how to work with
+the returned objects, how things work inside event handlers, etc.
+
+Next, we will see a quick reference summary of *all* the methods and
+properties that you will need when using the library. If you follow
+the links there, you will expand the documentation for the method
+and property, with more examples on how to use them.
+
+Therefore, **you can find an example on every method** of the client
+to learn how to use it, as well as a description of all the arguments.
+
+After that, we will go in-depth with some other important concepts
+that are worth learning and understanding.
+
+From now on, you can keep pressing the "Next" button if you want,
+or use the menu on the left, since some pages are quite lengthy.
diff --git a/readthedocs/basic/quick-start.rst b/readthedocs/basic/quick-start.rst
new file mode 100644
index 00000000..40e99f6b
--- /dev/null
+++ b/readthedocs/basic/quick-start.rst
@@ -0,0 +1,79 @@
+===========
+Quick-Start
+===========
+
+Let's see a longer example to learn some of the methods that the library
+has to offer. These are known as "friendly methods", and you should always
+use these if possible.
+
+.. code-block:: python
+
+ from telethon.sync import TelegramClient
+
+ # Remember to use your own values from my.telegram.org!
+ api_id = 12345
+ api_hash = '0123456789abcdef0123456789abcdef'
+
+ with TelegramClient('anon', api_id, api_hash) as client:
+ # Getting information about yourself
+ me = client.get_me()
+
+ # "me" is an User object. You can pretty-print
+ # any Telegram object with the "stringify" method:
+ print(me.stringify())
+
+ # When you print something, you see a representation of it.
+ # You can access all attributes of Telegram objects with
+ # the dot operator. For example, to get the username:
+ username = me.username
+ print(username)
+ print(me.phone)
+
+ # You can print all the dialogs/conversations that you are part of:
+ for dialog in client.iter_dialogs():
+ print(dialog.name, 'has ID', dialog.id)
+
+ # You can send messages to yourself...
+ client.send_message('me', 'Hello, myself!')
+ # ...to some chat ID
+ client.send_message(-100123456, 'Hello, group!')
+ # ...to your contacts
+ client.send_message('+34600123123', 'Hello, friend!')
+ # ...or even to any username
+ client.send_message('TelethonChat', 'Hello, Telethon!')
+
+ # You can, of course, use markdown in your messages:
+ message = client.send_message(
+ 'me',
+ 'This message has **bold**, `code`, __italics__ and '
+ 'a [nice website](https://lonamiwebs.github.io)!',
+ link_preview=False
+ )
+
+ # Sending a message returns the sent message object, which you can use
+ print(message.raw_text)
+
+ # You can reply to messages directly if you have a message object
+ message.reply('Cool!')
+
+ # Or send files, songs, documents, albums...
+ client.send_file('me', '/home/me/Pictures/holidays.jpg')
+
+ # You can print the message history of any chat:
+ for message in client.iter_messages('me'):
+ print(message.id, message.text)
+
+ # You can download media from messages, too!
+ # The method will return the path where the file was saved.
+ if message.photo:
+ path = message.download_media()
+ print('File saved to', path)
+
+
+Here, we show how to sign in, get information about yourself, send
+messages, files, getting chats, printing messages, and downloading
+files.
+
+You should make sure that you understand what the code shown here
+does, take note on how methods are called and used and so on before
+proceeding. We will see all the available methods later on.
diff --git a/readthedocs/basic/signing-in.rst b/readthedocs/basic/signing-in.rst
new file mode 100644
index 00000000..a0b3faa3
--- /dev/null
+++ b/readthedocs/basic/signing-in.rst
@@ -0,0 +1,128 @@
+.. _signing-in:
+
+==========
+Signing In
+==========
+
+Before working with Telegram's API, you need to get your own API ID and hash:
+
+1. `Login to your Telegram account `_ with the
+ phone number of the developer account to use.
+
+2. Click under API Development tools.
+
+3. A *Create new application* window will appear. Fill in your application
+ details. There is no need to enter any *URL*, and only the first two
+ fields (*App title* and *Short name*) can currently be changed later.
+
+4. Click on *Create application* at the end. Remember that your
+ **API hash is secret** and Telegram won't let you revoke it.
+ Don't post it anywhere!
+
+.. note::
+
+ This API ID and hash is the one used by *your application*, not your
+ phone number. You can use this API ID and hash with *any* phone number
+ or even for bot accounts.
+
+
+Editing the Code
+================
+
+This is a little introduction for those new to Python programming in general.
+
+We will write our code inside ``hello.py``, so you can use any text
+editor that you like. To run the code, use ``python3 hello.py`` from
+the terminal.
+
+.. important::
+
+ Don't call your script ``telethon.py``! Python will try to import
+ the client from there and it will fail with an error such as
+ "ImportError: cannot import name 'TelegramClient' ...".
+
+
+Signing In
+==========
+
+We can finally write some code to log into our account!
+
+.. code-block:: python
+
+ from telethon.sync import TelegramClient
+
+ # Use your own values from my.telegram.org
+ api_id = 12345
+ api_hash = '0123456789abcdef0123456789abcdef'
+
+ # The first parameter is the .session file name (absolute paths allowed)
+ with TelegramClient('anon', api_id, api_hash) as client:
+ client.send_message('me', 'Hello, myself!')
+
+
+In the first line, we import the class name so we can create an instance
+of the client. Then, we define variables to store our API ID and hash
+conveniently.
+
+At last, we create a new `TelegramClient `
+instance and call it ``client``. We can now use the client variable
+for anything that we want, such as sending a message to ourselves.
+
+Using a ``with`` block is the preferred way to use the library. It will
+automatically `start() ` the client,
+logging or signing up if necessary.
+
+If the ``.session`` file already existed, it will not login
+again, so be aware of this if you move or rename the file!
+
+
+Signing In as a Bot Account
+===========================
+
+You can also use Telethon for your bots (normal bot accounts, not users).
+You will still need an API ID and hash, but the process is very similar:
+
+
+.. code-block:: python
+
+ from telethon.sync import TelegramClient
+
+ api_id = 12345
+ api_hash = '0123456789abcdef0123456789abcdef'
+ bot_token = '12345:0123456789abcdef0123456789abcdef
+
+ # We have to manually call "start" if we want a explicit bot token
+ bot = TelegramClient('bot', api_id, api_hash).start(bot_token=bot_token)
+
+ # But then we can use the client instance as usual
+ with bot:
+ ...
+
+
+To get a bot account, you need to talk
+with `@BotFather `_.
+
+
+Signing In behind a Proxy
+=========================
+
+If you need to use a proxy to access Telegram,
+you will need to `install PySocks`__ and then change:
+
+.. code-block:: python
+
+ TelegramClient('anon', api_id, api_hash)
+
+with
+
+.. code-block:: python
+
+ TelegramClient('anon', api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 4444))
+
+(of course, replacing the IP and port with the IP and port of the proxye).
+
+The ``proxy=`` argument should be a tuple, a list or a dict,
+consisting of parameters described `in PySocks usage`__.
+
+.. __: https://github.com/Anorov/PySocks#installation
+.. __: https://github.com/Anorov/PySocks#usage-1
diff --git a/readthedocs/basic/updates.rst b/readthedocs/basic/updates.rst
new file mode 100644
index 00000000..bf9ca92b
--- /dev/null
+++ b/readthedocs/basic/updates.rst
@@ -0,0 +1,161 @@
+=======
+Updates
+=======
+
+Updates are an important topic in a messaging platform like Telegram.
+After all, you want to be notified when a new message arrives, when
+a member joins, when someone starts typing, etc.
+For that, you can use **events**.
+
+.. important::
+
+ It is strongly advised to enable logging when working with events,
+ since exceptions in event handlers are hidden by default. Please
+ add the following snippet to the very top of your file:
+
+ .. code-block:: python
+
+ import logging
+ logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
+ level=logging.WARNING)
+
+
+Getting Started
+===============
+
+Let's start things with an example to automate replies:
+
+.. code-block:: python
+
+ from telethon import TelegramClient, events
+
+ client = TelegramClient('anon', api_id, api_hash)
+
+ @client.on(events.NewMessage)
+ async def my_event_handler(event):
+ if 'hello' in event.raw_text:
+ await event.reply('hi!')
+
+ client.start()
+ client.run_until_disconnected()
+
+
+This code isn't much, but there might be some things unclear.
+Let's break it down:
+
+.. code-block:: python
+
+ from telethon import TelegramClient, events
+
+ client = TelegramClient('anon', api_id, api_hash)
+
+
+This is normal creation (of course, pass session name, API ID and hash).
+Nothing we don't know already.
+
+.. code-block:: python
+
+ @client.on(events.NewMessage)
+
+
+This Python decorator will attach itself to the ``my_event_handler``
+definition, and basically means that *on* a `NewMessage
+` *event*,
+the callback function you're about to define will be called:
+
+.. code-block:: python
+
+ async def my_event_handler(event):
+ if 'hello' in event.raw_text:
+ await event.reply('hi!')
+
+
+If a `NewMessage
+` event occurs,
+and ``'hello'`` is in the text of the message, we `reply()
+` to the event
+with a ``'hi!'`` message.
+
+.. note::
+
+ Event handlers **must** be ``async def``. After all,
+ Telethon is an asynchronous library based on asyncio_,
+ which is a safer and often faster approach to threads.
+
+ You **must** ``await`` all method calls that use
+ network requests, which is most of them.
+
+
+More Examples
+=============
+
+Replying to messages with hello is fun, but, can we do more?
+
+.. code-block:: python
+
+ @client.on(events.NewMessage(outgoing=True, pattern=r'\.save'))
+ async def handler(event):
+ if event.is_reply:
+ replied = await event.get_reply_message()
+ sender = replied.sender
+ await client.download_profile_photo(sender)
+ await event.respond('Saved your photo {}'.format(sender.username))
+
+We could also get replies. This event filters outgoing messages
+(only those that we send will trigger the method), then we filter
+by the regex ``r'\.save'``, which will match messages starting
+with ``".save"``.
+
+Inside the method, we check whether the event is replying to another message
+or not. If it is, we get the reply message and the sender of that message,
+and download their profile photo.
+
+Let's delete messages which contain "heck". We don't allow swearing here.
+
+.. code-block:: python
+
+ @client.on(events.NewMessage(pattern=r'(?i).*heck'))
+ async def handler(event):
+ await event.delete()
+
+
+With the ``r'(?i).*heck'`` regex, we match case-insensitive
+"heck" anywhere in the message. Regex is very powerful and you
+can learn more at https://regexone.com/.
+
+So far, we have only seen the `NewMessage
+`, but there are many more
+which will be covered later. This is only a small introduction to updates.
+
+Entities
+========
+
+When you need the user or chat where an event occurred, you **must** use
+the following methods:
+
+.. code-block::
+
+ async def handler(event):
+ # Good
+ chat = await event.get_chat()
+ sender = await event.get_sender()
+ chat_id = event.chat_id
+ sender_id = event.sender_id
+
+ # BAD. Don't do this
+ chat = event.chat
+ sender = event.sender
+ chat_id = event.chat.id
+ sender_id = event.sender.id
+
+Events are like messages, but don't have all the information a message has!
+When you manually get a message, it will have all the information it needs.
+When you receive an update about a message, it **won't** have all the
+information, so you have to **use the methods**, not the properties.
+
+Make sure you understand the code seen here before continuing!
+As a rule of thumb, remember that new message events behave just
+like message objects, so you can do with them everything you can
+do with a message object.
+
+.. _asyncio: https://docs.python.org/3/library/asyncio.html
diff --git a/readthedocs/extra/advanced-usage/mastering-asyncio.rst b/readthedocs/concepts/asyncio.rst
similarity index 97%
rename from readthedocs/extra/advanced-usage/mastering-asyncio.rst
rename to readthedocs/concepts/asyncio.rst
index 96382951..182a5d6f 100644
--- a/readthedocs/extra/advanced-usage/mastering-asyncio.rst
+++ b/readthedocs/concepts/asyncio.rst
@@ -8,7 +8,7 @@ Mastering asyncio
What's asyncio?
-***************
+===============
asyncio_ is a Python 3's built-in library. This means it's already installed if
you have Python 3. Since Python 3.5, it is convenient to work with asynchronous
@@ -20,7 +20,7 @@ APIs such as Telegram's makes a lot of sense this way.
Why asyncio?
-************
+============
Asynchronous IO makes a lot of sense in a library like Telethon.
You send a request to the server (such as "get some message"), and
@@ -38,7 +38,7 @@ because tasks are smaller than threads, which are smaller than processes.
What are asyncio basics?
-************************
+========================
.. code-block:: python
@@ -59,7 +59,7 @@ What are asyncio basics?
What does telethon.sync do?
-***************************
+===========================
The moment you import any of these:
@@ -133,7 +133,7 @@ running, and if the loop is running, you must ``await`` things yourself:
What are async, await and coroutines?
-*************************************
+=====================================
The ``async`` keyword lets you define asynchronous functions,
also known as coroutines, and also iterate over asynchronous
@@ -212,7 +212,7 @@ The same example, but without the comment noise:
Can I use threads?
-******************
+==================
Yes, you can, but you must understand that the loops themselves are
not thread safe. and you must be sure to know what is happening. You
@@ -250,7 +250,7 @@ which only works in the main thread.
client.run_until_disconnected() blocks!
-***************************************
+=======================================
All of what `client.run_until_disconnected()
` does is
@@ -282,7 +282,7 @@ Of course, there are better tools to run code hourly or daily, see below.
What else can asyncio do?
-*************************
+=========================
Asynchronous IO is a really powerful tool, as we've seen. There are plenty
of other useful libraries that also use asyncio_ and that you can integrate
@@ -339,7 +339,7 @@ combine all the libraries you want. People seem to forget this simple fact!
Why does client.start() work outside async?
-*******************************************
+===========================================
Because it's so common that it's really convenient to offer said
functionality by default. This means you can set up all your event
@@ -352,7 +352,7 @@ Using the client in a ``with`` block, `start
all support this.
Where can I read more?
-**********************
+======================
`Check out my blog post
`_ about asyncio_, which
diff --git a/readthedocs/extra/basic/entities.rst b/readthedocs/concepts/entities.rst
similarity index 59%
rename from readthedocs/extra/basic/entities.rst
rename to readthedocs/concepts/entities.rst
index 18fda69c..a92d36ba 100644
--- a/readthedocs/extra/basic/entities.rst
+++ b/readthedocs/concepts/entities.rst
@@ -1,46 +1,8 @@
.. _entities:
-=========================
-Users, Chats and Channels
-=========================
-
-
-.. important::
-
- TL;DR; If you're here because of *"Could not find the input entity for"*,
- you must ask yourself "how did I find this entity through official
- applications"? Now do the same with the library. Use what applies:
-
- .. code-block:: python
-
- with client:
- # Does it have an username? Use it!
- entity = client.get_entity(username)
-
- # Do you have a conversation open with them? Get dialogs.
- client.get_dialogs()
-
- # Are they participant of some group? Get them.
- client.get_participants('TelethonChat')
-
- # Is the entity the original sender of a forwarded message? Get it.
- client.get_messages('TelethonChat', 100)
-
- # NOW you can use the ID, anywhere!
- entity = client.get_entity(123456)
- client.send_message(123456, 'Hi!')
-
- Once the library has "seen" the entity, you can use their **integer** ID.
- You can't use entities from IDs the library hasn't seen. You must make the
- library see them *at least once* and disconnect properly. You know where
- the entities are and you must tell the library. It won't guess for you.
-
-
-.. contents::
-
-
-Introduction
-************
+========
+Entities
+========
The library widely uses the concept of "entities". An entity will refer
to any :tl:`User`, :tl:`Chat` or :tl:`Channel` object that the API may return
@@ -67,8 +29,72 @@ in response to certain methods, such as :tl:`GetUsersRequest`.
should work to find the entity.
-Getting entities
-****************
+.. contents::
+
+
+What is an Entity?
+==================
+
+A lot of methods and requests require *entities* to work. For example,
+you send a message to an *entity*, get the username of an *entity*, and
+so on.
+
+There are a lot of things that work as entities: usernames, phone numbers,
+chat links, invite links, IDs, and the types themselves. That is, you can
+use any of those when you see an "entity" is needed.
+
+.. note::
+
+ Remember that the phone number must be in your contact list before you
+ can use it.
+
+You should use, **from better to worse**:
+
+1. Input entities. For example, `event.input_chat
+ `,
+ `message.input_sender
+ `,
+ or caching an entity you will use a lot with
+ ``entity = await client.get_input_entity(...)``.
+
+2. Entities. For example, if you had to get someone's
+ username, you can just use ``user`` or ``channel``.
+ It will work. Only use this option if you already have the entity!
+
+3. IDs. This will always look the entity up from the
+ cache (the ``*.session`` file caches seen entities).
+
+4. Usernames, phone numbers and links. The cache will be
+ used too (unless you force a `client.get_entity()
+ `),
+ but may make a request if the username, phone or link
+ has not been found yet.
+
+In recent versions of the library, the following two are equivalent:
+
+.. code-block:: python
+
+ async def handler(event):
+ await client.send_message(event.sender_id, 'Hi')
+ await client.send_message(event.input_sender, 'Hi')
+
+
+If you need to be 99% sure that the code will work (sometimes it's
+simply impossible for the library to find the input entity), or if
+you will reuse the chat a lot, consider using the following instead:
+
+.. code-block:: python
+
+ async def handler(event):
+ # This method may make a network request to find the input sender.
+ # Properties can't make network requests, so we need a method.
+ sender = await event.get_input_sender()
+ await client.send_message(sender, 'Hi')
+ await client.send_message(sender, 'Hi')
+
+
+Getting Entities
+================
Through the use of the :ref:`sessions`, the library will automatically
remember the ID and hash pair, along with some extra information, so
@@ -79,6 +105,8 @@ you're able to just do this:
# Dialogs are the "conversations you have open".
# This method returns a list of Dialog, which
# has the .entity attribute and other information.
+ #
+ # This part is IMPORTANT, because it feels the entity cache.
dialogs = client.get_dialogs()
# All of these work and do the same.
@@ -109,7 +137,7 @@ you're able to just do this:
library do its job. Use a phone from your contacts, username, ID or
input entity (preferred but not necessary), whatever you already have.
-All methods in the :ref:`telegram-client` call `.get_input_entity()
+All methods in the :ref:`telethon-client` call `.get_input_entity()
` prior
to sending the request to save you from the hassle of doing so manually.
That way, convenience calls such as `client.send_message('lonami', 'hi!')
@@ -124,16 +152,12 @@ made to obtain the required information.
Entities vs. Input Entities
-***************************
+===========================
.. 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 `client.get_entity() `
- beforehand, just use the username, a phone from your contacts, or the entity
- retrieved by other means like `client.get_dialogs()
- `.
+ This section is informative, but worth reading. The library
+ will transparently handle all of these details for you.
On top of the normal types, the API also make use of what they call their
``Input*`` versions of objects. The input version of an entity (e.g.
@@ -195,8 +219,8 @@ resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if
you don't get this yet, but remember some of the details here are important.
-Full entities
-*************
+Full Entities
+=============
In addition to :tl:`PeerUser`, :tl:`InputPeerUser`, :tl:`User` (and its
variants for chats and channels), there is also the concept of :tl:`UserFull`.
@@ -211,3 +235,74 @@ suggest commands to use).
You can get both of these by invoking :tl:`GetFullUser`, :tl:`GetFullChat`
and :tl:`GetFullChannel` respectively.
+
+
+Accessing Entities
+==================
+
+Although it's explicitly noted in the documentation that messages
+*subclass* `ChatGetter `
+and `SenderGetter `,
+some people still don't get inheritance.
+
+When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
+it means that the class you're looking at, *also* can act as the class it
+bases. In this case, `ChatGetter `
+knows how to get the *chat* where a thing belongs to.
+
+So, a `Message ` is a
+`ChatGetter `.
+That means you can do this:
+
+.. code-block:: python
+
+ message.is_private
+ message.chat_id
+ message.get_chat()
+ # ...etc
+
+`SenderGetter ` is similar:
+
+.. code-block:: python
+
+ message.user_id
+ message.get_input_user()
+ message.user
+ # ...etc
+
+Quite a few things implement them, so it makes sense to reuse the code.
+For example, all events (except raw updates) implement `ChatGetter
+` since all events occur
+in some chat.
+
+
+Summary
+=======
+
+TL;DR; If you're here because of *"Could not find the input entity for"*,
+you must ask yourself "how did I find this entity through official
+applications"? Now do the same with the library. Use what applies:
+
+.. code-block:: python
+
+ with client:
+ # Does it have an username? Use it!
+ entity = client.get_entity(username)
+
+ # Do you have a conversation open with them? Get dialogs.
+ client.get_dialogs()
+
+ # Are they participant of some group? Get them.
+ client.get_participants('TelethonChat')
+
+ # Is the entity the original sender of a forwarded message? Get it.
+ client.get_messages('TelethonChat', 100)
+
+ # NOW you can use the ID, anywhere!
+ entity = client.get_entity(123456)
+ client.send_message(123456, 'Hi!')
+
+Once the library has "seen" the entity, you can use their **integer** ID.
+You can't use entities from IDs the library hasn't seen. You must make the
+library see them *at least once* and disconnect properly. You know where
+the entities are and you must tell the library. It won't guess for you.
diff --git a/readthedocs/extra/troubleshooting/rpc-errors.rst b/readthedocs/concepts/errors.rst
similarity index 61%
rename from readthedocs/extra/troubleshooting/rpc-errors.rst
rename to readthedocs/concepts/errors.rst
index f675a26b..429c5697 100644
--- a/readthedocs/extra/troubleshooting/rpc-errors.rst
+++ b/readthedocs/concepts/errors.rst
@@ -1,3 +1,5 @@
+.. _rpc-errors:
+
==========
RPC Errors
==========
@@ -6,7 +8,7 @@ RPC stands for Remote Procedure Call, and when the library raises
a ``RPCError``, it's because you have invoked some of the API
methods incorrectly (wrong parameters, wrong permissions, or even
something went wrong on Telegram's server). All the errors are
-available in :ref:`telethon-errors-package`, but some examples are:
+available in :ref:`telethon-errors`, but some examples are:
- ``FloodWaitError`` (420), the same request was repeated many times.
Must wait ``.seconds`` (you can access this attribute). For example:
@@ -43,3 +45,33 @@ If the error is not recognised, it will only be an ``RPCError``.
You can refer to all errors from Python through the ``telethon.errors``
module. If you don't know what attributes they have, try printing their
dir (like ``print(dir(e))``).
+
+Avoiding Limits
+===============
+
+Don't spam. You won't get ``FloodWaitError`` or your account banned or
+deleted if you use the library *for legit use cases*. Make cool tools.
+Don't spam! Nobody knows the exact limits for all requests since they
+depend on a lot of factors, so don't bother asking.
+
+Still, if you do have a legit use case and still get those errors, the
+library will automatically sleep when they are smaller than 60 seconds
+by default. You can set different "auto-sleep" thresholds:
+
+.. code-block:: python
+
+ client.flood_sleep_threshold = 0 # Don't auto-sleep
+ client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
+
+You can also except it and act as you prefer:
+
+.. code-block:: python
+
+ from telethon.errors import FloodWaitError
+ try:
+ ...
+ except FloodWaitError as e:
+ print('Flood waited for', e.seconds)
+ quit(1)
+
+VoIP numbers are very limited, and some countries are more limited too.
diff --git a/readthedocs/extra/advanced-usage/accessing-the-full-api.rst b/readthedocs/concepts/full-api.rst
similarity index 85%
rename from readthedocs/extra/advanced-usage/accessing-the-full-api.rst
rename to readthedocs/concepts/full-api.rst
index 2d61c253..e7c86b56 100644
--- a/readthedocs/extra/advanced-usage/accessing-the-full-api.rst
+++ b/readthedocs/concepts/full-api.rst
@@ -1,21 +1,21 @@
-.. _accessing-the-full-api:
+.. _full-api:
-======================
-Accessing the Full API
-======================
+============
+The Full API
+============
.. important::
While you have access to this, you should always use the friendly
- methods listed on :ref:`telethon-client` unless you have a better
- reason not to, like a method not existing or you wanting more control.
+ methods listed on :ref:`client-ref` unless you have a better reason
+ not to, like a method not existing or you wanting more control.
-The :ref:`TelegramClient ` doesn't offer a method for
-every single request the Telegram API supports. However, it's very simple to
-*call* or *invoke* any request. Whenever you need something, don't forget to
-`check the documentation`__ and look for the `method you need`__. There you
-can go through a sorted list of everything you can do.
+The :ref:`telethon-client` doesn't offer a method for every single request
+the Telegram API supports. However, it's very simple to *call* or *invoke*
+any request. Whenever you need something, don't forget to `check the documentation`_
+and look for the `method you need`_. There you can go through a sorted list
+of everything you can do.
.. note::
@@ -39,9 +39,9 @@ You should also refer to the documentation to see what the objects
(constructors) Telegram returns look like. Every constructor inherits
from a common type, and that's the reason for this distinction.
-Say `client.send_message
+Say `client.send_message()
` didn't exist,
-we could use the `search`__ to look for "message". There we would find
+we could `use the search`_ to look for "message". There we would find
:tl:`SendMessageRequest`, which we can work with.
Every request is a Python class, and has the parameters needed for you
@@ -73,7 +73,7 @@ construct one, for instance:
peer = InputPeerUser(user_id, user_hash)
-Or we call `client.get_input_entity
+Or we call `client.get_input_entity()
`:
.. code-block:: python
@@ -84,10 +84,10 @@ Or we call `client.get_input_entity
When you're going to invoke an API method, most require you to pass an
:tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
-`client.get_input_entity `
+`client.get_input_entity() `
is more straightforward (and often immediate, if you've seen the user before,
know their ID, etc.). If you also **need** to have information about the whole
-user, use `client.get_entity `
+user, use `client.get_entity() `
instead:
.. code-block:: python
@@ -114,7 +114,7 @@ every time its used, simply call `telethon.utils.get_input_peer`:
After this small parenthesis about `client.get_entity
` versus
-`client.get_input_entity `,
+`client.get_input_entity() `,
we have everything we need. To invoke our
request we do:
@@ -156,7 +156,7 @@ This can further be simplified to:
Requests in Parallel
-********************
+====================
The library will automatically merge outgoing requests into a single
*container*. Telegram's API supports sending multiple requests in a
@@ -224,6 +224,6 @@ and still access the successful results:
# The second request failed.
second = e.exceptions[1]
-__ https://lonamiwebs.github.io/Telethon
-__ https://lonamiwebs.github.io/Telethon/methods/index.html
-__ https://lonamiwebs.github.io/Telethon/?q=message&redirect=no
+.. _check the documentation: https://lonamiwebs.github.io/Telethon
+.. _method you need: https://lonamiwebs.github.io/Telethon/methods/index.html
+.. _use the search: https://lonamiwebs.github.io/Telethon/?q=message&redirect=no
diff --git a/readthedocs/extra/advanced-usage/sessions.rst b/readthedocs/concepts/sessions.rst
similarity index 81%
rename from readthedocs/extra/advanced-usage/sessions.rst
rename to readthedocs/concepts/sessions.rst
index eeae7940..ee528b48 100644
--- a/readthedocs/extra/advanced-usage/sessions.rst
+++ b/readthedocs/concepts/sessions.rst
@@ -6,8 +6,11 @@ Session Files
.. contents::
-What are sessions?
-******************
+They are an important part for the library to be efficient, such as caching
+and handling your authorization key (or you would have to login every time!).
+
+What are Sessions?
+==================
The first parameter you pass to the constructor of the
:ref:`TelegramClient ` is
@@ -43,7 +46,7 @@ by setting ``client.session.save_entities = False``.
Different Session Storage
-*************************
+=========================
If you don't want to use the default SQLite session storage, you can also use
one of the other implementations or implement your own storage.
@@ -54,13 +57,15 @@ the session name.
Telethon contains three implementations of the abstract ``Session`` class:
-* ``MemorySession``: stores session data within memory.
-* ``SQLiteSession``: stores sessions within on-disk SQLite databases. Default.
-* ``StringSession``: stores session data within memory,
+.. currentmodule:: telethon.sessions
+
+* `MemorySession `: stores session data within memory.
+* `SQLiteSession `: stores sessions within on-disk SQLite databases. Default.
+* `StringSession `: stores session data within memory,
but can be saved as a string.
You can import these ``from telethon.sessions``. For example, using the
-``StringSession`` is done as follows:
+`StringSession ` is done as follows:
.. code-block:: python
@@ -91,25 +96,27 @@ There are other community-maintained implementations available:
* `Redis `_:
stores all sessions in a single Redis data store.
+
Creating your Own Storage
-*************************
+=========================
The easiest way to create your own storage implementation is to use
-``MemorySession`` as the base and check out how ``SQLiteSession`` or
-one of the community-maintained implementations work. You can find the
-relevant Python files under the ``sessions`` directory in Telethon.
+`MemorySession ` as the base and check out how
+`SQLiteSession ` or one of the community-maintained
+implementations work. You can find the relevant Python files under the
+``sessions/`` directory in the Telethon's repository.
After you have made your own implementation, you can add it to the
community-maintained session implementation list above with a pull request.
String Sessions
-***************
+===============
-``StringSession`` are a convenient way to embed your login credentials
-directly into your code for extremely easy portability, since all they
-take is a string to be able to login without asking for your phone and
-code (or faster start if you're using a bot token).
+`StringSession ` are a convenient way to embed your
+login credentials directly into your code for extremely easy portability,
+since all they take is a string to be able to login without asking for your
+phone and code (or faster start if you're using a bot token).
The easiest way to generate a string session is as follows:
diff --git a/readthedocs/concepts/strings.rst b/readthedocs/concepts/strings.rst
new file mode 100644
index 00000000..f6f3812e
--- /dev/null
+++ b/readthedocs/concepts/strings.rst
@@ -0,0 +1,100 @@
+======================
+String-based Debugging
+======================
+
+Debugging is *really* important. Telegram's API is really big and there
+is a lot of things that you should know. Such as, what attributes or fields
+does a result have? Well, the easiest thing to do is printing it:
+
+.. code-block:: python
+
+ user = client.get_entity('Lonami')
+ print(user)
+
+That will show a huge **string** similar to the following:
+
+.. code-block:: python
+
+ User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
+
+That's a lot of text. But as you can see, all the properties are there.
+So if you want the username you **don't use regex** or anything like
+splitting ``str(user)`` to get what you want. You just access the
+attribute you need:
+
+.. code-block:: python
+
+ username = user.username
+
+Can we get better than the shown string, though? Yes!
+
+.. code-block:: python
+
+ print(user.stringify())
+
+Will show a much better:
+
+.. code-block:: python
+
+ User(
+ id=10885151,
+ is_self=False,
+ contact=False,
+ mutual_contact=False,
+ deleted=False,
+ bot=False,
+ bot_chat_history=False,
+ bot_nochats=False,
+ verified=False,
+ restricted=False,
+ min=False,
+ bot_inline_geo=False,
+ access_hash=123456789012345678,
+ first_name='Lonami',
+ last_name=None,
+ username='Lonami',
+ phone=None,
+ photo=UserProfilePhoto(
+ photo_id=123456789012345678,
+ photo_small=FileLocation(
+ dc_id=4,
+ volume_id=123456789,
+ local_id=123456789,
+ secret=-123456789012345678
+ ),
+ photo_big=FileLocation(
+ dc_id=4,
+ volume_id=123456789,
+ local_id=123456789,
+ secret=123456789012345678
+ )
+ ),
+ status=UserStatusOffline(
+ was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
+ ),
+ bot_info_version=None,
+ restriction_reason=None,
+ bot_inline_placeholder=None,
+ lang_code=None
+ )
+
+Now it's easy to see how we could get, for example,
+the ``was_online`` time. It's inside ``status``:
+
+.. code-block:: python
+
+ online_at = user.status.was_online
+
+You don't need to print everything to see what all the possible values
+can be. You can just search in http://lonamiwebs.github.io/Telethon/.
+
+Remember that you can use Python's `isinstance
+`_
+to check the type of something. For example:
+
+.. code-block:: python
+
+ from telethon import types
+
+ if isinstance(user.status, types.UserStatusOffline):
+ print(user.status.was_online)
diff --git a/readthedocs/concepts/updates.rst b/readthedocs/concepts/updates.rst
new file mode 100644
index 00000000..aec75094
--- /dev/null
+++ b/readthedocs/concepts/updates.rst
@@ -0,0 +1,229 @@
+================
+Updates in Depth
+================
+
+Properties vs. Methods
+======================
+
+The event shown above acts just like a `custom.Message
+`, which means you
+can access all the properties it has, like ``.sender``.
+
+**However** events are different to other methods in the client, like
+`client.get_messages `.
+Events *may not* send information about the sender or chat, which means it
+can be ``None``, but all the methods defined in the client always have this
+information so it doesn't need to be re-fetched. For this reason, you have
+``get_`` methods, which will make a network call if necessary.
+
+In short, you should do this:
+
+.. code-block:: python
+
+ @client.on(events.NewMessage)
+ async def handler(event):
+ # event.input_chat may be None, use event.get_input_chat()
+ chat = await event.get_input_chat()
+ sender = await event.get_sender()
+ buttons = await event.get_buttons()
+
+ async def main():
+ async for message in client.iter_messages('me', 10):
+ # Methods from the client always have these properties ready
+ chat = message.input_chat
+ sender = message.sender
+ buttons = message.buttons
+
+Notice, properties (`message.sender
+`) don't need an ``await``, but
+methods (`message.get_sender
+`) **do** need an ``await``,
+and you should use methods in events for these properties that may need network.
+
+Events Without the client
+=========================
+
+The code of your application starts getting big, so you decide to
+separate the handlers into different files. But how can you access
+the client from these files? You don't need to! Just `events.register
+` them:
+
+.. code-block:: python
+
+ # handlers/welcome.py
+ from telethon import events
+
+ @events.register(events.NewMessage('(?i)hello'))
+ async def handler(event):
+ client = event.client
+ await event.respond('Hey!')
+ await client.send_message('me', 'I said hello to someone')
+
+
+Registering events is a way of saying "this method is an event handler".
+You can use `telethon.events.is_handler` to check if any method is a handler.
+You can think of them as a different approach to Flask's blueprints.
+
+It's important to note that this does **not** add the handler to any client!
+You never specified the client on which the handler should be used. You only
+declared that it is a handler, and its type.
+
+To actually use the handler, you need to `client.add_event_handler
+` to the
+client (or clients) where they should be added to:
+
+.. code-block:: python
+
+ # main.py
+ from telethon import TelegramClient
+ import handlers.welcome
+
+ with TelegramClient(...) as client:
+ client.add_event_handler(handlers.welcome.handler)
+ client.run_until_disconnected()
+
+
+This also means that you can register an event handler once and
+then add it to many clients without re-declaring the event.
+
+
+Events Without Decorators
+=========================
+
+If for any reason you don't want to use `telethon.events.register`,
+you can explicitly pass the event handler to use to the mentioned
+`client.add_event_handler
+`:
+
+.. code-block:: python
+
+ from telethon import TelegramClient, events
+
+ async def handler(event):
+ ...
+
+ with TelegramClient(...) as client:
+ client.add_event_handler(handler, events.NewMessage)
+ client.run_until_disconnected()
+
+
+Similarly, you also have `client.remove_event_handler
+`
+and `client.list_event_handlers
+`.
+
+The ``event`` argument is optional in all three methods and defaults to
+`events.Raw ` for adding, and ``None`` when
+removing (so all callbacks would be removed).
+
+.. note::
+
+ The ``event`` type is ignored in `client.add_event_handler
+ `
+ if you have used `telethon.events.register` on the ``callback``
+ before, since that's the point of using such method at all.
+
+
+Stopping Propagation of Updates
+===============================
+
+There might be cases when an event handler is supposed to be used solitary and
+it makes no sense to process any other handlers in the chain. For this case,
+it is possible to raise a `telethon.events.StopPropagation` exception which
+will cause the propagation of the update through your handlers to stop:
+
+.. code-block:: python
+
+ from telethon.events import StopPropagation
+
+ @client.on(events.NewMessage)
+ async def _(event):
+ # ... some conditions
+ await event.delete()
+
+ # Other handlers won't have an event to work with
+ raise StopPropagation
+
+ @client.on(events.NewMessage)
+ async def _(event):
+ # Will never be reached, because it is the second handler
+ # in the chain.
+ pass
+
+
+Remember to check :ref:`telethon-events` if you're looking for
+the methods reference.
+
+Understanding asyncio
+=====================
+
+
+With ``asyncio``, the library has several tasks running in the background.
+One task is used for sending requests, another task is used to receive them,
+and a third one is used to handle updates.
+
+To handle updates, you must keep your script running. You can do this in
+several ways. For instance, if you are *not* running ``asyncio``'s event
+loop, you should use `client.run_until_disconnected
+`:
+
+.. code-block:: python
+
+ import asyncio
+ from telethon import TelegramClient
+
+ client = TelegramClient(...)
+ ...
+ client.run_until_disconnected()
+
+
+Behind the scenes, this method is ``await``'ing on the `client.disconnected
+` property,
+so the code above and the following are equivalent:
+
+.. code-block:: python
+
+ import asyncio
+ from telethon import TelegramClient
+
+ client = TelegramClient(...)
+
+ async def main():
+ await client.disconnected
+
+ loop = asyncio.get_event_loop()
+ loop.run_until_complete(main())
+
+
+You could also run `client.disconnected
+`
+until it completed.
+
+But if you don't want to ``await``, then you should know what you want
+to be doing instead! What matters is that you shouldn't let your script
+die. If you don't care about updates, you don't need any of this.
+
+Notice that unlike `client.disconnected
+`,
+`client.run_until_disconnected
+` will
+handle ``KeyboardInterrupt`` with you. This method is special and can
+also be ran while the loop is running, so you can do this:
+
+.. code-block:: python
+
+ async def main():
+ await client.run_until_disconnected()
+
+ loop.run_until_complete(main())
+
+Sequential Updates
+==================
+
+If you need to process updates sequentially (i.e. not in parallel),
+you should set ``sequential_updates=True`` when creating the client:
+
+.. code-block:: python
+
+ with TelegramClient(..., sequential_updates=True) as client:
+ ...
diff --git a/readthedocs/conf.py b/readthedocs/conf.py
index 9c04cc47..ed57f537 100644
--- a/readthedocs/conf.py
+++ b/readthedocs/conf.py
@@ -61,7 +61,7 @@ master_doc = 'index'
# General information about the project.
project = 'Telethon'
-copyright = '2017, Lonami'
+copyright = '2017 - 2019, Lonami'
author = 'Lonami'
# The version info for the project you're documenting, acts as replacement for
diff --git a/readthedocs/extra/developing/coding-style.rst b/readthedocs/developing/coding-style.rst
similarity index 100%
rename from readthedocs/extra/developing/coding-style.rst
rename to readthedocs/developing/coding-style.rst
diff --git a/readthedocs/extra/developing/philosophy.rst b/readthedocs/developing/philosophy.rst
similarity index 100%
rename from readthedocs/extra/developing/philosophy.rst
rename to readthedocs/developing/philosophy.rst
diff --git a/readthedocs/extra/developing/project-structure.rst b/readthedocs/developing/project-structure.rst
similarity index 98%
rename from readthedocs/extra/developing/project-structure.rst
rename to readthedocs/developing/project-structure.rst
index c96a243b..960234ac 100644
--- a/readthedocs/extra/developing/project-structure.rst
+++ b/readthedocs/developing/project-structure.rst
@@ -4,7 +4,7 @@ Project Structure
Main interface
-**************
+==============
The library itself is under the ``telethon/`` directory. The
``__init__.py`` file there exposes the main ``TelegramClient``, a class
@@ -34,7 +34,7 @@ which outgoing messages should be sent (how to encode their length and
their body, if they're further encrypted).
Auto-generated code
-*******************
+===================
The files under ``telethon_generator/`` are used to generate the code
that gets placed under ``telethon/tl/``. The parsers take in files in
diff --git a/readthedocs/extra/developing/telegram-api-in-other-languages.rst b/readthedocs/developing/telegram-api-in-other-languages.rst
similarity index 98%
rename from readthedocs/extra/developing/telegram-api-in-other-languages.rst
rename to readthedocs/developing/telegram-api-in-other-languages.rst
index 22bb416a..d77ebaa9 100644
--- a/readthedocs/extra/developing/telegram-api-in-other-languages.rst
+++ b/readthedocs/developing/telegram-api-in-other-languages.rst
@@ -19,7 +19,7 @@ there by `@vysheng `__,
has been moved to `BitBucket `__.
C++
-***
+===
The newest (and official) library, written from scratch, is called
`tdlib `__ and is what the Telegram X
@@ -27,7 +27,7 @@ uses. You can find more information in the official documentation,
published `here `__.
JavaScript
-**********
+==========
`@zerobias `__ is working on
`telegram-mtproto `__,
@@ -35,7 +35,7 @@ a work-in-progress JavaScript library installable via
`npm `__.
Kotlin
-******
+======
`Kotlogram `__ is a Telegram
implementation written in Kotlin (one of the
@@ -46,7 +46,7 @@ languages for
yet working.
PHP
-***
+===
A PHP implementation is also available thanks to
`@danog `__ and his
@@ -55,7 +55,7 @@ a very nice `online
documentation `__ too.
Python
-******
+======
A fairly new (as of the end of 2017) Telegram library written from the
ground up in Python by
@@ -66,7 +66,7 @@ sad to see you go, but it would be nice to know what you miss from each
other library in either one so both can improve.
Rust
-****
+====
Yet another work-in-progress implementation, this time for Rust thanks
to `@JuanPotato `__ under the fancy
diff --git a/readthedocs/extra/developing/test-servers.rst b/readthedocs/developing/test-servers.rst
similarity index 100%
rename from readthedocs/extra/developing/test-servers.rst
rename to readthedocs/developing/test-servers.rst
diff --git a/readthedocs/extra/developing/tips-for-porting-the-project.rst b/readthedocs/developing/tips-for-porting-the-project.rst
similarity index 100%
rename from readthedocs/extra/developing/tips-for-porting-the-project.rst
rename to readthedocs/developing/tips-for-porting-the-project.rst
diff --git a/readthedocs/extra/developing/understanding-the-type-language.rst b/readthedocs/developing/understanding-the-type-language.rst
similarity index 100%
rename from readthedocs/extra/developing/understanding-the-type-language.rst
rename to readthedocs/developing/understanding-the-type-language.rst
diff --git a/readthedocs/extra/examples/chats-and-channels.rst b/readthedocs/examples/chats-and-channels.rst
similarity index 95%
rename from readthedocs/extra/examples/chats-and-channels.rst
rename to readthedocs/examples/chats-and-channels.rst
index 33d06d85..c764d2b7 100644
--- a/readthedocs/extra/examples/chats-and-channels.rst
+++ b/readthedocs/examples/chats-and-channels.rst
@@ -5,13 +5,13 @@ Working with Chats and Channels
.. note::
- These examples assume you have read :ref:`accessing-the-full-api`.
+ These examples assume you have read :ref:`full-api`.
.. contents::
Joining a chat or channel
-*************************
+=========================
Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a
special form of :tl:`Chat`, which can also be super-groups if
@@ -19,7 +19,7 @@ their ``megagroup`` member is ``True``.
Joining a public channel
-************************
+========================
Once you have the :ref:`entity ` of the channel you want to join
to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
@@ -41,7 +41,7 @@ __ https://lonamiwebs.github.io/Telethon/methods/channels/index.html
Joining a private chat or channel
-*********************************
+=================================
If all you have is a link like this one:
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
@@ -57,7 +57,7 @@ example, is the ``hash`` of the chat or channel. Now you can use
Adding someone else to such chat or channel
-*******************************************
+===========================================
If you don't want to add yourself, maybe because you're already in,
you can always add someone else with the :tl:`AddChatUserRequest`, which
@@ -86,7 +86,7 @@ use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
Checking a link without joining
-*******************************
+===============================
If you don't need to join but rather check whether it's a group or a
channel, you can use the :tl:`CheckChatInviteRequest`, which takes in
@@ -94,7 +94,7 @@ the hash of said channel or group.
Admin Permissions
-*****************
+=================
Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`:
@@ -152,7 +152,7 @@ Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`
Restricting Users
-*****************
+=================
Similar to how you give or revoke admin permissions, you can edit the
banned rights of a user through :tl:`EditBannedRequest` and its parameter
@@ -203,7 +203,7 @@ https://core.telegram.org/bots/api#restrictchatmember.
Kicking a member
-****************
+================
Telegram doesn't actually have a request to kick a user from a group.
Instead, you need to restrict them so they can't see messages. Any date
@@ -228,7 +228,7 @@ __ https://lonamiwebs.github.io/Telethon/constructors/channel_admin_rights.html
Increasing View Count in a Channel
-**********************************
+==================================
It has been asked `quite`__ `a few`__ `times`__ (really, `many`__), and
while I don't understand why so many people ask this, the solution is to
diff --git a/readthedocs/extra/examples/projects-using-telethon.rst b/readthedocs/examples/projects-using-telethon.rst
similarity index 62%
rename from readthedocs/extra/examples/projects-using-telethon.rst
rename to readthedocs/examples/projects-using-telethon.rst
index 122e02a7..7b7be2c1 100644
--- a/readthedocs/extra/examples/projects-using-telethon.rst
+++ b/readthedocs/examples/projects-using-telethon.rst
@@ -1,3 +1,5 @@
+.. _telethon_projects:
+
=======================
Projects using Telethon
=======================
@@ -15,10 +17,10 @@ the library.
.. _projects-telegram-export:
telethon_examples/
-******************
+==================
-`Link `_ /
-`Author's website `_
+`telethon_examples `_ /
+`LonamiWebs' site `_
This documentation is not the only place where you can find useful code
snippets using the library. The main repository also has a folder with
@@ -26,10 +28,10 @@ some cool examples (even a Tkinter GUI!) which you can download, edit
and run to learn and play with them.
telegram-export
-***************
+===============
-`Link `_ /
-`Author's website `_
+`telegram-export `_ /
+`expectocode's GitHub `_
A tool to download Telegram data (users, chats, messages, and media)
into a database (and display the saved data).
@@ -37,28 +39,28 @@ into a database (and display the saved data).
.. _projects-mautrix-telegram:
mautrix-telegram
-****************
+================
-`Link `_ /
-`Author's website `_
+`mautrix-telegram `_ /
+`maunium's site `_
A Matrix-Telegram hybrid puppeting/relaybot bridge.
.. _projects-telegramtui:
TelegramTUI
-***********
+===========
-`Link `_ /
-`Author's website `_
+`TelegramTUI `_ /
+`bad-day's GitHub `_
A Telegram client on your terminal.
spotify_telegram_bio_updater
-****************************
+============================
-`Link `_ /
-`Author's website `_
+`spotify_telegram_bio_updater `_ /
+`pooltalks' Telegram `_
Small project that updates the biography of a telegram user according
to their current Spotify playback, or revert it if no playback is active.
diff --git a/readthedocs/extra/examples/users.rst b/readthedocs/examples/users.rst
similarity index 88%
rename from readthedocs/extra/examples/users.rst
rename to readthedocs/examples/users.rst
index 54cae92c..130bd7ae 100644
--- a/readthedocs/extra/examples/users.rst
+++ b/readthedocs/examples/users.rst
@@ -5,13 +5,13 @@ Users
.. note::
- These examples assume you have read :ref:`accessing-the-full-api`.
+ These examples assume you have read :ref:`full-api`.
.. contents::
Retrieving full information
-***************************
+===========================
If you need to retrieve the bio, biography or about information for a user
you should use :tl:`GetFullUser`:
@@ -32,7 +32,7 @@ See :tl:`UserFull` to know what other fields you can access.
Updating your name and/or bio
-*****************************
+=============================
The first name, last name and bio (about) can all be changed with the same
request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
@@ -47,7 +47,7 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
Updating your username
-**********************
+======================
You need to use :tl:`account.UpdateUsername`:
@@ -59,7 +59,7 @@ You need to use :tl:`account.UpdateUsername`:
Updating your profile photo
-***************************
+===========================
The easiest way is to upload a new file and use that as the profile photo
through :tl:`UploadProfilePhoto`:
diff --git a/readthedocs/examples/word-of-warning.rst b/readthedocs/examples/word-of-warning.rst
new file mode 100644
index 00000000..5501325f
--- /dev/null
+++ b/readthedocs/examples/word-of-warning.rst
@@ -0,0 +1,16 @@
+=================
+A Word of Warning
+=================
+
+Full API is **not** how you are intended to use the library. You **should**
+always prefer the :ref:`client-ref`. However, not everything is implemented
+as a friendly method, so full API is your last resort.
+
+If you select a method in :ref:`client-ref`, you will most likely find an
+example for that method. This is how you are intended to use the library.
+
+Full API **will** break between different minor versions of the library,
+since Telegram changes very often. The friendly methods will be kept
+compatible between major versions.
+
+If you need to see real-world examples, please refer to :ref:`telethon_projects`.
diff --git a/readthedocs/extra/examples/working-with-messages.rst b/readthedocs/examples/working-with-messages.rst
similarity index 93%
rename from readthedocs/extra/examples/working-with-messages.rst
rename to readthedocs/examples/working-with-messages.rst
index 08b47c8e..e08e4cf0 100644
--- a/readthedocs/extra/examples/working-with-messages.rst
+++ b/readthedocs/examples/working-with-messages.rst
@@ -5,13 +5,13 @@ Working with messages
.. note::
- These examples assume you have read :ref:`accessing-the-full-api`.
+ These examples assume you have read :ref:`full-api`.
.. contents::
Sending stickers
-****************
+================
Stickers are nothing else than ``files``, and when you successfully retrieve
the stickers for a certain sticker set, all you will have are ``handles`` to
diff --git a/readthedocs/extra/advanced-usage/mastering-telethon.rst b/readthedocs/extra/advanced-usage/mastering-telethon.rst
deleted file mode 100644
index 60803db4..00000000
--- a/readthedocs/extra/advanced-usage/mastering-telethon.rst
+++ /dev/null
@@ -1,343 +0,0 @@
-.. _mastering-telethon:
-
-==================
-Mastering Telethon
-==================
-
-You've come far! In this section you will learn best practices, as well
-as how to fix some silly (yet common) errors you may have found. Let's
-start with a simple one.
-
-Asyncio madness
-***************
-
-We promise ``asyncio`` is worth learning. Take your time to learn it.
-It's a powerful tool that enables you to use this powerful library.
-You need to be comfortable with it if you want to master Telethon.
-
-.. code-block:: text
-
- AttributeError: 'coroutine' object has no attribute 'id'
-
-You probably had a previous version, upgraded, and expected everything
-to work. Remember, just add this line:
-
-.. code-block:: python
-
- import telethon.sync
-
-If you're inside an event handler you need to ``await`` **everything** that
-*makes a network request*. Getting users, sending messages, and nearly
-everything in the library needs access to the network, so they need to
-be awaited:
-
-.. code-block:: python
-
- @client.on(events.NewMessage)
- async def handler(event):
- print((await event.get_sender()).username)
-
-
-You may want to read https://lonamiwebs.github.io/blog/asyncio/ to help
-you understand ``asyncio`` better. I'm open for `feedback
-`_ regarding that blog post
-
-Entities
-********
-
-A lot of methods and requests require *entities* to work. For example,
-you send a message to an *entity*, get the username of an *entity*, and
-so on. There is an entire section on this at :ref:`entities` due to their
-importance.
-
-There are a lot of things that work as entities: usernames, phone numbers,
-chat links, invite links, IDs, and the types themselves. That is, you can
-use any of those when you see an "entity" is needed.
-
-.. note::
-
- Remember that the phone number must be in your contact list before you
- can use it.
-
-You should use, **from better to worse**:
-
-1. Input entities. For example, `event.input_chat
- `,
- `message.input_sender
- `,
- or caching an entity you will use a lot with
- ``entity = await client.get_input_entity(...)``.
-
-2. Entities. For example, if you had to get someone's
- username, you can just use ``user`` or ``channel``.
- It will work. Only use this option if you already have the entity!
-
-3. IDs. This will always look the entity up from the
- cache (the ``*.session`` file caches seen entities).
-
-4. Usernames, phone numbers and links. The cache will be
- used too (unless you force a `client.get_entity()
- `),
- but may make a request if the username, phone or link
- has not been found yet.
-
-In short, unlike in most bot API libraries where you use the ID, you
-**should not** use the ID *if* you have the input entity. This is OK:
-
-.. code-block:: python
-
- async def handler(event):
- await client.send_message(event.sender_id, 'Hi')
-
-However, **this is better**:
-
-.. code-block:: python
-
- async def handler(event):
- await client.send_message(event.input_sender, 'Hi')
-
-Note that this also works for `message `
-instead of ``event``. Telegram may not send the sender information, so if you
-want to be 99% confident that the above will work you should do this:
-
-.. code-block:: python
-
- async def handler(event):
- await client.send_message(await event.get_input_sender(), 'Hi')
-
-Methods are able to make network requests to get information that
-could be missing. Properties will never make a network request.
-
-Of course, it is convenient to IDs or usernames for most purposes. It will
-be fast enough and caching with `client.get_input_entity(...)
-` will
-be a micro-optimization. However it's worth knowing, and it
-will also let you know if the entity cannot be found beforehand.
-
-.. note::
-
- Sometimes Telegram doesn't send the access hash inside entities,
- so using `chat `
- or `sender `
- may not work, but `input_chat
- `
- and `input_sender
- `
- while making requests definitely will since that's what they exist
- for. If Telegram did not send information about the access hash,
- you will get something like "Invalid channel object" or
- "Invalid user object".
-
-
-Debugging
-*********
-
-**Please enable logging**:
-
-.. code-block:: python
-
- import logging
- logging.basicConfig(level=logging.WARNING)
-
-Change it for ``logging.DEBUG`` if you are asked for logs. It will save you
-a lot of headaches and time when you work with events. This is for errors.
-
-Debugging is *really* important. Telegram's API is really big and there
-is a lot of things that you should know. Such as, what attributes or fields
-does a result have? Well, the easiest thing to do is printing it:
-
-.. code-block:: python
-
- user = client.get_entity('Lonami')
- print(user)
-
-That will show a huge line similar to the following:
-
-.. code-block:: python
-
- User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
-
-That's a lot of text. But as you can see, all the properties are there.
-So if you want the username you **don't use regex** or anything like
-splitting ``str(user)`` to get what you want. You just access the
-attribute you need:
-
-.. code-block:: python
-
- username = user.username
-
-Can we get better than the shown string, though? Yes!
-
-.. code-block:: python
-
- print(user.stringify())
-
-Will show a much better:
-
-.. code-block:: python
-
- User(
- id=10885151,
- is_self=False,
- contact=False,
- mutual_contact=False,
- deleted=False,
- bot=False,
- bot_chat_history=False,
- bot_nochats=False,
- verified=False,
- restricted=False,
- min=False,
- bot_inline_geo=False,
- access_hash=123456789012345678,
- first_name='Lonami',
- last_name=None,
- username='Lonami',
- phone=None,
- photo=UserProfilePhoto(
- photo_id=123456789012345678,
- photo_small=FileLocation(
- dc_id=4,
- volume_id=123456789,
- local_id=123456789,
- secret=-123456789012345678
- ),
- photo_big=FileLocation(
- dc_id=4,
- volume_id=123456789,
- local_id=123456789,
- secret=123456789012345678
- )
- ),
- status=UserStatusOffline(
- was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
- ),
- bot_info_version=None,
- restriction_reason=None,
- bot_inline_placeholder=None,
- lang_code=None
- )
-
-Now it's easy to see how we could get, for example,
-the ``was_online`` time. It's inside ``status``:
-
-.. code-block:: python
-
- online_at = user.status.was_online
-
-You don't need to print everything to see what all the possible values
-can be. You can just search in http://lonamiwebs.github.io/Telethon/.
-
-Remember that you can use Python's `isinstance
-`_
-to check the type of something. For example:
-
-.. code-block:: python
-
- from telethon import types
-
- if isinstance(user.status, types.UserStatusOffline):
- print(user.status.was_online)
-
-Avoiding Limits
-***************
-
-Don't spam. You won't get ``FloodWaitError`` or your account banned or
-deleted if you use the library *for legit use cases*. Make cool tools.
-Don't spam! Nobody knows the exact limits for all requests since they
-depend on a lot of factors, so don't bother asking.
-
-Still, if you do have a legit use case and still get those errors, the
-library will automatically sleep when they are smaller than 60 seconds
-by default. You can set different "auto-sleep" thresholds:
-
-.. code-block:: python
-
- client.flood_sleep_threshold = 0 # Don't auto-sleep
- client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
-
-You can also except it and act as you prefer:
-
-.. code-block:: python
-
- from telethon.errors import FloodWaitError
- try:
- ...
- except FloodWaitError as e:
- print('Flood waited for', e.seconds)
- quit(1)
-
-VoIP numbers are very limited, and some countries are more limited too.
-
-Chat or User From Messages
-**************************
-
-Although it's explicitly noted in the documentation that messages
-*subclass* `ChatGetter `
-and `SenderGetter `,
-some people still don't get inheritance.
-
-When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
-it means that the class you're looking at, *also* can act as the class it
-bases. In this case, `ChatGetter `
-knows how to get the *chat* where a thing belongs to.
-
-So, a `Message ` is a
-`ChatGetter `.
-That means you can do this:
-
-.. code-block:: python
-
- message.is_private
- message.chat_id
- message.get_chat()
- # ...etc
-
-`SenderGetter ` is similar:
-
-.. code-block:: python
-
- message.user_id
- message.get_input_user()
- message.user
- # ...etc
-
-Quite a few things implement them, so it makes sense to reuse the code.
-For example, all events (except raw updates) implement `ChatGetter
-` since all events occur
-in some chat.
-
-Session Files
-*************
-
-They are an important part for the library to be efficient, such as caching
-and handling your authorization key (or you would have to login every time!).
-
-However, some people have a lot of trouble with SQLite, especially in Windows:
-
-.. code-block:: text
-
- ...some lines of traceback
- 'insert or replace into entities values (?,?,?,?,?)', rows)
- sqlite3.OperationalError: database is locked
-
-This error occurs when **two or more clients use the same session**,
-that is, when you write the same session name to be used in the client:
-
-* You have two scripts running (interactive sessions count too).
-* You have two clients in the same script running at the same time.
-
-The solution is, if you need two clients, use two sessions. If the
-problem persists and you're on Linux, you can use ``fuser my.session``
-to find out the process locking the file. As a last resort, you can
-reboot your system.
-
-If you really dislike SQLite, use a different session storage. There
-is an entire section covering that at :ref:`sessions`.
-
-Final Words
-***********
-
-Now you are aware of some common errors and use cases, this should help
-you master your Telethon skills to get the most out of the library. Have
-fun developing awesome things!
diff --git a/readthedocs/extra/advanced-usage/update-modes.rst b/readthedocs/extra/advanced-usage/update-modes.rst
deleted file mode 100644
index d8950834..00000000
--- a/readthedocs/extra/advanced-usage/update-modes.rst
+++ /dev/null
@@ -1,73 +0,0 @@
-.. _update-modes:
-
-============
-Update Modes
-============
-
-With ``asyncio``, the library has several tasks running in the background.
-One task is used for sending requests, another task is used to receive them,
-and a third one is used to handle updates.
-
-To handle updates, you must keep your script running. You can do this in
-several ways. For instance, if you are *not* running ``asyncio``'s event
-loop, you should use `client.run_until_disconnected
-`:
-
-.. code-block:: python
-
- import asyncio
- from telethon import TelegramClient
-
- client = TelegramClient(...)
- ...
- client.run_until_disconnected()
-
-
-Behind the scenes, this method is ``await``'ing on the `client.disconnected
-` property,
-so the code above and the following are equivalent:
-
-.. code-block:: python
-
- import asyncio
- from telethon import TelegramClient
-
- client = TelegramClient(...)
-
- async def main():
- await client.disconnected
-
- loop = asyncio.get_event_loop()
- loop.run_until_complete(main())
-
-
-You could also run `client.disconnected
-`
-until it completed.
-
-But if you don't want to ``await``, then you should know what you want
-to be doing instead! What matters is that you shouldn't let your script
-die. If you don't care about updates, you don't need any of this.
-
-Notice that unlike `client.disconnected
-`,
-`client.run_until_disconnected
-` will
-handle ``KeyboardInterrupt`` with you. This method is special and can
-also be ran while the loop is running, so you can do this:
-
-.. code-block:: python
-
- async def main():
- await client.run_until_disconnected()
-
- loop.run_until_complete(main())
-
-
-If you need to process updates sequentially (i.e. not in parallel),
-you should set ``sequential_updates=True`` when creating the client:
-
-.. code-block:: python
-
- with TelegramClient(..., sequential_updates=True) as client:
- ...
diff --git a/readthedocs/extra/basic/creating-a-client.rst b/readthedocs/extra/basic/creating-a-client.rst
deleted file mode 100644
index 8416e3b5..00000000
--- a/readthedocs/extra/basic/creating-a-client.rst
+++ /dev/null
@@ -1,263 +0,0 @@
-.. _creating-a-client:
-
-=================
-Creating a Client
-=================
-
-
-Before working with Telegram's API, you need to get your own API ID and hash:
-
-1. Follow `this link `_ and login with your
- phone number.
-
-2. Click under API Development tools.
-
-3. A *Create new application* window will appear. Fill in your application
- details. There is no need to enter any *URL*, and only the first two
- fields (*App title* and *Short name*) can currently be changed later.
-
-4. Click on *Create application* at the end. Remember that your
- **API hash is secret** and Telegram won't let you revoke it.
- Don't post it anywhere!
-
-Once that's ready, the next step is to create a ``TelegramClient``.
-This class will be your main interface with Telegram's API, and creating
-one is very simple:
-
-.. code-block:: python
-
- from telethon import TelegramClient, sync
-
- # Use your own values here
- api_id = 12345
- api_hash = '0123456789abcdef0123456789abcdef'
-
- client = TelegramClient('some_name', api_id, api_hash)
-
-
-Note that ``'some_name'`` will be used to save your session (persistent
-information such as access key and others) as ``'some_name.session'`` in
-your disk. This is by default a database file using Python's ``sqlite3``.
-
-.. note::
-
- It's important that the library always accesses the same session file so
- that you don't need to re-send the code over and over again. By default it
- creates the file in your working directory, but absolute paths work too.
-
-
-Once you have a client ready, simply `.start()
-` it:
-
-.. code-block:: python
-
- client.start()
-
-This line connects to Telegram, checks whether the current user is
-authorized or not, and if it's not, it begins the login or sign up process.
-
-When you're done with your code, you should always disconnect:
-
-.. code-block:: python
-
- client = TelegramClient(...)
- try:
- client.start()
- ... # your code here
- finally:
- client.disconnect()
-
-
-You can also use a ``with`` block to achieve the same effect:
-
-.. code-block:: python
-
- client = TelegramClient(...)
- with client:
- ... # your code here
-
- # or
- with TelegramClient(...) as client:
- ... # your code here
-
-
-Wrapping it all together:
-
-.. code-block:: python
-
- from telethon import TelegramClient, sync
- with TelegramClient('session_name', api_id, api_hash) as client:
- ... # your code
-
-Just two setup lines.
-
-.. warning::
- Please note that if you fail to login around 5 times (or change the first
- parameter of the :ref:`TelegramClient `, which is the session
- name) you will receive a ``FloodWaitError`` of around 22 hours, so be
- careful not to mess this up! This shouldn't happen if you're doing things
- as explained, though.
-
-.. note::
- If you want to use a **proxy**, you have to `install PySocks`__
- (via pip or manual) and then set the appropriated parameters:
-
- .. code-block:: python
-
- import socks
- client = TelegramClient('session_id',
- api_id=12345, api_hash='0123456789abcdef0123456789abcdef',
- proxy=(socks.SOCKS5, 'localhost', 4444)
- )
-
- The ``proxy=`` argument should be a tuple, a list or a dict,
- consisting of parameters described `here`__.
-
-
-Manually Signing In
-*******************
-
-.. note::
-
- Skip this unless you need more control when connecting.
-
-If you need more control, you can replicate what `client.start()
-` is doing behind the scenes
-for your convenience. The first step is to connect to the servers:
-
-.. code-block:: python
-
- client.connect()
-
-You may or may not be authorized yet. You must be authorized
-before you're able to send any request:
-
-.. code-block:: python
-
- client.is_user_authorized() # Returns True if you can send requests
-
-If you're not authorized, you need to `.sign_in
-`:
-
-.. code-block:: python
-
- phone_number = '+34600000000'
- client.send_code_request(phone_number)
- myself = client.sign_in(phone_number, input('Enter code: '))
- # If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
- # If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
- # You can import both exceptions from telethon.errors.
-
-.. note::
-
- If you send the code that Telegram sent you over the app through the
- app itself, it will expire immediately. You can still send the code
- through the app by "obfuscating" it (maybe add a magic constant, like
- ``12345``, and then subtract it to get the real code back) or any other
- technique.
-
-``myself`` is your Telegram user. You can view all the information about
-yourself by doing ``print(myself.stringify())``. You're now ready to use
-the client as you wish! Remember that any object returned by the API has
-mentioned ``.stringify()`` method, and printing these might prove useful.
-
-As a full example:
-
-.. code-block:: python
-
- from telethon import TelegramClient, sync
- client = TelegramClient('session_name', api_id, api_hash)
-
- client.connect()
- if not client.is_user_authorized():
- client.send_code_request(phone_number)
- me = client.sign_in(phone_number, input('Enter code: '))
-
-
-Remember that this is the manual process and it's so much easier
-to use the code snippets shown at the beginning of the page.
-
-The code shown is just what `.start()
-` will be doing behind the scenes
-(with a few extra checks), so that you know how to sign in case you want
-to avoid using ``input()`` (the default) for whatever reason. If no phone
-or bot token is provided, you will be asked one through ``input()``. The
-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()
-`.
-
-
-Two Factor Authorization (2FA)
-------------------------------
-
-If you have Two Factor Authorization (from now on, 2FA) enabled on your
-account, calling `.sign_in()
-` will raise a
-``SessionPasswordNeededError``. When this happens, just use the method
-again with a ``password=``:
-
-.. code-block:: python
-
- import getpass
- from telethon.errors import SessionPasswordNeededError
-
- client.sign_in(phone)
- try:
- client.sign_in(code=input('Enter code: '))
- except SessionPasswordNeededError:
- client.sign_in(password=getpass.getpass())
-
-
-The mentioned `.start()
-` method will handle this for you as
-well, but you must set the ``password=`` parameter beforehand (it won't be
-asked).
-
-If you don't have 2FA enabled, but you would like to do so through the
-library, use `client.edit_2fa()
-`.
-
-Be sure to know what you're doing when using this function and
-you won't run into any problems. Take note that if you want to
-set only the email/hint and leave the current password unchanged,
-you need to "redo" the 2fa.
-
-See the examples below:
-
-.. code-block:: python
-
- from telethon.errors import EmailUnconfirmedError
-
- # Sets 2FA password for first time:
- client.edit_2fa(new_password='supersecurepassword')
-
- # Changes password:
- client.edit_2fa(current_password='supersecurepassword',
- new_password='changedmymind')
-
- # Clears current password (i.e. removes 2FA):
- client.edit_2fa(current_password='changedmymind', new_password=None)
-
- # Sets new password with recovery email:
- try:
- client.edit_2fa(new_password='memes and dreams',
- email='JohnSmith@example.com')
- # Raises error (you need to check your email to complete 2FA setup.)
- except EmailUnconfirmedError:
- # You can put email checking code here if desired.
- pass
-
- # Also take note that unless you remove 2FA or explicitly
- # give email parameter again it will keep the last used setting
-
- # Set hint after already setting password:
- client.edit_2fa(current_password='memes and dreams',
- new_password='memes and dreams',
- hint='It keeps you alive')
-
-__ https://github.com/Anorov/PySocks#installation
-__ https://github.com/Anorov/PySocks#usage-1
diff --git a/readthedocs/extra/basic/getting-started.rst b/readthedocs/extra/basic/getting-started.rst
deleted file mode 100644
index b54a9e46..00000000
--- a/readthedocs/extra/basic/getting-started.rst
+++ /dev/null
@@ -1,95 +0,0 @@
-.. _getting-started:
-
-
-===============
-Getting Started
-===============
-
-.. contents::
-
-
-Simple Installation
-*******************
-
-.. code-block:: sh
-
- pip3 install telethon
-
-**More details**: :ref:`installation`
-
-
-Creating a client
-*****************
-
-.. code-block:: python
-
- from telethon import TelegramClient, sync
-
- # These example values won't work. You must get your own api_id and
- # api_hash from https://my.telegram.org, under API Development.
- api_id = 12345
- api_hash = '0123456789abcdef0123456789abcdef'
-
- client = TelegramClient('session_name', api_id, api_hash).start()
-
-**More details**: :ref:`creating-a-client`
-
-
-Basic Usage
-***********
-
-.. code-block:: python
-
- # Getting information about yourself
- me = client.get_me()
- print(me.stringify())
-
- # 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')
-
- # Retrieving messages from a chat
- from telethon import utils
- for message in client.iter_messages('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(dialog.name, dialog.draft.text)
-
- # 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(),
- # or even using message.download_media():
- messages = client.get_messages('username')
- messages[0].download_media()
-
-**More details**: :ref:`telegram-client`
-
-See :ref:`telethon-client` for all available friendly methods.
-
-
-Handling Updates
-****************
-
-.. code-block:: python
-
- from telethon import events
-
- @client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
- async def handler(event):
- await event.reply('Hello!')
-
- client.run_until_disconnected()
-
-**More details**: :ref:`working-with-updates`
-
-
-----------
-
-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
deleted file mode 100644
index 003e142d..00000000
--- a/readthedocs/extra/basic/installation.rst
+++ /dev/null
@@ -1,119 +0,0 @@
-.. _installation:
-
-============
-Installation
-============
-
-.. contents::
-
-
-Automatic Installation
-**********************
-
-To install Telethon, simply do:
-
-.. code-block:: sh
-
- pip3 install telethon
-
-Needless to say, you must have Python 3 and PyPi installed in your system.
-See https://python.org and https://pypi.python.org/pypi/pip for more.
-
-If you already have the library installed, upgrade with:
-
-.. code-block:: sh
-
- pip3 install --upgrade telethon
-
-You can also install the library directly from GitHub or a fork:
-
-.. code-block:: sh
-
- # pip3 install git+https://github.com/LonamiWebs/Telethon.git
- or
- $ git clone https://github.com/LonamiWebs/Telethon.git
- $ cd Telethon/
- # pip install -Ue .
-
-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.
-
-By default the library will use a pure Python implementation for encryption,
-which can be really slow when uploading or downloading files. If you don't
-mind using a C extension, install `cryptg `__
-via ``pip`` or as an extra:
-
-.. code-block:: sh
-
- pip3 install telethon[cryptg]
-
-
-Manual Installation
-*******************
-
-1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and
- ``rsa`` (`GitHub`__ | `PyPi`__) modules:
-
- .. code-block:: sh
-
- pip3 install pyaes rsa
-
-2. Clone Telethon's GitHub repository:
-
- .. code-block:: sh
-
- git clone https://github.com/LonamiWebs/Telethon.git
-
-3. Enter the cloned repository:
-
- .. code-block:: sh
-
- cd Telethon
-
-4. Run the code generator:
-
- .. code-block:: sh
-
- python3 setup.py gen
-
-5. Done!
-
-To generate the `method documentation`__, ``python3 setup.py gen docs``.
-
-
-Optional dependencies
-*********************
-
-If pillow_ is installed, large images will be automatically resized when
-sending photos to prevent Telegram from failing with "invalid image".
-Official clients also do this.
-
-If aiohttp_ is installed, the library will be able to download
-:tl:`WebDocument` media files (otherwise you will get an error).
-
-If hachoir_ is installed, it will be used to extract metadata from files
-when sending documents. Telegram uses this information to show the song's
-performer, artist, title, duration, and for videos too (including size).
-Otherwise, they will default to empty values, and you can set the attributes
-manually.
-
-If cryptg_ is installed, encryption and decryption will be made in C instead
-of Python which will be a lot faster. If your code deals with a lot of
-updates or you are downloading/uploading a lot of files, you will notice
-a considerable speed-up (from a hundred kilobytes per second to several
-megabytes per second, if your connection allows it). If it's not installed,
-pyaes_ will be used (which is pure Python, so it's much slower).
-
-
-__ https://github.com/ricmoo/pyaes
-__ https://pypi.python.org/pypi/pyaes
-__ https://github.com/sybrenstuvel/python-rsa
-__ https://pypi.python.org/pypi/rsa/3.4.2
-__ https://lonamiwebs.github.io/Telethon
-
-.. _pillow: https://python-pillow.org
-.. _aiohttp: https://docs.aiohttp.org
-.. _hachoir: https://hachoir.readthedocs.io
-.. _cryptg: https://github.com/Lonami/cryptg
-.. _pyaes: https://github.com/ricmoo/pyaes
diff --git a/readthedocs/extra/basic/telegram-client.rst b/readthedocs/extra/basic/telegram-client.rst
deleted file mode 100644
index 9d2f5011..00000000
--- a/readthedocs/extra/basic/telegram-client.rst
+++ /dev/null
@@ -1,104 +0,0 @@
-.. _telegram-client:
-
-==============
-TelegramClient
-==============
-
-.. note::
-
- Make sure to use the friendly methods described in :ref:`telethon-client`!
- This section is just an introduction to using the client, but all the
- available methods are in the :ref:`telethon-client` reference, including
- detailed descriptions to what they do.
-
-The :ref:`TelegramClient ` is the
-central class of the library, the one you will be using most of the time. For
-this reason, it's important to know what it offers.
-
-Since we're working with Python, one must not forget that we can do
-``help(client)`` or ``help(TelegramClient)`` at any time for a more
-detailed description and a list of all the available methods. Calling
-``help()`` from an interactive Python session will always list all the
-methods for any object, even yours!
-
-Interacting with the Telegram API is done through sending **requests**,
-this is, any "method" listed on the API. There are a few methods (and
-growing!) on the :ref:`TelegramClient ` class that abstract
-you from the need of manually importing the requests you need.
-
-For instance, retrieving your own user can be done in a single line
-(assuming you have ``from telethon import sync`` or ``import telethon.sync``):
-
-.. code-block:: python
-
- myself = client.get_me()
-
-Internally, this method has sent a request to Telegram, who replied with
-the information about your own user, and then the desired information
-was extracted from their response.
-
-If you want to retrieve any other user, chat or channel (channels are a
-special subset of chats), you want to retrieve their "entity". This is
-how the library refers to either of these:
-
-.. code-block:: python
-
- # The method will infer that you've passed a username
- # It also accepts phone numbers, and will get the user
- # from your contact list.
- lonami = client.get_entity('lonami')
-
-The so called "entities" are another important whole concept on its own,
-but for now you don't need to worry about it. Simply know that they are
-a good way to get information about a user, chat or channel.
-
-Many other common methods for quick scripts are also available:
-
-.. code-block:: python
-
- # Note that you can use 'me' or 'self' to message yourself
- client.send_message('username', 'Hello World from Telethon!')
-
- # .send_message's parse mode defaults to markdown, so you
- # can use **bold**, __italics__, [links](https://example.com), `code`,
- # and even [mentions](@username)/[mentions](tg://user?id=123456789)
- client.send_message('username', '**Using** __markdown__ `too`!')
-
- client.send_file('username', '/home/myself/Pictures/holidays.jpg')
-
- # The utils package has some goodies, like .get_display_name()
- from telethon import utils
- for message in client.iter_messages('username', limit=10):
- print(utils.get_display_name(message.sender), message.message)
-
- # Dialogs are the conversations you have open
- for dialog in client.get_dialogs(limit=10):
- print(dialog.name, dialog.draft.text)
-
- # Default path is the working directory
- client.download_profile_photo('username')
-
- # Call .disconnect() when you're done
- client.disconnect()
-
-Remember that you can call ``.stringify()`` to any object Telegram returns
-to pretty print it. Calling ``str(result)`` does the same operation, but on
-a single line.
-
-
-Available methods
-*****************
-
-The :ref:`reference ` lists all the "handy" methods
-available for you to use in the :ref:`TelegramClient ` class.
-These are simply wrappers around the "raw" Telegram API, making it much more
-manageable and easier to work with.
-
-Please refer to :ref:`accessing-the-full-api` if these aren't enough,
-and don't be afraid to read the source code of the InteractiveTelegramClient_
-or even the TelegramClient_ itself to learn how it works.
-
-See the mentioned :ref:`telethon-client` to find the available methods.
-
-.. _InteractiveTelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/interactive_telegram_client.py
-.. _TelegramClient: https://github.com/LonamiWebs/Telethon/tree/master/telethon/client
diff --git a/readthedocs/extra/basic/working-with-updates.rst b/readthedocs/extra/basic/working-with-updates.rst
deleted file mode 100644
index 944317d3..00000000
--- a/readthedocs/extra/basic/working-with-updates.rst
+++ /dev/null
@@ -1,333 +0,0 @@
-.. _working-with-updates:
-
-====================
-Working with Updates
-====================
-
-.. important::
-
- Coming from Telethon before it reached its version 1.0?
- Make sure to read :ref:`compatibility-and-convenience`!
- Otherwise, you can ignore this note and just follow along.
-
-The library comes with the `telethon.events` module. *Events* are an abstraction
-over what Telegram calls `updates`__, and are meant to ease simple and common
-usage when dealing with them, since there are many updates. If you're looking
-for the method reference, check :ref:`telethon-events-package`, otherwise,
-let's dive in!
-
-
-.. important::
-
- The library logs by default no output, and any exception that occurs
- inside your handlers will be "hidden" from you to prevent the thread
- from terminating (so it can still deliver events). You should enable
- logging when working with events, at least the error level, to see if
- this is happening so you can debug the error.
-
- **When using updates, please enable logging:**
-
- .. code-block:: python
-
- import logging
- logging.basicConfig(level=logging.ERROR)
-
-
-.. contents::
-
-
-Getting Started
-***************
-
-.. code-block:: python
-
- from telethon import TelegramClient, events
-
- client = TelegramClient('name', api_id, api_hash)
-
- @client.on(events.NewMessage)
- async def my_event_handler(event):
- if 'hello' in event.raw_text:
- await event.reply('hi!')
-
- client.start()
- client.run_until_disconnected()
-
-
-Not much, but there might be some things unclear. What does this code do?
-
-.. code-block:: python
-
- from telethon import TelegramClient, events
-
- client = TelegramClient('name', api_id, api_hash)
-
-
-This is normal creation (of course, pass session name, API ID and hash).
-Nothing we don't know already.
-
-.. code-block:: python
-
- @client.on(events.NewMessage)
-
-
-This Python decorator will attach itself to the ``my_event_handler``
-definition, and basically means that *on* a `NewMessage
-` *event*,
-the callback function you're about to define will be called:
-
-.. code-block:: python
-
- async def my_event_handler(event):
- if 'hello' in event.raw_text:
- await event.reply('hi!')
-
-
-If a `NewMessage
-` event occurs,
-and ``'hello'`` is in the text of the message, we `.reply()
-` to the event
-with a ``'hi!'`` message.
-
-Do you notice anything different? Yes! Event handlers **must** be ``async``
-for them to work, and **every method using the network** needs to have an
-``await``, otherwise, Python's ``asyncio`` will tell you that you forgot
-to do so, so you can easily add it.
-
-.. code-block:: python
-
- client.start()
- client.run_until_disconnected()
-
-
-Finally, this tells the client that we're done with our code. We run the
-``asyncio`` loop until the client starts (this is done behind the scenes,
-since the method is so common), and then we run it again until we are
-disconnected. Of course, you can do other things instead of running
-until disconnected. For this refer to :ref:`update-modes`.
-
-
-More on events
-**************
-
-The `NewMessage ` event has much
-more than what was shown. You can access the `.sender
-` of the message
-through that member, or even see if the message had `.media
-`, a `.photo
-` or a `.document
-` (which you
-could download with for example `client.download_media(event.photo)
-`.
-
-If you don't want to `.reply()
-` as a reply,
-you can use the `.respond() `
-method instead. Of course, there are more events such as `ChatAction
-` or `UserUpdate
-`, and they're all
-used in the same way. Simply add the `@client.on(events.XYZ)
-` decorator on the top
-of your handler and you're done! The event that will be passed always
-is of type ``XYZ.Event`` (for instance, `NewMessage.Event
-`), except for the `Raw
-` event which just passes the :tl:`Update` object.
-
-Note that `.reply()
-` and `.respond()
-` are just wrappers around the
-`client.send_message() `
-method which supports the ``file=`` parameter.
-This means you can reply with a photo if you do `event.reply(file=photo)
-`.
-
-You can put the same event on many handlers, and even different events on
-the same handler. You can also have a handler work on only specific chats,
-for example:
-
-
-.. code-block:: python
-
- import ast
- import random
-
-
- # Either a single item or a list of them will work for the chats.
- # You can also use the IDs, Peers, or even User/Chat/Channel objects.
- @client.on(events.NewMessage(chats=('TelethonChat', 'TelethonOffTopic')))
- async def normal_handler(event):
- if 'roll' in event.raw_text:
- await event.reply(str(random.randint(1, 6)))
-
-
- # Similarly, you can use incoming=True for messages that you receive
- @client.on(events.NewMessage(chats='TelethonOffTopic', outgoing=True,
- pattern='eval (.+)'))
- async def admin_handler(event):
- expression = event.pattern_match.group(1)
- await event.reply(str(ast.literal_eval(expression)))
-
-
-You can pass one or more chats to the ``chats`` parameter (as a list or tuple),
-and only events from there will be processed. You can also specify whether you
-want to handle incoming or outgoing messages (those you receive or those you
-send). In this example, people can say ``'roll'`` and you will reply with a
-random number, while if you say ``'eval 4+4'``, you will reply with the
-solution. Try it!
-
-
-Properties vs. Methods
-**********************
-
-The event shown above acts just like a `custom.Message
-`, which means you
-can access all the properties it has, like ``.sender``.
-
-**However** events are different to other methods in the client, like
-`client.get_messages `.
-Events *may not* send information about the sender or chat, which means it
-can be ``None``, but all the methods defined in the client always have this
-information so it doesn't need to be re-fetched. For this reason, you have
-``get_`` methods, which will make a network call if necessary.
-
-In short, you should do this:
-
-.. code-block:: python
-
- @client.on(events.NewMessage)
- async def handler(event):
- # event.input_chat may be None, use event.get_input_chat()
- chat = await event.get_input_chat()
- sender = await event.get_sender()
- buttons = await event.get_buttons()
-
- async def main():
- async for message in client.iter_messages('me', 10):
- # Methods from the client always have these properties ready
- chat = message.input_chat
- sender = message.sender
- buttons = message.buttons
-
-Notice, properties (`message.sender
-`) don't need an ``await``, but
-methods (`message.get_sender
-`) **do** need an ``await``,
-and you should use methods in events for these properties that may need network.
-
-
-Events Without the client
-*************************
-
-The code of your application starts getting big, so you decide to
-separate the handlers into different files. But how can you access
-the client from these files? You don't need to! Just `events.register
-` them:
-
-.. code-block:: python
-
- # handlers/welcome.py
- from telethon import events
-
- @events.register(events.NewMessage('(?i)hello'))
- async def handler(event):
- client = event.client
- await event.respond('Hey!')
- await client.send_message('me', 'I said hello to someone')
-
-
-Registering events is a way of saying "this method is an event handler".
-You can use `telethon.events.is_handler` to check if any method is a handler.
-You can think of them as a different approach to Flask's blueprints.
-
-It's important to note that this does **not** add the handler to any client!
-You never specified the client on which the handler should be used. You only
-declared that it is a handler, and its type.
-
-To actually use the handler, you need to `client.add_event_handler
-` to the
-client (or clients) where they should be added to:
-
-.. code-block:: python
-
- # main.py
- from telethon import TelegramClient
- import handlers.welcome
-
- with TelegramClient(...) as client:
- client.add_event_handler(handlers.welcome.handler)
- client.run_until_disconnected()
-
-
-This also means that you can register an event handler once and
-then add it to many clients without re-declaring the event.
-
-
-Events Without Decorators
-*************************
-
-If for any reason you don't want to use `telethon.events.register`,
-you can explicitly pass the event handler to use to the mentioned
-`client.add_event_handler
-`:
-
-.. code-block:: python
-
- from telethon import TelegramClient, events
-
- async def handler(event):
- ...
-
- with TelegramClient(...) as client:
- client.add_event_handler(handler, events.NewMessage)
- client.run_until_disconnected()
-
-
-Similarly, you also have `client.remove_event_handler
-`
-and `client.list_event_handlers
-`.
-
-The ``event`` argument is optional in all three methods and defaults to
-`events.Raw ` for adding, and ``None`` when
-removing (so all callbacks would be removed).
-
-.. note::
-
- The ``event`` type is ignored in `client.add_event_handler
- `
- if you have used `telethon.events.register` on the ``callback``
- before, since that's the point of using such method at all.
-
-
-Stopping Propagation of Updates
-*******************************
-
-There might be cases when an event handler is supposed to be used solitary and
-it makes no sense to process any other handlers in the chain. For this case,
-it is possible to raise a `telethon.events.StopPropagation` exception which
-will cause the propagation of the update through your handlers to stop:
-
-.. code-block:: python
-
- from telethon.events import StopPropagation
-
- @client.on(events.NewMessage)
- async def _(event):
- # ... some conditions
- await event.delete()
-
- # Other handlers won't have an event to work with
- raise StopPropagation
-
- @client.on(events.NewMessage)
- async def _(event):
- # Will never be reached, because it is the second handler
- # in the chain.
- pass
-
-
-Remember to check :ref:`telethon-events-package` if you're looking for
-the methods reference.
-
-
-__ https://lonamiwebs.github.io/Telethon/types/update.html
diff --git a/readthedocs/extra/examples/telegram-client.rst b/readthedocs/extra/examples/telegram-client.rst
deleted file mode 100644
index afc62ae2..00000000
--- a/readthedocs/extra/examples/telegram-client.rst
+++ /dev/null
@@ -1,751 +0,0 @@
-.. _telegram-client-example:
-
-
-========================
-Examples with the Client
-========================
-
-This section explores the methods defined in the :ref:`telegram-client`
-with some practical examples. The section assumes that you have imported
-the ``telethon.sync`` package and that you have a client ready to use.
-
-
-.. note::
-
- There are some very common errors (such as forgetting to add
- ``import telethon.sync``) for newcomers to ``asyncio``:
-
- .. code-block:: python
-
- # AttributeError: 'coroutine' object has no attribute 'first_name'
- print(client.get_me().first_name)
-
- # TypeError: 'AsyncGenerator' object is not iterable
- for message in client.iter_messages('me'):
- ...
-
- # RuntimeError: This event loop is already running
- with client.conversation('me') as conv:
- ...
-
- That error means you're probably inside an ``async def`` so you
- need to use:
-
- .. code-block:: python
-
- print((await client.get_me()).first_name)
- async for message in client.iter_messages('me'):
- ...
-
- async with client.conversation('me') as conv:
- ...
-
- You can of course call other ``def`` functions from your ``async def``
- event handlers, but if they need making API calls, make your own
- functions ``async def`` so you can ``await`` things:
-
- .. code-block:: python
-
- async def helper(client):
- await client.send_message('me', 'Hi')
-
- If you're not inside an ``async def`` you can enter one like so:
-
- .. code-block:: python
-
- import asyncio
- loop = asyncio.get_event_loop()
- loop.run_until_complete(my_async_def())
-
-
-.. contents::
-
-
-Authorization
-*************
-
-Starting the client is as easy as calling `client.start()
-`:
-
-.. code-block:: python
-
- client.start()
- ... # code using the client
- client.disconnect()
-
-And you can even use a ``with`` block:
-
-.. code-block:: python
-
- with client:
- ... # code using the client
-
-
-.. note::
-
- Remember we assume you have ``import telethon.sync``. You can of course
- use the library without importing it. The code would be rewritten as:
-
- .. code-block:: python
-
- import asyncio
- loop = asyncio.get_event_loop()
-
- async def main():
- await client.start()
- ...
- await client.disconnect()
-
- # or
- async with client:
- ...
-
- loop.run_until_complete(main())
-
- All methods that need access to the network (e.g. to make an API call)
- **must** be awaited (or their equivalent such as ``async for`` and
- ``async with``). You can do this yourself or you can let the library
- do it for you by using ``import telethon.sync``. With event handlers,
- you must do this yourself.
-
-The cleanest way to delete your ``*.session`` file is `client.log_out
-`. Note that you will obviously
-need to login again if you use this:
-
-.. code-block:: python
-
- # Logs out and deletes the session file; you will need to sign in again
- client.log_out()
-
- # You often simply want to disconnect. You will not need to sign in again
- client.disconnect()
-
-
-Group Chats
-***********
-
-You can easily iterate over all the :tl:`User` in a chat and
-do anything you want with them by using `client.iter_participants
-`:
-
-.. code-block:: python
-
- for user in client.iter_participants(chat):
- ... # do something with the user
-
-You can also search by their name:
-
-.. code-block:: python
-
- for user in client.iter_participants(chat, search='name'):
- ...
-
-Or by their type (e.g. if they are admin) with :tl:`ChannelParticipantsFilter`:
-
-.. code-block:: python
-
- from telethon.tl.types import ChannelParticipantsAdmins
-
- for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
- ...
-
-
-Open Conversations and Joined Channels
-**************************************
-
-The conversations you have open and the channels you have joined
-are in your "dialogs", so to get them you need to `client.get_dialogs
-`:
-
-.. code-block:: python
-
- dialogs = client.get_dialogs()
- first = dialogs[0]
- print(first.title)
-
-You can then use the dialog as if it were a peer:
-
-.. code-block:: python
-
- client.send_message(first, 'hi')
-
-
-You can access `dialog.draft ` or you can
-get them all at once without getting the dialogs:
-
-.. code-block:: python
-
- drafts = client.get_drafts()
-
-
-Downloading Media
-*****************
-
-It's easy to `download_profile_photo
-`:
-
-.. code-block:: python
-
- client.download_profile_photo(user)
-
-Or `download_media `
-from a message:
-
-.. code-block:: python
-
- client.download_media(message)
- client.download_media(message, filename)
- # or
- message.download_media()
- message.download_media(filename)
-
-Remember that these methods return the final filename where the
-media was downloaded (e.g. it may add the extension automatically).
-
-Getting Messages
-****************
-
-You can easily iterate over all the `messages
-` of a chat with `iter_messages
-`:
-
-.. code-block:: python
-
- for message in client.iter_messages(chat):
- ... # do something with the message from recent to older
-
- for message in client.iter_messages(chat, reverse=True):
- ... # going from the oldest to the most recent
-
-You can also use it to search for messages from a specific person:
-
-.. code-block:: python
-
- for message in client.iter_messages(chat, from_user='me'):
- ...
-
-Or you can search by text:
-
-.. code-block:: python
-
- for message in client.iter_messages(chat, search='hello'):
- ...
-
-Or you can search by media with a :tl:`MessagesFilter`:
-
-.. code-block:: python
-
- from telethon.tl.types import InputMessagesFilterPhotos
-
- for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
- ...
-
-If you want a list instead, use the get variant. The second
-argument is the limit, and ``None`` means "get them all":
-
-.. code-block:: python
-
-
- from telethon.tl.types import InputMessagesFilterPhotos
-
- # Get 0 photos and print the total
- photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
- print(photos.total)
-
- # Get all the photos
- photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
-
-Or just some IDs:
-
-.. code-block:: python
-
- message_1337 = client.get_messages(chats, ids=1337)
-
-
-Exporting Messages
-******************
-
-If you plan on exporting data from your Telegram account, such as the entire
-message history from your private conversations, chats or channels, or if you
-plan to download a lot of media, you may prefer to do this within a *takeout*
-session. Takeout sessions let you export data from your account with lower
-flood wait limits.
-
-To start a takeout session, simply call `client.takeout()
-`:
-
-.. code-block:: python
-
- from telethon import errors
-
- try:
- with client.takeout() as takeout:
- for message in takeout.iter_messages(chat, wait_time=0):
- ... # Do something with the message
-
- except errors.TakeoutInitDelayError as e:
- print('Must wait', e.seconds, 'before takeout')
-
-
-Depending on the condition of the session (for example, when it's very
-young and the method has not been called before), you may or not need
-to ``except errors.TakeoutInitDelayError``. However, it is good practice.
-
-
-Sending Messages
-****************
-
-Just use `send_message `:
-
-.. code-block:: python
-
- client.send_message('lonami', 'Thanks for the Telethon library!')
-
-The function returns the `custom.Message `
-that was sent so you can do more things with it if you want.
-
-You can also `reply ` or
-`respond ` to messages:
-
-.. code-block:: python
-
- message.reply('Hello')
- message.respond('World')
-
-Sending Markdown or HTML messages
-*********************************
-
-Markdown (``'md'`` or ``'markdown'``) is the default `parse_mode
-`
-for the client. You can change the default parse mode like so:
-
-.. code-block:: python
-
- client.parse_mode = 'html'
-
-
-Now all messages will be formatted as HTML by default:
-
-.. code-block:: python
-
- client.send_message('me', 'Some bold and italic text')
- client.send_message('me', 'An URL')
- client.send_message('me', 'code
and pre\nblocks
')
- client.send_message('me', 'Mentions')
-
-
-You can override the default parse mode to use for special cases:
-
-.. code-block:: python
-
- # No parse mode by default
- client.parse_mode = None
-
- # ...but here I want markdown
- client.send_message('me', 'Hello, **world**!', parse_mode='md')
-
- # ...and here I need HTML
- client.send_message('me', 'Hello, world!', parse_mode='html')
-
-The rules are the same as for Bot API, so please refer to
-https://core.telegram.org/bots/api#formatting-options.
-
-Sending Messages with Media
-***************************
-
-Sending media can be done with `send_file
-`:
-
-.. code-block:: python
-
- client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
- # or
- client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
-
-You can send voice notes or round videos by setting the right arguments:
-
-.. code-block:: python
-
- client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
- client.send_file(chat, '/my/videos/video.mp4', video_note=True)
-
-You can set a JPG thumbnail for any document:
-
-.. code-block:: python
-
- client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
-
-You can force sending images as documents:
-
-.. code-block:: python
-
- client.send_file(chat, '/my/photos/photo.png', force_document=True)
-
-You can send albums if you pass more than one file:
-
-.. code-block:: python
-
- client.send_file(chat, [
- '/my/photos/holiday1.jpg',
- '/my/photos/holiday2.jpg',
- '/my/drawings/portrait.png'
- ])
-
-The caption can also be a list to match the different photos.
-
-Reusing Uploaded Files
-**********************
-
-All files you send are automatically cached, so if you do:
-
-.. code-block:: python
-
- client.send_file(first_chat, 'document.txt')
- client.send_file(second_chat, 'document.txt')
-
-The ``'document.txt'`` file will only be uploaded once. You
-can disable this behaviour by settings ``allow_cache=False``:
-
-.. code-block:: python
-
- client.send_file(first_chat, 'document.txt', allow_cache=False)
- client.send_file(second_chat, 'document.txt', allow_cache=False)
-
-Disabling cache is the only way to send the same document with different
-attributes (for example, you send an ``.ogg`` as a song but now you want
-it to show as a voice note; you probably need to disable the cache).
-
-However, you can *upload* the file once (not sending it yet!), and *then*
-you can send it with different attributes. This means you can send an image
-as a photo and a document:
-
-.. code-block:: python
-
- file = client.upload_file('photo.jpg')
- client.send_file(chat, file) # sends as photo
- client.send_file(chat, file, force_document=True) # sends as document
-
- file.name = 'not a photo.jpg'
- client.send_file(chat, file, force_document=True) # document, new name
-
-Or, the example described before:
-
-.. code-block:: python
-
- file = client.upload_file('song.ogg')
- client.send_file(chat, file) # sends as song
- client.send_file(chat, file, voice_note=True) # sends as voice note
-
-The ``file`` returned by `client.upload_file
-` represents the uploaded
-file, not an immutable document (that's why the attributes can change, because
-they are set later). This handle can be used only for a limited amount of time
-(somewhere within a day). Telegram decides this limit and it is not public.
-However, a day is often more than enough.
-
-
-Sending Messages with Buttons
-*****************************
-
-**You must sign in as a bot** in order to add inline buttons (or normal
-keyboards) to your messages. Once you have signed in as a bot specify
-the `Button ` or buttons to use:
-
-.. code-block:: python
-
- from telethon import events
- from telethon.tl.custom import Button
-
- @client.on(events.CallbackQuery)
- async def callback(event):
- await event.edit('Thank you for clicking {}!'.format(event.data))
-
- client.send_message(chat, 'A single button, with "clk1" as data',
- buttons=Button.inline('Click me', b'clk1'))
-
- client.send_message(chat, 'Pick one from this grid', buttons=[
- [Button.inline('Left'), Button.inline('Right')],
- [Button.url('Check this site!', 'https://lonamiwebs.github.io')]
- ])
-
-You can also use normal buttons (not inline) to request the user's
-location, phone number, or simply for them to easily send a message:
-
-.. code-block:: python
-
- client.send_message(chat, 'Welcome', buttons=[
- Button.text('Thanks!', resize=True, single_use=True),
- Button.request_phone('Send phone'),
- Button.request_location('Send location')
- ])
-
-Forcing a reply or removing the keyboard can also be done:
-
-.. code-block:: python
-
- client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
- client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
-
-Remember to check `Button ` for more.
-
-Making Inline Queries
-*********************
-
-You can send messages ``via @bot`` by first making an inline query:
-
-.. code-block:: python
-
- results = client.inline_query('like', 'Do you like Telethon?')
-
-Then access the result you want and `click
-` it in the chat
-where you want to send it to:
-
-.. code-block:: python
-
- message = results[0].click('TelethonOffTopic')
-
-Sending messages through inline bots lets you use buttons as a normal user.
-
-It can look a bit strange at first, but you can make inline queries in no
-chat in particular, and then click a *result* to send it to some chat.
-
-Clicking Buttons
-****************
-
-Let's `click `
-the message we sent in the example above!
-
-.. code-block:: python
-
- message.click(0)
-
-This will click the first button in the message. You could also
-``click(row, column)``, using some text such as ``click(text='👍')``
-or even the data directly ``click(data=b'payload')``.
-
-Answering Inline Queries
-************************
-
-As a bot, you can answer to inline queries with `events.InlineQuery
-`. You should make use of the
-`builder ` property
-to conveniently build the list of results to show to the user. Remember
-to check the properties of the `InlineQuery.Event
-`:
-
-.. code-block:: python
-
- @bot.on(events.InlineQuery)
- async def handler(event):
- builder = event.builder
-
- rev_text = event.text[::-1]
- await event.answer([
- builder.article('Reverse text', text=rev_text),
- builder.photo('/path/to/photo.jpg')
- ])
-
-Conversations: Waiting for Messages or Replies
-**********************************************
-
-This one is really useful for unit testing your bots, which you can
-even write within Telethon itself! You can open a `Conversation
-` in any chat as:
-
-.. code-block:: python
-
- with client.conversation(chat) as conv:
- ...
-
-Conversations let you program a finite state machine with the
-higher-level constructs we are all used to, such as ``while``
-and ``if`` conditionals instead setting the state and jumping
-from one place to another which is less clean.
-
-For instance, let's imagine ``you`` are the bot talking to ``usr``:
-
-.. code-block:: text
-
- Hi!
- Hello!
- Please tell me your name
- ?
- Your name didn't have any letters! Try again
- Lonami
- Thanks Lonami!
-
-This can be programmed as follows:
-
-.. code-block:: python
-
- with bot.conversation(chat) as conv:
- conv.send_message('Hi!')
- hello = conv.get_response()
-
- conv.send_message('Please tell me your name')
- name = conv.get_response().raw_text
- while not any(x.isalpha() for x in name):
- conv.send_message("Your name didn't have any letters! Try again")
- name = conv.get_response().raw_text
-
- conv.send_message('Thanks {}!'.format(name))
-
-Note how we sent a message **with the conversation**, not with the client.
-This is important so the conversation remembers what messages you sent.
-
-The method reference for getting a response, getting a reply or marking
-the conversation as read can be found by clicking here: `Conversation
-`.
-
-Sending a message or getting a response returns a `Message
-`. Reading its documentation
-will also be really useful!
-
-If a reply never arrives or too many messages come in, getting
-responses will raise ``asyncio.TimeoutError`` or ``ValueError``
-respectively. You may want to ``except`` these and tell the user
-they were too slow, or simply drop the conversation.
-
-
-Forwarding Messages
-*******************
-
-You can forward up to 100 messages with `forward_messages
-`,
-or a single one if you have the message with `forward_to
-`:
-
-.. code-block:: python
-
- # a single one
- client.forward_messages(chat, message)
- # or
- client.forward_messages(chat, message_id, from_chat)
- # or
- message.forward_to(chat)
-
- # multiple
- client.forward_messages(chat, messages)
- # or
- client.forward_messages(chat, message_ids, from_chat)
-
-You can also "forward" messages without showing "Forwarded from" by
-re-sending the message:
-
-.. code-block:: python
-
- client.send_message(chat, message)
-
-
-Editing Messages
-****************
-
-With `edit_message `
-or `message.edit `:
-
-.. code-block:: python
-
- client.edit_message(message, 'New text')
- # or
- message.edit('New text')
- # or
- client.edit_message(chat, message_id, 'New text')
-
-Deleting Messages
-*****************
-
-With `delete_messages `
-or `message.delete `. Note that the
-first one supports deleting entire chats at once!:
-
-.. code-block:: python
-
- client.delete_messages(chat, messages)
- # or
- message.delete()
-
-
-Marking Messages as Read
-************************
-
-Marking messages up to a certain point as read with `send_read_acknowledge
-`:
-
-.. code-block:: python
-
- client.send_read_acknowledge(last_message)
- # or
- client.send_read_acknowledge(last_message_id)
- # or
- client.send_read_acknowledge(messages)
-
-
-Getting Entities
-****************
-
-Entities are users, chats, or channels. You can get them by their ID if
-you have seen them before (e.g. you probably need to get all dialogs or
-all the members from a chat first):
-
-.. code-block:: python
-
- from telethon import utils
-
- me = client.get_entity('me')
- print(utils.get_display_name(me))
-
- chat = client.get_input_entity('username')
- 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.
- for message in client.iter_messages('username'):
- ...
-
- # Note that for this to work the phone number must be in your contacts
- some_id = client.get_peer_id('+34123456789')
-
-The documentation for shown methods are `get_entity
-`, `get_input_entity
-` and `get_peer_id
-`.
-
-Note that the utils package also has a `get_peer_id
-` but it won't work with things
-that need access to the network such as usernames or phones,
-which need to be in your contact list.
-
-Getting the Admin Log
-*********************
-
-If you're an administrator in a channel or megagroup, then you have access
-to the admin log. This is a list of events within the last 48 hours of
-different actions, such as joining or leaving members, edited or deleted
-messages, new promotions, bans or restrictions.
-
-You can iterate over all the available actions like so:
-
-.. code-block:: python
-
- for event in client.iter_admin_log(channel):
- if event.changed_title:
- print('The title changed from', event.old, 'to', event.new)
-
-You can also filter to only show some text or actions.
-Let's find people who swear to ban them:
-
-.. code-block:: python
-
- # Get a list of deleted message events which said "heck"
- events = client.get_admin_log(channel, search='heck', delete=True)
-
- # Print the old message before it was deleted
- print(events[0].old)
-
-You can find here the documentation for `client.iter_admin_log
-`, and be sure
-to also check the properties of the returned `AdminLogEvent
-` to know what
-you can access.
diff --git a/readthedocs/extra/troubleshooting/deleted-limited-or-deactivated-accounts.rst b/readthedocs/extra/troubleshooting/deleted-limited-or-deactivated-accounts.rst
deleted file mode 100644
index 671306c4..00000000
--- a/readthedocs/extra/troubleshooting/deleted-limited-or-deactivated-accounts.rst
+++ /dev/null
@@ -1,27 +0,0 @@
-========================================
-Deleted, Limited or Deactivated Accounts
-========================================
-
-If you're from Iran or Russia, we have bad news for you. Telegram is much more
-likely to ban these numbers, as they are often used to spam other accounts,
-likely through the use of libraries like this one. The best advice we can
-give you is to not abuse the API, like calling many requests really quickly,
-and to sign up with these phones through an official application.
-
-We have also had reports from Kazakhstan and China, where connecting
-would fail. To solve these connection problems, you should use a proxy.
-
-Telegram may also ban virtual (VoIP) phone numbers,
-as again, they're likely to be used for spam.
-
-If you want to check if your account has been limited,
-simply send a private message to `@SpamBot`__ through Telegram itself.
-You should notice this by getting errors like ``PeerFloodError``,
-which means you're limited, for instance,
-when sending a message to some accounts but not others.
-
-For more discussion, please see `issue 297`__.
-
-
-__ https://t.me/SpamBot
-__ https://github.com/LonamiWebs/Telethon/issues/297
diff --git a/readthedocs/extra/troubleshooting/enable-logging.rst b/readthedocs/extra/troubleshooting/enable-logging.rst
deleted file mode 100644
index 8d8747f4..00000000
--- a/readthedocs/extra/troubleshooting/enable-logging.rst
+++ /dev/null
@@ -1,40 +0,0 @@
-================
-Enabling Logging
-================
-
-Telethon makes use of the `logging`__ module, and you can enable it as follows:
-
-.. code:: python
-
- import logging
- logging.basicConfig(level=logging.DEBUG)
-
-The library has the `NullHandler`__ added by default so that no log calls
-will be printed unless you explicitly enable it.
-
-You can also `use the module`__ on your own project very easily:
-
-.. code-block:: python
-
- import logging
- logger = logging.getLogger(__name__)
-
- logger.debug('Debug messages')
- logger.info('Useful information')
- logger.warning('This is a warning!')
-
-
-If you want to enable ``logging`` for your project *but* use a different
-log level for the library:
-
-.. code-block:: python
-
- import logging
- logging.basicConfig(level=logging.DEBUG)
- # For instance, show only warnings and above
- logging.getLogger('telethon').setLevel(level=logging.WARNING)
-
-
-__ https://docs.python.org/3/library/logging.html
-__ https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
-__ https://docs.python.org/3/howto/logging.html
diff --git a/readthedocs/index.rst b/readthedocs/index.rst
index 097ce208..1d2847c4 100644
--- a/readthedocs/index.rst
+++ b/readthedocs/index.rst
@@ -1,29 +1,31 @@
-.. 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.
+========================
+Telethon's Documentation
+========================
-====================================
-Welcome to Telethon's documentation!
-====================================
+.. code-block:: python
+
+ from telethon.sync import TelegramClient, events
+
+ with TelegramClient('name', api_id, api_hash) as client:
+ client.send_message('me', 'Hello, myself!')
+ print(client.download_profile_photo('me'))
+
+ @client.on(events.NewMessage(pattern='(?i).*Hello'))
+ async def handler(event):
+ await event.reply('Hey!')
+
+ client.run_until_disconnected()
-Pure Python 3 Telegram client library.
-Official Site `here `_.
-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::
-
- * Are you new here? Jump straight into :ref:`getting-started`!
- * Looking for available friendly methods? See :ref:`ref-summary`.
- * Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
- * Need the full API reference? https://lonamiwebs.github.io/Telethon/.
+* Are you new here? Jump straight into :ref:`installation`!
+* Looking for the method reference? See :ref:`client-ref`.
+* Did you upgrade the library? Please read :ref:`changelog`.
+* Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
+* Need the full API reference? https://lonamiwebs.github.io/Telethon/.
What is this?
-*************
+-------------
Telegram is a popular messaging application. This library is meant
to make it easy for you to write Python programs that can interact
@@ -31,93 +33,84 @@ with Telegram. Think of it as a wrapper that has already done the
heavy job for you, so you can focus on developing an application.
-.. _installation-and-usage:
+How should I use the documentation?
+-----------------------------------
+
+If you are getting started with the library, you should follow the
+documentation in order by pressing the "Next" button at the bottom-right
+of every page.
+
+You can also use the menu on the left to quickly skip over sections.
.. toctree::
- :maxdepth: 2
- :caption: Installation and Simple Usage
+ :hidden:
+ :caption: First Steps
- extra/basic/getting-started
- extra/basic/installation
- extra/basic/creating-a-client
- extra/basic/telegram-client
- extra/reference
- extra/basic/entities
- extra/basic/working-with-updates
- extra/basic/compatibility-and-convenience
-
-
-.. _Advanced-usage:
+ basic/installation
+ basic/signing-in
+ basic/quick-start
+ basic/updates
+ basic/next-steps
.. toctree::
- :maxdepth: 2
- :caption: Advanced Usage
+ :hidden:
+ :caption: Quick References
- extra/advanced-usage/accessing-the-full-api
- extra/advanced-usage/sessions
- extra/advanced-usage/update-modes
- extra/advanced-usage/mastering-telethon
- extra/advanced-usage/mastering-asyncio
-
-
-.. _Examples:
+ quick-references/faq
+ quick-references/client-reference
+ quick-references/events-reference
+ quick-references/objects-reference
.. toctree::
- :maxdepth: 2
- :caption: Examples
+ :hidden:
+ :caption: Concepts
- extra/examples/telegram-client
- extra/examples/working-with-messages
- extra/examples/chats-and-channels
- extra/examples/users
- extra/examples/projects-using-telethon
-
-
-.. _Troubleshooting:
+ concepts/strings
+ concepts/entities
+ concepts/updates
+ concepts/sessions
+ concepts/full-api
+ concepts/errors
+ concepts/asyncio
.. toctree::
- :maxdepth: 2
- :caption: Troubleshooting
+ :hidden:
+ :caption: Full API Examples
- extra/troubleshooting/enable-logging
- extra/troubleshooting/deleted-limited-or-deactivated-accounts
- extra/troubleshooting/rpc-errors
-
-
-.. _Developing:
+ examples/word-of-warning
+ examples/chats-and-channels
+ examples/users
+ examples/working-with-messages
+ examples/projects-using-telethon
.. toctree::
- :maxdepth: 2
- :caption: Developing
+ :hidden:
+ :caption: Developing
- extra/developing/philosophy.rst
- extra/developing/test-servers.rst
- extra/developing/project-structure.rst
- extra/developing/coding-style.rst
- extra/developing/understanding-the-type-language.rst
- extra/developing/tips-for-porting-the-project.rst
- extra/developing/telegram-api-in-other-languages.rst
-
-
-.. _More:
+ developing/philosophy.rst
+ developing/test-servers.rst
+ developing/project-structure.rst
+ developing/coding-style.rst
+ developing/understanding-the-type-language.rst
+ developing/tips-for-porting-the-project.rst
+ developing/telegram-api-in-other-languages.rst
.. toctree::
- :maxdepth: 2
- :caption: More
-
- extra/changelog
- extra/wall-of-shame.rst
+ :hidden:
+ :caption: Miscellaneous
+ misc/changelog
+ misc/wall-of-shame.rst
+ misc/compatibility-and-convenience
.. toctree::
- :caption: Telethon modules
+ :hidden:
+ :caption: Telethon Modules
- modules
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
+ modules/client
+ modules/events
+ modules/custom
+ modules/utils
+ modules/errors
+ modules/sessions
+ modules/network
diff --git a/readthedocs/extra/changelog.rst b/readthedocs/misc/changelog.rst
similarity index 99%
rename from readthedocs/extra/changelog.rst
rename to readthedocs/misc/changelog.rst
index 08f0395f..a2a649fb 100644
--- a/readthedocs/extra/changelog.rst
+++ b/readthedocs/misc/changelog.rst
@@ -867,7 +867,7 @@ Additions
`.
- New ``silent`` parameter when sending messages, usable in broadcast channels.
- Documentation now has an entire section dedicate to how to use
- the client's friendly methods at :ref:`telegram-client-example`.
+ the client's friendly methods at *(removed broken link)*.
Bug fixes
~~~~~~~~~
@@ -924,7 +924,7 @@ Additions
~~~~~~~~~
- ``add_mark=`` is now back on ``utils.get_input_peer`` and also on
- `client.get_input_entity `.
+ `client.get_input_entity() `.
- New `client.get_peer_id `
convenience for ``utils.get_peer_id(await client.get_input_entity(peer))``.
@@ -1776,7 +1776,7 @@ Of course there was more work to be done regarding updates, and it's here!
The library comes with a new ``events`` module (which you will often import
as ``from telethon import TelegramClient, events``). This are pretty much
all the additions that come with this version change, but they are a nice
-addition. Refer to :ref:`working-with-updates` to get started with events.
+addition. Refer to *(removed broken link)* to get started with events.
Trust the Server with Updates (v0.17)
diff --git a/readthedocs/extra/basic/compatibility-and-convenience.rst b/readthedocs/misc/compatibility-and-convenience.rst
similarity index 99%
rename from readthedocs/extra/basic/compatibility-and-convenience.rst
rename to readthedocs/misc/compatibility-and-convenience.rst
index 86be8c1c..9d6e8257 100644
--- a/readthedocs/extra/basic/compatibility-and-convenience.rst
+++ b/readthedocs/misc/compatibility-and-convenience.rst
@@ -12,7 +12,7 @@ is there to tell you when these important changes happen.
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
@@ -76,7 +76,7 @@ the chat or sender. If you don't use updates, you're done!
Convenience
-***********
+===========
.. note::
@@ -134,7 +134,7 @@ This keeps the best of both worlds as a sane default.
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,
@@ -176,7 +176,7 @@ 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
diff --git a/readthedocs/extra/wall-of-shame.rst b/readthedocs/misc/wall-of-shame.rst
similarity index 100%
rename from readthedocs/extra/wall-of-shame.rst
rename to readthedocs/misc/wall-of-shame.rst
diff --git a/readthedocs/modules.rst b/readthedocs/modules.rst
deleted file mode 100644
index f710574a..00000000
--- a/readthedocs/modules.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-telethon
-========
-
-.. toctree::
- :maxdepth: 3
-
- telethon
diff --git a/readthedocs/telethon.client.rst b/readthedocs/modules/client.rst
similarity index 76%
rename from readthedocs/telethon.client.rst
rename to readthedocs/modules/client.rst
index c5d80d0b..6639200f 100644
--- a/readthedocs/telethon.client.rst
+++ b/readthedocs/modules/client.rst
@@ -1,12 +1,14 @@
.. _telethon-client:
+==============
+TelegramClient
+==============
-telethon\.client package
-========================
+.. currentmodule:: telethon.client
-The `telethon.TelegramClient` aggregates several mixin classes to provide
-all the common functionality in a nice, Pythonic interface. Each mixin has
-its own methods, which you all can use.
+The `TelegramClient ` aggregates several mixin
+classes to provide all the common functionality in a nice, Pythonic interface.
+Each mixin has its own methods, which you all can use.
**In short, to create a client you must run:**
@@ -24,8 +26,15 @@ its own methods, which you all can use.
You **don't** need to import these `AuthMethods`, `MessageMethods`, etc.
-Together they are the `telethon.TelegramClient` and you can access all of
-their methods.
+Together they are the `TelegramClient ` and
+you can access all of their methods.
+
+See :ref:`client-ref` for a short summary.
+
+.. automodule:: telethon.client.telegramclient
+ :members:
+ :undoc-members:
+ :show-inheritance:
.. automodule:: telethon.client.telegrambaseclient
:members:
diff --git a/readthedocs/telethon.tl.custom.rst b/readthedocs/modules/custom.rst
similarity index 55%
rename from readthedocs/telethon.tl.custom.rst
rename to readthedocs/modules/custom.rst
index f005f209..1f1329bf 100644
--- a/readthedocs/telethon.tl.custom.rst
+++ b/readthedocs/modules/custom.rst
@@ -1,115 +1,145 @@
-telethon\.tl\.custom package
-============================
+==============
+Custom package
+==============
+The `telethon.tl.custom` package contains custom classes that the library
+uses in order to make working with Telegram easier. Only those that you
+are supposed to use will be documented here. You can use undocumented ones
+at your own risk.
-telethon\.tl\.custom\.draft module
-----------------------------------
+More often than not, you don't need to import these (unless you want
+type hinting), nor do you need to manually create instances of these
+classes. They are returned by client methods.
-.. automodule:: telethon.tl.custom.draft
+.. contents::
+
+.. automodule:: telethon.tl.custom
:members:
:undoc-members:
:show-inheritance:
-telethon\.tl\.custom\.dialog module
------------------------------------
-.. automodule:: telethon.tl.custom.dialog
+AdminLogEvent
+=============
+
+.. automodule:: telethon.tl.custom.adminlogevent
:members:
:undoc-members:
:show-inheritance:
-telethon\.tl\.custom\.file module
----------------------------------
-.. automodule:: telethon.tl.custom.file
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.message module
-------------------------------------
-
-.. automodule:: telethon.tl.custom.message
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.messagebutton module
-------------------------------------------
-
-.. automodule:: telethon.tl.custom.messagebutton
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.forward module
-------------------------------------
-
-.. automodule:: telethon.tl.custom.forward
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.button module
------------------------------------
+Button
+======
.. automodule:: telethon.tl.custom.button
:members:
:undoc-members:
:show-inheritance:
-telethon\.tl\.custom\.inlinebuilder module
-------------------------------------------
-.. automodule:: telethon.tl.custom.inlinebuilder
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.inlineresult module
------------------------------------------
-
-.. automodule:: telethon.tl.custom.inlineresult
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.inlineresults module
-------------------------------------------
-
-.. automodule:: telethon.tl.custom.inlineresults
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.chatgetter module
----------------------------------------
+ChatGetter
+==========
.. automodule:: telethon.tl.custom.chatgetter
:members:
:undoc-members:
:show-inheritance:
-telethon\.tl\.custom\.sendergetter module
------------------------------------------
-.. automodule:: telethon.tl.custom.sendergetter
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.tl\.custom\.conversation module
------------------------------------------
+Conversation
+============
.. automodule:: telethon.tl.custom.conversation
:members:
:undoc-members:
:show-inheritance:
-telethon\.tl\.custom\.adminlogevent module
-------------------------------------------
-.. automodule:: telethon.tl.custom.adminlogevent
+Dialog
+======
+
+.. automodule:: telethon.tl.custom.dialog
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+Draft
+=====
+
+.. automodule:: telethon.tl.custom.draft
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+File
+====
+
+.. automodule:: telethon.tl.custom.file
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+Forward
+=======
+
+.. automodule:: telethon.tl.custom.forward
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+InlineBuilder
+=============
+
+.. automodule:: telethon.tl.custom.inlinebuilder
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+InlineResult
+============
+
+.. automodule:: telethon.tl.custom.inlineresult
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+InlineResults
+=============
+
+.. automodule:: telethon.tl.custom.inlineresults
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+Message
+=======
+
+.. automodule:: telethon.tl.custom.message
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+MessageButton
+=============
+
+.. automodule:: telethon.tl.custom.messagebutton
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+SenderGetter
+============
+
+.. automodule:: telethon.tl.custom.sendergetter
:members:
:undoc-members:
:show-inheritance:
diff --git a/readthedocs/modules/errors.rst b/readthedocs/modules/errors.rst
new file mode 100644
index 00000000..0df239c9
--- /dev/null
+++ b/readthedocs/modules/errors.rst
@@ -0,0 +1,19 @@
+.. _telethon-errors:
+
+==========
+API Errors
+==========
+
+These are the base errors that Telegram's API may raise.
+
+See :ref:`rpc-errors` for a more friendly explanation.
+
+.. automodule:: telethon.errors.common
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.errors.rpcbaseerrors
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/readthedocs/telethon.events.rst b/readthedocs/modules/events.rst
similarity index 87%
rename from readthedocs/telethon.events.rst
rename to readthedocs/modules/events.rst
index deb83e96..961885a0 100644
--- a/readthedocs/telethon.events.rst
+++ b/readthedocs/modules/events.rst
@@ -1,9 +1,12 @@
-.. _telethon-events-package:
+.. _telethon-events:
-telethon\.events package
-========================
+=============
+Update Events
+=============
-Every event (builder) subclasses `telethon.events.common.EventBuilder`,
+.. currentmodule:: telethon.events
+
+Every event (builder) subclasses `common.EventBuilder`,
so all the methods in it can be used from any event builder/event instance.
.. automodule:: telethon.events.common
@@ -11,62 +14,51 @@ so all the methods in it can be used from any event builder/event instance.
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.newmessage
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.chataction
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.userupdate
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.messageedited
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.messagedeleted
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.messageread
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.callbackquery
:members:
:undoc-members:
:show-inheritance:
-
-
.. automodule:: telethon.events.inlinequery
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events.raw
:members:
:undoc-members:
:show-inheritance:
-
.. automodule:: telethon.events
:members:
:undoc-members:
diff --git a/readthedocs/modules/helpers.rst b/readthedocs/modules/helpers.rst
new file mode 100644
index 00000000..cffe53e5
--- /dev/null
+++ b/readthedocs/modules/helpers.rst
@@ -0,0 +1,8 @@
+=======
+Helpers
+=======
+
+.. automodule:: telethon.helpers
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/readthedocs/modules/network.rst b/readthedocs/modules/network.rst
new file mode 100644
index 00000000..3395fa51
--- /dev/null
+++ b/readthedocs/modules/network.rst
@@ -0,0 +1,33 @@
+.. _telethon-network:
+
+================
+Connection Modes
+================
+
+The only part about network that you should worry about are
+the different connection modes, which are the following:
+
+.. automodule:: telethon.network.connection.tcpfull
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.network.connection.tcpabridged
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.network.connection.tcpintermediate
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.network.connection.tcpobfuscated
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.network.connection.http
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/readthedocs/modules/sessions.rst b/readthedocs/modules/sessions.rst
new file mode 100644
index 00000000..86ae22a4
--- /dev/null
+++ b/readthedocs/modules/sessions.rst
@@ -0,0 +1,27 @@
+.. _telethon-sessions:
+
+========
+Sessions
+========
+
+These are the different built-in session storage that you may subclass.
+
+.. automodule:: telethon.sessions.abstract
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.sessions.memory
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.sessions.sqlite
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: telethon.sessions.string
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/readthedocs/modules/utils.rst b/readthedocs/modules/utils.rst
new file mode 100644
index 00000000..2fab89a2
--- /dev/null
+++ b/readthedocs/modules/utils.rst
@@ -0,0 +1,12 @@
+.. _telethon-utils:
+
+=========
+Utilities
+=========
+
+These are the utilities that the library has to offer.
+
+.. automodule:: telethon.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/readthedocs/quick-references/client-reference.rst b/readthedocs/quick-references/client-reference.rst
new file mode 100644
index 00000000..8ecc70dc
--- /dev/null
+++ b/readthedocs/quick-references/client-reference.rst
@@ -0,0 +1,188 @@
+.. _client-ref:
+
+================
+Client Reference
+================
+
+This page contains a summary of all the important methods and properties that
+you may need when using Telethon. They are sorted by relevance and are not in
+alphabetical order.
+
+You should use this page to learn about which methods are available, and
+if you need an usage example or further description of the arguments, be
+sure to follow the links.
+
+.. contents::
+
+TelegramClient
+==============
+
+This is a summary of the methods and
+properties you will find at :ref:`telethon-client`.
+
+Auth
+----
+
+.. currentmodule:: telethon.client.auth.AuthMethods
+
+.. autosummary::
+ :nosignatures:
+
+ start
+ send_code_request
+ sign_in
+ sign_up
+ log_out
+ edit_2fa
+
+Base
+----
+
+.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
+
+.. autosummary::
+ :nosignatures:
+
+ connect
+ disconnect
+ is_connected
+ disconnected
+ loop
+
+Messages
+--------
+
+.. py:currentmodule:: telethon.client.messages.MessageMethods
+
+.. autosummary::
+ :nosignatures:
+
+ send_message
+ edit_message
+ delete_messages
+ forward_messages
+ iter_messages
+ get_messages
+ send_read_acknowledge
+
+Uploads
+-------
+
+.. py:currentmodule:: telethon.client.uploads.UploadMethods
+
+.. autosummary::
+ :nosignatures:
+
+ send_file
+ upload_file
+
+Downloads
+---------
+
+.. currentmodule:: telethon.client.downloads.DownloadMethods
+
+.. autosummary::
+ :nosignatures:
+
+ download_media
+ download_profile_photo
+ download_file
+
+Dialogs
+-------
+
+.. py:currentmodule:: telethon.client.dialogs.DialogMethods
+
+.. autosummary::
+ :nosignatures:
+
+ iter_dialogs
+ get_dialogs
+ iter_drafts
+ get_drafts
+ conversation
+
+Users
+-----
+
+.. py:currentmodule:: telethon.client.users.UserMethods
+
+.. autosummary::
+ :nosignatures:
+
+ get_me
+ is_bot
+ is_user_authorized
+ get_entity
+ get_input_entity
+ get_peer_id
+
+Chats
+-----
+
+.. currentmodule:: telethon.client.chats.ChatMethods
+
+.. autosummary::
+ :nosignatures:
+
+ iter_participants
+ get_participants
+ iter_admin_log
+ get_admin_log
+ action
+
+Parse Mode
+----------
+
+.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
+
+.. autosummary::
+ :nosignatures:
+
+ parse_mode
+
+Updates
+-------
+
+.. py:currentmodule:: telethon.client.updates.UpdateMethods
+
+.. autosummary::
+ :nosignatures:
+
+ on
+ run_until_disconnected
+ add_event_handler
+ remove_event_handler
+ list_event_handlers
+ catch_up
+
+Bots
+----
+
+.. currentmodule:: telethon.client.bots.BotMethods
+
+.. autosummary::
+ :nosignatures:
+
+ inline_query
+
+Buttons
+-------
+
+.. currentmodule:: telethon.client.buttons.ButtonMethods
+
+.. autosummary::
+ :nosignatures:
+
+ build_reply_markup
+
+Account
+-------
+
+.. currentmodule:: telethon.client.account.AccountMethods
+
+.. autosummary::
+ :nosignatures:
+
+ takeout
+ end_takeout
diff --git a/readthedocs/quick-references/events-reference.rst b/readthedocs/quick-references/events-reference.rst
new file mode 100644
index 00000000..89c4cee2
--- /dev/null
+++ b/readthedocs/quick-references/events-reference.rst
@@ -0,0 +1,203 @@
+================
+Events Reference
+================
+
+Here you will find a quick summary of all the methods
+and properties that you can access when working with events.
+
+You can access the client that creates this event by doing
+``event.client``, and you should view the description of the
+events to find out what arguments it allows on creation and
+its **attributes** (the properties will be shown here).
+
+It is important to remember that **all events subclass**
+`ChatGetter `!
+
+.. contents::
+
+
+ChatGetter
+==========
+
+All events subclass `ChatGetter `,
+which means all events have (and you can access to):
+
+.. currentmodule:: telethon.tl.custom.chatgetter.ChatGetter
+
+.. autosummary::
+ :nosignatures:
+
+ chat
+ input_chat
+ chat_id
+ is_private
+ is_group
+ is_channel
+
+ get_chat
+ get_input_chat
+
+
+CallbackQuery
+=============
+
+Full documentation for the `CallbackQuery
+`.
+
+.. currentmodule:: telethon.events.callbackquery.CallbackQuery.Event
+
+.. autosummary::
+ :nosignatures:
+
+ id
+ message_id
+ data
+ chat_instance
+ via_inline
+
+ respond
+ reply
+ edit
+ delete
+ answer
+ get_message
+
+
+ChatAction
+==========
+
+Full documentation for the `ChatAction
+`.
+
+.. currentmodule:: telethon.events.chataction.ChatAction.Event
+
+.. autosummary::
+ :nosignatures:
+
+ added_by
+ kicked_by
+ user
+ input_user
+ user_id
+ users
+ input_users
+ user_ids
+
+ respond
+ reply
+ delete
+ get_pinned_message
+ get_added_by
+ get_kicked_by
+ get_user
+ get_input_user
+ get_users
+ get_input_users
+
+
+InlineQuery
+===========
+
+Full documentation for the `InlineQuery
+`.
+
+.. currentmodule:: telethon.events.inlinequery.InlineQuery.Event
+
+.. autosummary::
+ :nosignatures:
+
+ id
+ text
+ offset
+ geo
+ builder
+
+ answer
+
+
+MessageDeleted
+==============
+
+Full documentation for the `MessageDeleted
+`.
+
+It only has the ``deleted_id`` and ``deleted_ids`` attributes
+(in addition to the chat if the deletion happened in a channel).
+
+
+MessageEdited
+=============
+
+Full documentation for the `MessageEdited
+`.
+
+This event is the same as `NewMessage
+`,
+but occurs only when an edit happens.
+
+
+MessageRead
+===========
+
+Full documentation for the `MessageRead
+`.
+
+.. currentmodule:: telethon.events.messageread.MessageRead.Event
+
+.. autosummary::
+ :nosignatures:
+
+ inbox
+ message_ids
+
+ get_messages
+ is_read
+
+
+NewMessage
+==========
+
+Full documentation for the `NewMessage
+`.
+
+Note that the new message event **should be treated as** a
+normal `Message `, with
+the following exceptions:
+
+* ``pattern_match`` is the match object returned by ``pattern=``.
+* ``message`` is **not** the message string. It's the `Message
+ ` object.
+
+Remember, this event is just a proxy over the message, so while
+you won't see its attributes and properties, you can still access
+them.
+
+
+Raw
+===
+
+Raw events are not actual events. Instead, they are the raw
+:tl:`Update` object that Telegram sends. You normally shouldn't
+need these.
+
+
+UserUpdate
+==========
+
+Full documentation for the `UserUpdate
+`.
+
+A lot of fields are attributes and not properties, so they
+are not shown here.
+
+.. currentmodule:: telethon.events.userupdate.UserUpdate.Event
+
+.. autosummary::
+ :nosignatures:
+
+ user
+ input_user
+ user_id
+
+ get_user
+ get_input_user
diff --git a/readthedocs/quick-references/faq.rst b/readthedocs/quick-references/faq.rst
new file mode 100644
index 00000000..0363a873
--- /dev/null
+++ b/readthedocs/quick-references/faq.rst
@@ -0,0 +1,190 @@
+===
+FAQ
+===
+
+Let's start the quick references section with some useful tips to keep in
+mind, with the hope that you will understand why certain things work the
+way that they do.
+
+.. contents::
+
+
+Code without errors doesn't work
+================================
+
+Then it probably has errors, but you haven't enabled logging yet.
+To enable logging, at the following code to the top of your main file:
+
+.. code-block:: python
+
+ import logging
+ logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
+ level=logging.WARNING)
+
+You can change the logging level to be something different, from less to more information:
+
+.. code-block:: python
+
+ level=logging.CRITICAL # won't show errors (same as disabled)
+ level=logging.ERROR # will only show errors that you didn't handle
+ level=logging.WARNING # will also show messages with medium severity, such as internal Telegram issues
+ level=logging.INFO # will also show informational messages, such as connection or disconnections
+ level=logging.DEBUG # will show a lot of output to help debugging issues in the library
+
+See the official Python documentation for more information on logging_.
+
+
+How can I except FloodWaitError?
+================================
+
+You can use all errors from the API by importing:
+
+.. code-block:: python
+
+ from telethon import errors
+
+And except them as such:
+
+.. code-block:: python
+
+ import time
+ try:
+ client.send_message(chat, 'Hi')
+ except FloodWaitError as e:
+ print('Flood for', e.seconds)
+ time.sleep(e.seconds)
+
+
+My account was deleted/limited when using the library
+=====================================================
+
+The library will only do things that you tell it to do. If you use
+the library with bad intentions, Telegram will hopefully ban you.
+
+However, you may also be part of a limited country, such as Iran or Russia.
+In that case, we have bad news for you. Telegram is much more likely to ban
+these numbers, as they are often used to spam other accounts, likely through
+the use of libraries like this one. The best advice we can give you is to not
+abuse the API, like calling many requests really quickly, and to sign up with
+these phones through an official application.
+
+We have also had reports from Kazakhstan and China, where connecting
+would fail. To solve these connection problems, you should use a proxy.
+
+Telegram may also ban virtual (VoIP) phone numbers,
+as again, they're likely to be used for spam.
+
+If you want to check if your account has been limited,
+simply send a private message to `@SpamBot`_ through Telegram itself.
+You should notice this by getting errors like ``PeerFloodError``,
+which means you're limited, for instance,
+when sending a message to some accounts but not others.
+
+For more discussion, please see `issue 297`_.
+
+
+How can I use a proxy?
+======================
+
+This was one of the first things described in :ref:`signing-in`.
+
+
+How do I access a field?
+========================
+
+This is basic Python knowledge. You should use the dot operator:
+
+.. code-block:: python
+
+ me = client.get_me()
+ print(me.username)
+ # ^ we used the dot operator to access the username attribute
+
+ result = client(functions.photos.GetUserPhotosRequest(
+ user_id='me',
+ offset=0,
+ max_id=0,
+ limit=100
+ ))
+
+ # Working with list is also pretty basic
+ print(result.photos[0].sizes[-1].type)
+ # ^ ^ ^ ^ ^
+ # | | | | \ type
+ # | | | \ last size
+ # | | \ list of sizes
+ # access | \ first photo from the list
+ # the... \ list of photos
+ #
+ # To print all, you could do (or mix-and-match):
+ for photo in result.photos:
+ for size in photo.sizes:
+ print(size.type)
+
+
+AttributeError: 'coroutine' object has no attribute 'id'
+========================================================
+
+You either forgot to:
+
+.. code-block:: python
+
+ import telethon.sync
+ # ^^^^^ import sync
+
+Or:
+
+.. code-block:: python
+
+ async def handler(event):
+ me = await client.get_me()
+ # ^^^^^ note the await
+ print(me.username)
+
+
+sqlite3.OperationalError: database is locked
+============================================
+
+An older process is still running and is using the same ``'session'`` file.
+
+This error occurs when **two or more clients use the same session**,
+that is, when you write the same session name to be used in the client:
+
+* You have an older process using the same session file.
+* You have two different scripts running (interactive sessions count too).
+* You have two clients in the same script running at the same time.
+
+The solution is, if you need two clients, use two sessions. If the
+problem persists and you're on Linux, you can use ``fuser my.session``
+to find out the process locking the file. As a last resort, you can
+reboot your system.
+
+If you really dislike SQLite, use a different session storage. There
+is an entire section covering that at :ref:`sessions`.
+
+
+event.chat or event.sender is None
+==================================
+
+Telegram doesn't always send this information in order to save bandwidth.
+If you need the information, you should fetch it yourself, since the library
+won't do unnecessary work unless you need to:
+
+.. code-block:: python
+
+ async def handler(event):
+ chat = await event.get_chat()
+ sender = await event.get_sender()
+
+
+Can I use Flask with the library?
+=================================
+
+Yes, if you know what you are doing. However, you will probably have a
+lot of headaches to get threads and asyncio to work together. Instead,
+consider using `Quart `_, an asyncio-based
+alternative to `Flask `_.
+
+.. _logging: https://docs.python.org/3/library/logging.html
+.. _@SpamBot: https://t.me/SpamBot
+.. _issue 297: https://github.com/LonamiWebs/Telethon/issues/297
diff --git a/readthedocs/extra/reference.rst b/readthedocs/quick-references/objects-reference.rst
similarity index 62%
rename from readthedocs/extra/reference.rst
rename to readthedocs/quick-references/objects-reference.rst
index 34e093f8..2fed2253 100644
--- a/readthedocs/extra/reference.rst
+++ b/readthedocs/quick-references/objects-reference.rst
@@ -1,191 +1,16 @@
-.. _ref-summary:
-
=================
-Reference Summary
+Objects Reference
=================
-This page contains a summary of all the important methods and properties that
-you may need when using Telethon. They are sorted by relevance and are not in
-alphabetical order.
+This is the quick reference for those objects returned by client methods
+or other useful modules that the library has to offer. They are kept in
+a separate page to help finding and discovering them.
-The way you should use this page is by looking up the type you need in the
-table of contents (method index below) and searching for the method or
-property that you are interested in.
+Remember that this page only shows properties and methods,
+**not attributes**. Make sure to open the full documentation
+to find out about the attributes.
-.. contents:: Method Index
-
-TelegramClient
-==============
-
-This is a summary of the methods and
-properties you will find at :ref:`telethon-client`.
-
-Auth
-----
-
-.. currentmodule:: telethon.client.auth.AuthMethods
-
-.. autosummary::
- :nosignatures:
-
- start
- send_code_request
- sign_in
- sign_up
- log_out
- edit_2fa
-
-Base
-----
-
-.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
-
-.. autosummary::
- :nosignatures:
-
- connect
- disconnect
- is_connected
- disconnected
- loop
-
-Messages
---------
-
-.. py:currentmodule:: telethon.client.messages.MessageMethods
-
-.. autosummary::
- :nosignatures:
-
- send_message
- edit_message
- delete_messages
- forward_messages
- iter_messages
- get_messages
- send_read_acknowledge
-
-Uploads
--------
-
-.. py:currentmodule:: telethon.client.uploads.UploadMethods
-
-.. autosummary::
- :nosignatures:
-
- send_file
- upload_file
-
-Downloads
----------
-
-.. currentmodule:: telethon.client.downloads.DownloadMethods
-
-.. autosummary::
- :nosignatures:
-
- download_media
- download_profile_photo
- download_file
-
-Dialogs
--------
-
-.. py:currentmodule:: telethon.client.dialogs.DialogMethods
-
-.. autosummary::
- :nosignatures:
-
- iter_dialogs
- get_dialogs
- iter_drafts
- get_drafts
- conversation
-
-Users
------
-
-.. py:currentmodule:: telethon.client.users.UserMethods
-
-.. autosummary::
- :nosignatures:
-
- get_me
- is_bot
- is_user_authorized
- get_entity
- get_input_entity
- get_peer_id
-
-Chats
------
-
-.. currentmodule:: telethon.client.chats.ChatMethods
-
-.. autosummary::
- :nosignatures:
-
- iter_participants
- get_participants
- iter_admin_log
- get_admin_log
- action
-
-Parse Mode
-----------
-
-.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
-
-.. autosummary::
- :nosignatures:
-
- parse_mode
-
-Updates
--------
-
-.. py:currentmodule:: telethon.client.updates.UpdateMethods
-
-.. autosummary::
- :nosignatures:
-
- on
- run_until_disconnected
- add_event_handler
- remove_event_handler
- list_event_handlers
- catch_up
-
-Bots
-----
-
-.. currentmodule:: telethon.client.bots.BotMethods
-
-.. autosummary::
- :nosignatures:
-
- inline_query
-
-Buttons
--------
-
-.. currentmodule:: telethon.client.buttons.ButtonMethods
-
-.. autosummary::
- :nosignatures:
-
- build_reply_markup
-
-Account
--------
-
-.. currentmodule:: telethon.client.account.AccountMethods
-
-.. autosummary::
- :nosignatures:
-
- takeout
- end_takeout
+.. contents::
Message
diff --git a/readthedocs/telethon.errors.rst b/readthedocs/telethon.errors.rst
deleted file mode 100644
index f69e2967..00000000
--- a/readthedocs/telethon.errors.rst
+++ /dev/null
@@ -1,22 +0,0 @@
-.. _telethon-errors-package:
-
-
-telethon\.errors package
-========================
-
-
-telethon\.errors\.common module
--------------------------------
-
-.. automodule:: telethon.errors.common
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.errors\.rpcbaseerrors module
---------------------------------------
-
-.. automodule:: telethon.errors.rpcbaseerrors
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/readthedocs/telethon.extensions.rst b/readthedocs/telethon.extensions.rst
deleted file mode 100644
index 83bb4d93..00000000
--- a/readthedocs/telethon.extensions.rst
+++ /dev/null
@@ -1,27 +0,0 @@
-telethon\.extensions package
-============================
-
-
-telethon\.extensions\.binaryreader module
------------------------------------------
-
-.. automodule:: telethon.extensions.binaryreader
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.extensions\.markdown module
--------------------------------------
-
-.. automodule:: telethon.extensions.markdown
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.extensions\.html module
----------------------------------
-
-.. automodule:: telethon.extensions.html
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/readthedocs/telethon.network.rst b/readthedocs/telethon.network.rst
deleted file mode 100644
index 79da891b..00000000
--- a/readthedocs/telethon.network.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-telethon\.network package
-=========================
-
-
-telethon\.network\.connection module
-------------------------------------
-
-.. automodule:: telethon.network.connection
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.network\.mtprotoplainsender module
-------------------------------------------------
-
-.. automodule:: telethon.network.mtprotoplainsender
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.network\.mtprotosender module
------------------------------------------
-
-.. automodule:: telethon.network.mtprotosender
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.network\.authenticator module
----------------------------------------
-
-.. automodule:: telethon.network.authenticator
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/readthedocs/telethon.rst b/readthedocs/telethon.rst
deleted file mode 100644
index e91a3ee8..00000000
--- a/readthedocs/telethon.rst
+++ /dev/null
@@ -1,90 +0,0 @@
-.. _telethon-package:
-
-
-telethon package
-================
-
-
-telethon\.client module
------------------------
-
-.. toctree::
-
- telethon.client
-
-.. automodule:: telethon.client
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-telethon\.utils module
-----------------------
-
-.. automodule:: telethon.utils
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-telethon\.helpers module
-------------------------
-
-.. automodule:: telethon.helpers
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-telethon\.events package
-------------------------
-
-.. toctree::
-
- telethon.events
-
-
-telethon\.sessions module
--------------------------
-
-.. automodule:: telethon.sessions
- :members:
- :undoc-members:
- :show-inheritance:
-
-telethon\.errors package
-------------------------
-
-.. toctree::
-
- telethon.errors
-
-telethon\.extensions package
-----------------------------
-
-.. toctree::
-
- telethon.extensions
-
-telethon\.network package
--------------------------
-
-.. toctree::
-
- telethon.network
-
-telethon\.tl package
---------------------
-
-.. toctree::
-
- telethon.tl
-
-
-Module contents
----------------
-
-.. automodule:: telethon
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/readthedocs/telethon.tl.rst b/readthedocs/telethon.tl.rst
deleted file mode 100644
index 7e8c1da1..00000000
--- a/readthedocs/telethon.tl.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-telethon\.tl\.custom package
-============================
-
-
-.. toctree::
-
- telethon.tl.custom
-
-
-telethon\.tl\.tlobject module
------------------------------
-
-.. automodule:: telethon.tl.tlobject
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/telethon/client/account.py b/telethon/client/account.py
index 3faa366c..884bfae3 100644
--- a/telethon/client/account.py
+++ b/telethon/client/account.py
@@ -120,7 +120,7 @@ class AccountMethods(UserMethods):
files: bool = None,
max_file_size: bool = None) -> 'TelegramClient':
"""
- Returns a :ref:`TelegramClient` which calls methods behind a takeout session.
+ Returns a :ref:`telethon-client` which calls methods behind a takeout session.
It does so by creating a proxy object over the current client through
which making requests will use :tl:`InvokeWithTakeoutRequest` to wrap
@@ -190,6 +190,20 @@ class AccountMethods(UserMethods):
max_file_size (`int`):
The maximum file size, in bytes, that you plan
to download for each message with media.
+
+ Example:
+
+ .. code-block:: python
+
+ from telethon import errors
+
+ try:
+ with client.takeout() as takeout:
+ for message in takeout.iter_messages(chat, wait_time=0):
+ ... # Do something with the message
+
+ except errors.TakeoutInitDelayError as e:
+ print('Must wait', e.seconds, 'before takeout')
"""
request_kwargs = dict(
contacts=contacts,
diff --git a/telethon/client/auth.py b/telethon/client/auth.py
index 6d70b059..9010c301 100644
--- a/telethon/client/auth.py
+++ b/telethon/client/auth.py
@@ -40,13 +40,6 @@ class AuthMethods(MessageParseMethods, UserMethods):
will be banned otherwise.** See https://telegram.org/tos
and https://core.telegram.org/api/terms.
- Example usage:
- >>> client = ...
- >>> client.start(phone)
- Please enter the code you received: 12345
- Please enter your password: *******
- (You are now logged in)
-
If the event loop is already running, this method returns a
coroutine that you should await on your own code; otherwise
the loop is ran until said coroutine completes.
@@ -91,6 +84,24 @@ class AuthMethods(MessageParseMethods, UserMethods):
Returns:
This `TelegramClient`, so initialization
can be chained with ``.start()``.
+
+ Example:
+ .. code-block:: python
+
+ client = TelegramClient('anon', api_id, api_hash)
+
+ # Starting as a bot account
+ client.start(bot_token=bot_token)
+
+ # Starting as an user account
+ client.start(phone)
+ # Please enter the code you received: 12345
+ # Please enter your password: *******
+ # (You are now logged in)
+
+ # Starting using a context manager (this calls start()):
+ with client:
+ pass
"""
if code_callback is None:
def code_callback():
@@ -452,6 +463,13 @@ class AuthMethods(MessageParseMethods, UserMethods):
Returns:
``True`` if the operation was successful.
+
+ Example:
+
+ .. code-block:: python
+
+ # Note: you will need to login again!
+ client.log_out()
"""
try:
await self(functions.auth.LogOutRequest())
diff --git a/telethon/client/bots.py b/telethon/client/bots.py
index 33af4c84..1fefecf0 100644
--- a/telethon/client/bots.py
+++ b/telethon/client/bots.py
@@ -39,6 +39,16 @@ class BotMethods(UserMethods):
Returns:
A list of `custom.InlineResult
`.
+
+ Example:
+
+ .. code-block:: python
+
+ # Make an inline query to @like
+ results = client.inline_query('like', 'Do you like Telethon?')
+
+ # Send the first result to some chat
+ message = results[0].click('TelethonOffTopic')
"""
bot = await self.get_input_entity(bot)
result = await self(functions.messages.GetInlineBotResultsRequest(
diff --git a/telethon/client/chats.py b/telethon/client/chats.py
index 23292525..273979f6 100644
--- a/telethon/client/chats.py
+++ b/telethon/client/chats.py
@@ -328,6 +328,23 @@ class ChatMethods(UserMethods):
with an additional ``.participant`` attribute which is the
matched :tl:`ChannelParticipant` type for channels/megagroups
or :tl:`ChatParticipants` for normal chats.
+
+ Example:
+
+ .. code-block:: python
+
+ # Show all user IDs in a chat
+ for user in client.iter_participants(chat):
+ print(user.id)
+
+ # Search by name
+ for user in client.iter_participants(chat, search='name'):
+ print(user.username)
+
+ # Filter by admins
+ from telethon.tl.types import ChannelParticipantsAdmins
+ for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
+ print(user.first_name)
"""
return _ParticipantsIter(
self,
@@ -343,7 +360,7 @@ class ChatMethods(UserMethods):
*args,
**kwargs) -> 'hints.TotalList':
"""
- Same as `iter_participants`, but returns a
+ Same as `iter_participants()`, but returns a
`TotalList ` instead.
"""
return await self.iter_participants(*args, **kwargs).collect()
@@ -457,6 +474,20 @@ class ChatMethods(UserMethods):
Yields:
Instances of `telethon.tl.custom.adminlogevent.AdminLogEvent`.
+
+ Example:
+
+ .. code-block:: python
+
+ for event in client.iter_admin_log(channel):
+ if event.changed_title:
+ print('The title changed from', event.old, 'to', event.new)
+
+ # Get a list of deleted message events which said "heck"
+ events = client.get_admin_log(channel, search='heck', delete=True)
+
+ # Print the old message before it was deleted
+ print(events[0].old)
"""
return _AdminLogIter(
self,
@@ -487,7 +518,7 @@ class ChatMethods(UserMethods):
*args,
**kwargs) -> 'hints.TotalList':
"""
- Same as `iter_admin_log`, but returns a ``list`` instead.
+ Same as `iter_admin_log()`, but returns a ``list`` instead.
"""
return await self.iter_admin_log(*args, **kwargs).collect()
diff --git a/telethon/client/dialogs.py b/telethon/client/dialogs.py
index a18aaddf..90c54bbc 100644
--- a/telethon/client/dialogs.py
+++ b/telethon/client/dialogs.py
@@ -138,6 +138,21 @@ class DialogMethods(UserMethods):
Yields:
Instances of `telethon.tl.custom.dialog.Dialog`.
+
+ Example:
+
+ .. code-block:: python
+
+ # Get all open conversation, print the title of the first
+ dialogs = client.get_dialogs()
+ first = dialogs[0]
+ print(first.title)
+
+ # Use the dialog somewhere else
+ client.send_message(first, 'hi')
+
+ # Get drafts
+ drafts = client.get_drafts()
"""
return _DialogsIter(
self,
@@ -150,7 +165,7 @@ class DialogMethods(UserMethods):
async def get_dialogs(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
"""
- Same as `iter_dialogs`, but returns a
+ Same as `iter_dialogs()`, but returns a
`TotalList ` instead.
"""
return await self.iter_dialogs(*args, **kwargs).collect()
@@ -169,7 +184,7 @@ class DialogMethods(UserMethods):
async def get_drafts(self: 'TelegramClient') -> 'hints.TotalList':
"""
- Same as :meth:`iter_drafts`, but returns a list instead.
+ Same as `iter_drafts()`, but returns a list instead.
"""
return await self.iter_drafts().collect()
@@ -257,6 +272,35 @@ class DialogMethods(UserMethods):
Returns:
A `Conversation `.
+
+ Example:
+
+ .. code-block:: python
+
+ # denotes outgoing messages you sent
+ # denotes incoming response messages
+ with bot.conversation(chat) as conv:
+ # Hi!
+ conv.send_message('Hi!')
+
+ # Hello!
+ hello = conv.get_response()
+
+ # Please tell me your name
+ conv.send_message('Please tell me your name')
+
+ # ?
+ name = conv.get_response().raw_text
+
+ while not any(x.isalpha() for x in name):
+ # Your name didn't have any letters! Try again
+ conv.send_message("Your name didn't have any letters! Try again")
+
+ # Lonami
+ name = conv.get_response().raw_text
+
+ # Thanks Lonami!
+ conv.send_message('Thanks {}!'.format(name))
"""
return custom.Conversation(
self,
diff --git a/telethon/client/downloads.py b/telethon/client/downloads.py
index 39a3eed3..6b404bf1 100644
--- a/telethon/client/downloads.py
+++ b/telethon/client/downloads.py
@@ -56,6 +56,13 @@ class DownloadMethods(UserMethods):
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
+
+ path = client.download_profile_photo('me')
+ print(path)
"""
# hex(crc32(x.encode('ascii'))) for x in
# ('User', 'Chat', 'UserFull', 'ChatFull')
@@ -173,6 +180,17 @@ class DownloadMethods(UserMethods):
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 = client.download_media(message)
+ client.download_media(message, filename)
+ # or
+ path = message.download_media()
+ message.download_media(filename)
+
"""
# TODO This won't work for messageService
if isinstance(message, types.Message):
diff --git a/telethon/client/messages.py b/telethon/client/messages.py
index deb4db41..473d6ddb 100644
--- a/telethon/client/messages.py
+++ b/telethon/client/messages.py
@@ -413,6 +413,31 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Telegram's flood wait limit for :tl:`GetHistoryRequest` seems to
be around 30 seconds per 10 requests, therefore a sleep of 1
second is the default for this limit (or above).
+
+ Example:
+
+ .. code-block:: python
+
+ # From most-recent to oldest
+ for message in client.iter_messages(chat):
+ print(message.id, message.text)
+
+ # From oldest to most-recent
+ for message in client.iter_messages(chat, reverse=True):
+ print(message.id, message.text)
+
+ # Filter by sender
+ for message in client.iter_messages(chat, from_user='me'):
+ print(message.text)
+
+ # Server-side search with fuzzy text
+ for message in client.iter_messages(chat, search='hello'):
+ print(message.id)
+
+ # Filter by message type:
+ from telethon.tl.types import InputMessagesFilterPhotos
+ for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
+ print(message.photo)
"""
if ids is not None:
@@ -436,7 +461,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
async def get_messages(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
"""
- Same as `iter_messages`, but returns a
+ Same as `iter_messages()`, but returns a
`TotalList ` instead.
If the `limit` is not set, it will be 1 by default unless both
@@ -450,6 +475,21 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
If `ids` is present in the *named* arguments and is not a list,
a single `Message ` will be
returned for convenience instead of a list.
+
+ Example:
+
+ .. code-block:: python
+
+ # Get 0 photos and print the total to show how many photos there are
+ from telethon.tl.types import InputMessagesFilterPhotos
+ photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
+ print(photos.total)
+
+ # Get all the photos
+ photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
+
+ # Get messages by ID:
+ message_1337 = client.get_messages(chats, ids=1337)
"""
if len(args) == 1 and 'limit' not in kwargs:
if 'min_id' in kwargs and 'max_id' in kwargs:
@@ -501,6 +541,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
the bot.
Args:
+
entity (`entity`):
To who will it be sent.
@@ -556,7 +597,65 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
notify them. Set it to ``True`` to alter this behaviour.
Returns:
+
The sent `custom.Message `.
+
+ Example:
+
+ .. code-block:: python
+
+ client.send_message('lonami', 'Thanks for the Telethon library!')
+
+ # Replies and responses
+ message = client.send_message('me', 'Trying out **markdown**')
+ message.reply('Trying replies')
+ message.respond('Trying responses')
+
+ # Default to another parse mode
+ client.parse_mode = 'html'
+
+ client.send_message('me', 'Some bold and italic text')
+ client.send_message('me', 'An URL')
+ client.send_message('me', 'code
and pre\nblocks
')
+ client.send_message('me', 'Mentions')
+
+ # Explicit parse mode
+ # No parse mode by default
+ client.parse_mode = None
+
+ # ...but here I want markdown
+ client.send_message('me', 'Hello, **world**!', parse_mode='md')
+
+ # ...and here I need HTML
+ client.send_message('me', 'Hello, world!', parse_mode='html')
+
+ # If you logged in as a bot account, you can send buttons
+ from telethon import events, Button
+
+ @client.on(events.CallbackQuery)
+ async def callback(event):
+ await event.edit('Thank you for clicking {}!'.format(event.data))
+
+ # Single inline button
+ client.send_message(chat, 'A single button, with "clk1" as data',
+ buttons=Button.inline('Click me', b'clk1'))
+
+ # Matrix of inline buttons
+ client.send_message(chat, 'Pick one from this grid', buttons=[
+ [Button.inline('Left'), Button.inline('Right')],
+ [Button.url('Check this site!', 'https://lonamiwebs.github.io')]
+ ])
+
+ # Reply keyboard
+ client.send_message(chat, 'Welcome', buttons=[
+ Button.text('Thanks!', resize=True, single_use=True),
+ Button.request_phone('Send phone'),
+ Button.request_location('Send location')
+ ])
+
+ # Forcing replies or clearing buttons.
+ client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
+ client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
"""
if file is not None:
return await self.send_file(
@@ -685,6 +784,25 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Note that if all messages are invalid (i.e. deleted) the call
will fail with ``MessageIdInvalidError``. If only some are
invalid, the list will have ``None`` instead of those messages.
+
+ Example:
+
+ .. code-block:: python
+
+ # a single one
+ client.forward_messages(chat, message)
+ # or
+ client.forward_messages(chat, message_id, from_chat)
+ # or
+ message.forward_to(chat)
+
+ # multiple
+ client.forward_messages(chat, messages)
+ # or
+ client.forward_messages(chat, message_ids, from_chat)
+
+ # Forwarding as a copy
+ client.send_message(chat, message)
"""
single = not utils.is_list_like(messages)
if single:
@@ -829,6 +947,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
The edited `telethon.tl.custom.message.Message`, unless
`entity` was a :tl:`InputBotInlineMessageID` in which
case this method returns a boolean.
+
+ Example:
+
+ .. code-block:: python
+
+ client.edit_message(message, 'New text')
+ # or
+ message.edit('New text')
+ # or
+ client.edit_message(chat, message_id, 'New text')
"""
if isinstance(entity, types.InputBotInlineMessageID):
text = message
@@ -900,6 +1028,14 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
Returns:
A list of :tl:`AffectedMessages`, each item being the result
for the delete calls of the messages in chunks of 100 each.
+
+ Example:
+
+ .. code-block:: python
+
+ client.delete_messages(chat, messages)
+ # or
+ message.delete()
"""
if not utils.is_list_like(message_ids):
message_ids = (message_ids,)
@@ -955,6 +1091,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
If no message is provided, this will be the only action
taken.
+
+ Example:
+
+ .. code-block:: python
+
+ client.send_read_acknowledge(last_message)
+ # or
+ client.send_read_acknowledge(last_message_id)
+ # or
+ client.send_read_acknowledge(messages)
"""
if max_id is None:
if not message:
diff --git a/telethon/client/telegrambaseclient.py b/telethon/client/telegrambaseclient.py
index 3f6d1422..85d6fd23 100644
--- a/telethon/client/telegrambaseclient.py
+++ b/telethon/client/telegrambaseclient.py
@@ -396,6 +396,13 @@ class TelegramBaseClient(abc.ABC):
If the event loop is already running, this method returns a
coroutine that you should await on your own code; otherwise
the loop is ran until said coroutine completes.
+
+ Example:
+
+ .. code-block:: python
+
+ # You don't need to use this if you used "with client"
+ client.disconnect()
"""
if self._loop.is_running():
return self._disconnect_coro()
diff --git a/telethon/client/updates.py b/telethon/client/updates.py
index 927fb411..01e1aca0 100644
--- a/telethon/client/updates.py
+++ b/telethon/client/updates.py
@@ -117,7 +117,7 @@ class UpdateMethods(UserMethods):
callback: callable,
event: EventBuilder = None) -> int:
"""
- Inverse operation of `add_event_handler`.
+ Inverse operation of `add_event_handler()`.
If no event is given, all events for this callback are removed.
Returns how many callbacks were removed.
diff --git a/telethon/client/uploads.py b/telethon/client/uploads.py
index b141767c..888cbfd6 100644
--- a/telethon/client/uploads.py
+++ b/telethon/client/uploads.py
@@ -232,6 +232,32 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
Returns:
The `telethon.tl.custom.message.Message` (or messages) containing
the sent file, or messages if a list of them was passed.
+
+ Example:
+
+ .. code-block:: python
+
+ # Normal files like photos
+ client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
+ # or
+ client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
+
+ # Voice notes or round videos
+ client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
+ client.send_file(chat, '/my/videos/video.mp4', video_note=True)
+
+ # Custom thumbnails
+ client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
+
+ # Only documents
+ client.send_file(chat, '/my/photos/photo.png', force_document=True)
+
+ # Albums
+ client.send_file(chat, [
+ '/my/photos/holiday1.jpg',
+ '/my/photos/holiday2.jpg',
+ '/my/drawings/portrait.png'
+ ])
"""
# i.e. ``None`` was used
if not file:
@@ -427,6 +453,23 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
:tl:`InputFileBig` if the file size is larger than 10MB,
`telethon.tl.custom.inputsizedfile.InputSizedFile`
(subclass of :tl:`InputFile`) otherwise.
+
+ Example:
+
+ .. code-block:: python
+
+ # Photos as photo and document
+ file = client.upload_file('photo.jpg')
+ client.send_file(chat, file) # sends as photo
+ client.send_file(chat, file, force_document=True) # sends as document
+
+ file.name = 'not a photo.jpg'
+ client.send_file(chat, file, force_document=True) # document, new name
+
+ # As song or as voice note
+ file = client.upload_file('song.ogg')
+ client.send_file(chat, file) # sends as song
+ client.send_file(chat, file, voice_note=True) # sends as voice note
"""
if isinstance(file, (types.InputFile, types.InputFileBig)):
return file # Already uploaded
diff --git a/telethon/client/users.py b/telethon/client/users.py
index beba42b1..3ad3564c 100644
--- a/telethon/client/users.py
+++ b/telethon/client/users.py
@@ -191,6 +191,27 @@ class UserMethods(TelegramBaseClient):
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 = client.get_entity('me')
+ print(utils.get_display_name(me))
+
+ chat = client.get_input_entity('username')
+ 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.
+ for message in client.iter_messages('username'):
+ ...
+
+ # Note that for this to work the phone number must be in your contacts
+ some_id = client.get_peer_id('+34123456789')
"""
single = not utils.is_list_like(entity)
if single:
diff --git a/telethon/events/__init__.py b/telethon/events/__init__.py
index 25b2d4e9..0b1c16c6 100644
--- a/telethon/events/__init__.py
+++ b/telethon/events/__init__.py
@@ -42,7 +42,7 @@ class StopPropagation(Exception):
def register(event=None):
"""
Decorator method to *register* event handlers. This is the client-less
- `add_event_handler
+ `add_event_handler()
` variant.
Note that this method only registers callbacks as handlers,
diff --git a/telethon/events/inlinequery.py b/telethon/events/inlinequery.py
index 4845295f..7946ecb5 100644
--- a/telethon/events/inlinequery.py
+++ b/telethon/events/inlinequery.py
@@ -178,6 +178,20 @@ class InlineQuery(EventBuilder):
switch_pm_param (`str`, optional):
Optional parameter to start the bot with if
`switch_pm` was used.
+
+ Example:
+
+ .. code-block:: python
+
+ @bot.on(events.InlineQuery)
+ async def handler(event):
+ builder = event.builder
+
+ rev_text = event.text[::-1]
+ await event.answer([
+ builder.article('Reverse text', text=rev_text),
+ builder.photo('/path/to/photo.jpg')
+ ])
"""
if self._answered:
return
diff --git a/telethon/events/messageread.py b/telethon/events/messageread.py
index fd8d73db..1b782db1 100644
--- a/telethon/events/messageread.py
+++ b/telethon/events/messageread.py
@@ -95,7 +95,7 @@ class MessageRead(EventBuilder):
async def get_messages(self):
"""
- Returns the list of `telethon.tl.custom.message.Message`
+ Returns the list of `Message `
**which contents'** were read.
Use :meth:`is_read` if you need to check whether a message
diff --git a/telethon/events/userupdate.py b/telethon/events/userupdate.py
index 63ebb4cf..0357f870 100644
--- a/telethon/events/userupdate.py
+++ b/telethon/events/userupdate.py
@@ -190,23 +190,23 @@ class UserUpdate(EventBuilder):
@property
def user(self):
- """Alias for `sender`."""
+ """Alias for `sender `."""
return self.sender
async def get_user(self):
- """Alias for `get_sender`."""
+ """Alias for `get_sender `."""
return await self.get_sender()
@property
def input_user(self):
- """Alias for `input_sender`."""
+ """Alias for `input_sender `."""
return self.input_sender
async def get_input_user(self):
- """Alias for `get_input_sender`."""
+ """Alias for `get_input_sender `."""
return await self.get_input_sender()
@property
def user_id(self):
- """Alias for `sender_id`."""
+ """Alias for `sender_id `."""
return self.sender_id
diff --git a/telethon/tl/custom/inlinebuilder.py b/telethon/tl/custom/inlinebuilder.py
index 5edb1438..2f4cc7d4 100644
--- a/telethon/tl/custom/inlinebuilder.py
+++ b/telethon/tl/custom/inlinebuilder.py
@@ -33,11 +33,11 @@ class InlineBuilder:
May be ``True`` to indicate that the game will be sent.
buttons (`list`, `custom.Button `, :tl:`KeyboardButton`, optional):
- Same as ``buttons`` for `client.send_message
+ Same as ``buttons`` for `client.send_message()
`.
parse_mode (`str`, optional):
- Same as ``parse_mode`` for `client.send_message
+ Same as ``parse_mode`` for `client.send_message()
`.
id (`str`, optional):
@@ -119,7 +119,7 @@ class InlineBuilder:
Args:
file (`obj`, optional):
- Same as ``file`` for `client.send_file
+ Same as ``file`` for `client.send_file()
`.
"""
try:
@@ -173,7 +173,7 @@ class InlineBuilder:
Args:
file (`obj`):
- Same as ``file`` for `client.send_file
+ Same as ``file`` for `client.send_file()
`.
title (`str`, optional):
diff --git a/telethon/tl/custom/message.py b/telethon/tl/custom/message.py
index d32129d6..f5ce9ece 100644
--- a/telethon/tl/custom/message.py
+++ b/telethon/tl/custom/message.py
@@ -784,6 +784,22 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
behave as if it clicked a button with said data. Note
that if the message does not have this data, it will
``raise DataInvalidError``.
+
+ Example:
+
+ .. code-block:: python
+
+ # Click the first button
+ message.click(0)
+
+ # Click some row/column
+ message.click(row, column)
+
+ # Click by text
+ message.click(text='👍')
+
+ # Click by data
+ message.click(data=b'payload')
"""
if not self._client:
return
diff --git a/telethon/utils.py b/telethon/utils.py
index 0a4f09bb..e8e71af5 100644
--- a/telethon/utils.py
+++ b/telethon/utils.py
@@ -937,11 +937,12 @@ def _encode_telegram_base64(string):
def resolve_bot_file_id(file_id):
"""
- Given a Bot API-style `file_id`, returns the media it represents.
- If the `file_id` is not valid, ``None`` is returned instead.
+ Given a Bot API-style `file_id `,
+ returns the media it represents. If the `file_id `
+ is not valid, ``None`` is returned instead.
- Note that the `file_id` does not have information such as image
- dimensions or file size, so these will be zero if present.
+ Note that the `file_id ` does not have information
+ such as image dimensions or file size, so these will be zero if present.
For thumbnails, the photo ID and hash will always be zero.
"""