diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..c3b69284 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at dan@pyrogram.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000..e721fd98 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1 @@ +# How to Contribute diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..e0556d54 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug Report +about: Create a bug report affecting the library +labels: "bug" +--- + + + +## Checklist +- [ ] I am sure the error is coming from Pyrogram's code and not elsewhere. +- [ ] I have searched in the issue tracker for similar bug reports, including closed ones. +- [ ] I ran `pip3 install -U https://github.com/pyrogram/pyrogram/archive/develop.zip` and reproduced the issue using the latest development version. + +## Description +A clear and concise description of the problem. + +## Steps to Reproduce +[A minimal, complete and verifiable example](https://stackoverflow.com/help/mcve). + +## Traceback +The full traceback (if applicable). \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..70a39192 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature Request +about: Suggest ideas, new features or enhancements +labels: "enhancement" +--- + + + +## Checklist +- [ ] I believe the idea is awesome and would benefit the library. +- [ ] I have searched in the issue tracker for similar requests, including closed ones. + +## Description +A detailed description of the request. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..737304d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,15 @@ +--- +name: Ask Question +about: Ask a Pyrogram related question +title: For Q&A purposes, please read this template body +labels: "question" +--- + + + +# Important +This place is for issues about Pyrogram, it's **not a forum**. + +If you'd like to post a question, please move to https://stackoverflow.com or join the Telegram community by following the description in https://t.me/pyrogram. + +Thanks. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index 80c061ff..97d04588 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ ## Include -include COPYING COPYING.lesser NOTICE requirements.txt +include README.md COPYING COPYING.lesser NOTICE requirements.txt recursive-include compiler *.py *.tl *.tsv *.txt recursive-include pyrogram mime.types diff --git a/README.md b/README.md new file mode 100644 index 00000000..4e758b5a --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +

+ + Pyrogram + +
+ Telegram MTProto API Framework for Python +
+ + Documentation + + • + + Releases + + • + + Community + +

+ +## Pyrogram + +``` python +from pyrogram import Client, Filters + +app = Client("my_account") + + +@app.on_message(Filters.private) +def hello(client, message): + message.reply("Hello {}".format(message.from_user.first_name)) + + +app.run() +``` + +**Pyrogram** is an elegant, easy-to-use [Telegram](https://telegram.org/) client library and framework written from the +ground up in Python and C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the [MTProto API](https://core.telegram.org/api#telegram-api). + +> [Pyrogram in fully-asynchronous mode is also available »](https://github.com/pyrogram/pyrogram/issues/181) +> +> [Working PoC of Telegram voice calls using Pyrogram »](https://github.com/bakatrouble/pytgvoip) + +### Features + +- **Easy**: You can install Pyrogram with pip and start building your applications right away. +- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way. +- **Fast**: Crypto parts are boosted up by [TgCrypto](https://github.com/pyrogram/tgcrypto), a high-performance library + written in pure C. +- **Documented**: Pyrogram API methods, types and public interfaces are well documented. +- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. +- **Updated**, to make use of the latest Telegram API version and features. +- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed. +- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code. +- **Comprehensive**: Execute any advanced action an official client is able to do, and even more. + +### Requirements + +- Python 3.4 or higher. +- A [Telegram API key](https://docs.pyrogram.org/intro/setup#api-keys). + +### Installing + +``` bash +pip3 install pyrogram +``` + +### Resources + +- The Docs contain lots of resources to help you getting started with Pyrogram: https://docs.pyrogram.org. +- Reading [Examples in this repository](https://github.com/pyrogram/pyrogram/tree/master/examples) is also a good way + for learning how Pyrogram works. +- Seeking extra help? Don't be shy, come join and ask our [Community](https://t.me/PyrogramChat)! +- For other requests you can send an [Email](mailto:dan@pyrogram.org) or a [Message](https://t.me/haskell). + +### Contributing + +Pyrogram is brand new, and **you are welcome to try it and help make it even better** by either submitting pull +requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code +and documentation. Any help is appreciated! + +### Copyright & License + +- Copyright (C) 2017-2019 Dan Tès <> +- Licensed under the terms of the [GNU Lesser General Public License v3 or later (LGPLv3+)](COPYING.lesser) diff --git a/README.rst b/README.rst deleted file mode 100644 index dfb03abc..00000000 --- a/README.rst +++ /dev/null @@ -1,131 +0,0 @@ -|header| - -Pyrogram -======== - -.. code-block:: python - - from pyrogram import Client, Filters - - app = Client("my_account") - - - @app.on_message(Filters.private) - def hello(client, message): - message.reply("Hello {}".format(message.from_user.first_name)) - - - app.run() - -**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and C. -It enables you to easily create custom apps using both user and bot identities (bot API alternative) via the `MTProto API`_. - - `Pyrogram in fully-asynchronous mode is also available » `_ - - `Working PoC of Telegram voice calls using Pyrogram » `_ - -Features --------- - -- **Easy**: You can install Pyrogram with pip and start building your applications right away. -- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way. -- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C. -- **Documented**: Pyrogram API methods, types and public interfaces are well documented. -- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. -- **Updated**, to the latest Telegram API version, currently Layer 97 on top of `MTProto 2.0`_. -- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code. -- **Comprehensive**: Execute any advanced action an official client is able to do, and even more. - -Requirements ------------- - -- Python 3.4 or higher. -- A `Telegram API key`_. - -Installing ----------- - -.. code:: shell - - pip3 install pyrogram - -Resources ---------- - -- The Docs contain lots of resources to help you getting started with Pyrogram: https://docs.pyrogram.ml. -- Reading `Examples in this repository`_ is also a good way for learning how Pyrogram works. -- Seeking extra help? Don't be shy, come join and ask our Community_! -- For other requests you can send an Email_ or a Message_. - -Contributing ------------- - -Pyrogram is brand new, and **you are welcome to try it and help make it even better** by either submitting pull -requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code -and documentation. Any help is appreciated! - -Copyright & License -------------------- - -- Copyright (C) 2017-2019 Dan Tès -- Licensed under the terms of the `GNU Lesser General Public License v3 or later (LGPLv3+)`_ - -.. _`Telegram`: https://telegram.org/ -.. _`MTProto API`: https://core.telegram.org/api#telegram-api -.. _`Telegram API key`: https://docs.pyrogram.ml/start/ProjectSetup#api-keys -.. _`Community`: https://t.me/PyrogramChat -.. _`Examples in this repository`: https://github.com/pyrogram/pyrogram/tree/master/examples -.. _`GitHub`: https://github.com/pyrogram/pyrogram/issues -.. _`Email`: admin@pyrogram.ml -.. _`Message`: https://t.me/haskell -.. _TgCrypto: https://github.com/pyrogram/tgcrypto -.. _`MTProto 2.0`: https://core.telegram.org/mtproto -.. _`GNU Lesser General Public License v3 or later (LGPLv3+)`: COPYING.lesser - -.. |header| raw:: html - -

- -
Pyrogram Logo
-
-

- -

- Telegram MTProto API Framework for Python - -
- - Documentation - - • - - Changelog - - • - - Community - -
- - Schema Layer - - - TgCrypto Version - -

- -.. |logo| image:: https://raw.githubusercontent.com/pyrogram/logos/master/logos/pyrogram_logo2.png - :target: https://pyrogram.ml - :alt: Pyrogram - -.. |description| replace:: **Telegram MTProto API Framework for Python** - -.. |schema| image:: https://img.shields.io/badge/schema-layer%2097-eda738.svg?longCache=true&colorA=262b30 - :target: compiler/api/source/main_api.tl - :alt: Schema Layer - -.. |tgcrypto| image:: https://img.shields.io/badge/tgcrypto-v1.1.1-eda738.svg?longCache=true&colorA=262b30 - :target: https://github.com/pyrogram/tgcrypto - :alt: TgCrypto Version diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py index 6be16ba5..21348336 100644 --- a/compiler/api/compiler.py +++ b/compiler/api/compiler.py @@ -328,15 +328,15 @@ def start(): ) if docstring_args: - docstring_args = "Args:\n " + "\n ".join(docstring_args) + docstring_args = "Parameters:\n " + "\n ".join(docstring_args) else: docstring_args = "No parameters required." docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args if c.section == "functions": - docstring_args += "\n\n Raises:\n :obj:`RPCError `" docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type) + else: references = get_references(".".join(filter(None, [c.namespace, c.name]))) @@ -462,7 +462,7 @@ def start(): ["{0}={0}".format(i[0]) for i in sorted_args if i != ("flags", "#")] ), slots=", ".join(['"{}"'.format(i[0]) for i in sorted_args if i != ("flags", "#")]), - qualname="{}{}".format("{}.".format(c.namespace) if c.namespace else "", c.name) + qualname="{}.{}{}".format(c.section, "{}.".format(c.namespace) if c.namespace else "", c.name) ) ) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 6ea2240d..2c67e66c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -21,7 +21,7 @@ import os import shutil HOME = "compiler/docs" -DESTINATION = "docs/source" +DESTINATION = "docs/source/telegram" FUNCTIONS_PATH = "pyrogram/api/functions" TYPES_PATH = "pyrogram/api/types" @@ -129,6 +129,6 @@ if "__main__" == __name__: FUNCTIONS_PATH = "../../pyrogram/api/functions" TYPES_PATH = "../../pyrogram/api/types" HOME = "." - DESTINATION = "../../docs/source" + DESTINATION = "../../docs/source/telegram" start() diff --git a/compiler/docs/template/page.txt b/compiler/docs/template/page.txt index 25a396fa..638a10cf 100644 --- a/compiler/docs/template/page.txt +++ b/compiler/docs/template/page.txt @@ -1,5 +1,5 @@ {title} {title_markup} -.. autoclass:: {full_class_path} +.. autoclass:: {full_class_path}() :members: diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index 8325040d..cbea977a 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -96,4 +96,6 @@ EXTERNAL_URL_INVALID The external media URL is invalid CHAT_NOT_MODIFIED The chat settings were not modified RESULTS_TOO_MUCH The result contains too many items RESULT_ID_DUPLICATE The result contains items with duplicated identifiers -ACCESS_TOKEN_INVALID The bot access token is invalid \ No newline at end of file +ACCESS_TOKEN_INVALID The bot access token is invalid +INVITE_HASH_EXPIRED The chat invite link is no longer valid +USER_BANNED_IN_CHANNEL You are limited, check @SpamBot for details \ No newline at end of file diff --git a/compiler/error/source/403_FORBIDDEN.tsv b/compiler/error/source/403_FORBIDDEN.tsv index 34433da7..dd1e98fa 100644 --- a/compiler/error/source/403_FORBIDDEN.tsv +++ b/compiler/error/source/403_FORBIDDEN.tsv @@ -2,4 +2,6 @@ id message CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup) CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users -MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat \ No newline at end of file +MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat +CHAT_SEND_MEDIA_FORBIDDEN You can't send media messages in this chat +MESSAGE_AUTHOR_REQUIRED You are not the author of this message \ No newline at end of file diff --git a/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv b/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv index d1c666c6..4dfe5994 100644 --- a/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv +++ b/compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv @@ -5,4 +5,7 @@ RPC_MCGET_FAIL Telegram is having internal problems. Please try again later PERSISTENT_TIMESTAMP_OUTDATED Telegram is having internal problems. Please try again later HISTORY_GET_FAILED Telegram is having internal problems. Please try again later REG_ID_GENERATE_FAILED Telegram is having internal problems. Please try again later -RANDOM_ID_DUPLICATE Telegram is having internal problems. Please try again later \ No newline at end of file +RANDOM_ID_DUPLICATE Telegram is having internal problems. Please try again later +WORKER_BUSY_TOO_LONG_RETRY Telegram is having internal problems. Please try again later +INTERDC_X_CALL_ERROR Telegram is having internal problems. Please try again later +INTERDC_X_CALL_RICH_ERROR Telegram is having internal problems. Please try again later \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 00000000..0ecbac7b --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://docs.pyrogram.org/sitemap.xml \ No newline at end of file diff --git a/docs/source/sitemap.py b/docs/sitemap.py similarity index 62% rename from docs/source/sitemap.py rename to docs/sitemap.py index 539bac0d..87c27849 100644 --- a/docs/source/sitemap.py +++ b/docs/sitemap.py @@ -18,17 +18,16 @@ import datetime import os -import re -canonical = "https://docs.pyrogram.ml" +canonical = "https://docs.pyrogram.org/" dirs = { - "start": ("weekly", 0.9), - "resources": ("weekly", 0.8), - "pyrogram": ("weekly", 0.8), - "functions": ("monthly", 0.7), - "types": ("monthly", 0.7), - "errors": ("weekly", 0.6) + ".": ("weekly", 1.0), + "intro": ("weekly", 0.8), + "start": ("weekly", 0.8), + "api": ("weekly", 0.6), + "topics": ("weekly", 0.6), + "telegram": ("weekly", 0.4) } @@ -37,10 +36,10 @@ def now(): with open("sitemap.xml", "w") as f: - f.write("\n") - f.write("\n") + f.write('\n') + f.write('\n') - urls = [(canonical, now(), "weekly", 1.0)] + urls = [] def search(path): @@ -48,14 +47,27 @@ with open("sitemap.xml", "w") as f: for j in os.listdir(path): search("{}/{}".format(path, j)) except NotADirectoryError: - d = path.split("/")[0] - path = "{}/{}".format(canonical, path.split(".")[0]) - path = re.sub("^(.+)/index$", "\g<1>", path) - urls.append((path, now(), dirs[d][0], dirs[d][1])) + if not path.endswith(".rst"): + return + + path = path.split("/")[1:] + + if path[0].endswith(".rst"): + folder = "." + else: + folder = path[0] + + path = "{}{}".format(canonical, "/".join(path))[:-len(".rst")] + + if path.endswith("index"): + path = path[:-len("index")] + + urls.append((path, now(), *dirs[folder])) - for i in dirs.keys(): - search(i) + search("source") + + urls.sort(key=lambda x: x[3], reverse=True) for i in urls: f.write(" \n") diff --git a/docs/source/_images/logo.png b/docs/source/_images/logo.png deleted file mode 100644 index 1f06fa81..00000000 Binary files a/docs/source/_images/logo.png and /dev/null differ diff --git a/docs/source/_images/pyrogram.png b/docs/source/_images/pyrogram.png new file mode 100644 index 00000000..caadf983 Binary files /dev/null and b/docs/source/_images/pyrogram.png differ diff --git a/docs/source/api/bound-methods.rst b/docs/source/api/bound-methods.rst new file mode 100644 index 00000000..d93497fe --- /dev/null +++ b/docs/source/api/bound-methods.rst @@ -0,0 +1,102 @@ +Bound Methods +============= + +Some Pyrogram types define what are called bound methods. Bound methods are functions attached to a class which are +accessed via an instance of that class. They make it even easier to call specific methods by automatically inferring +some of the required arguments. + +.. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client + + app = Client("my_account") + + + @app.on_message() + def hello(client, message) + message.reply("hi") + + + app.run() + +.. currentmodule:: pyrogram + +- Message_ +- CallbackQuery_ +- InlineQuery_ + +.. _Message: + +Message +------- + +- :meth:`Message.click()` +- :meth:`Message.delete()` +- :meth:`Message.download()` +- :meth:`Message.edit()` +- :meth:`Message.edit_caption()` +- :meth:`Message.edit_media()` +- :meth:`Message.edit_reply_markup()` +- :meth:`Message.forward()` +- :meth:`Message.pin()` +- :meth:`Message.reply()` +- :meth:`Message.reply_animation()` +- :meth:`Message.reply_audio()` +- :meth:`Message.reply_cached_media()` +- :meth:`Message.reply_chat_action()` +- :meth:`Message.reply_contact()` +- :meth:`Message.reply_document()` +- :meth:`Message.reply_game()` +- :meth:`Message.reply_inline_bot_result()` +- :meth:`Message.reply_location()` +- :meth:`Message.reply_media_group()` +- :meth:`Message.reply_photo()` +- :meth:`Message.reply_poll()` +- :meth:`Message.reply_sticker()` +- :meth:`Message.reply_venue()` +- :meth:`Message.reply_video()` +- :meth:`Message.reply_video_note()` +- :meth:`Message.reply_voice()` + +.. automethod:: Message.click() +.. automethod:: Message.delete() +.. automethod:: Message.download() +.. automethod:: Message.edit() +.. automethod:: Message.edit_caption() +.. automethod:: Message.edit_media() +.. automethod:: Message.edit_reply_markup() +.. automethod:: Message.forward() +.. automethod:: Message.pin() +.. automethod:: Message.reply() +.. automethod:: Message.reply_animation() +.. automethod:: Message.reply_audio() +.. automethod:: Message.reply_cached_media() +.. automethod:: Message.reply_chat_action() +.. automethod:: Message.reply_contact() +.. automethod:: Message.reply_document() +.. automethod:: Message.reply_game() +.. automethod:: Message.reply_inline_bot_result() +.. automethod:: Message.reply_location() +.. automethod:: Message.reply_media_group() +.. automethod:: Message.reply_photo() +.. automethod:: Message.reply_poll() +.. automethod:: Message.reply_sticker() +.. automethod:: Message.reply_venue() +.. automethod:: Message.reply_video() +.. automethod:: Message.reply_video_note() +.. automethod:: Message.reply_voice() + +.. _CallbackQuery: + +CallbackQuery +------------- + +.. automethod:: CallbackQuery.answer() + +.. _InlineQuery: + +InlineQuery +----------- + +.. automethod:: InlineQuery.answer() \ No newline at end of file diff --git a/docs/source/api/client.rst b/docs/source/api/client.rst new file mode 100644 index 00000000..9527ca73 --- /dev/null +++ b/docs/source/api/client.rst @@ -0,0 +1,16 @@ +Pyrogram Client +=============== + +This is the Client class. It exposes high-level methods for an easy access to the API. + +.. code-block:: python + :emphasize-lines: 1-3 + + from pyrogram import Client + + app = Client("my_account") + + with app: + app.send_message("me", "Hi!") + +.. autoclass:: pyrogram.Client() diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst new file mode 100644 index 00000000..be8376f5 --- /dev/null +++ b/docs/source/api/decorators.rst @@ -0,0 +1,48 @@ +Decorators +========== + +While still being methods bound to the :obj:`Client ` class, decorators are of a special kind and thus deserve a +dedicated page. + +Decorators are able to register callback functions for handling updates in a much easier and cleaner way compared to +`Handlers `_; they do so by instantiating the correct handler and calling +:meth:`add_handler() `, automatically. All you need to do is adding the decorators on top +of your functions. + +.. code-block:: python + :emphasize-lines: 6 + + from pyrogram import Client + + app = Client("my_account") + + + @app.on_message() + def log(client, message): + print(message) + + + app.run() + +.. currentmodule:: pyrogram.Client + +.. autosummary:: + :nosignatures: + + on_message + on_callback_query + on_inline_query + on_deleted_messages + on_user_status + on_poll + on_disconnect + on_raw_update + +.. automethod:: pyrogram.Client.on_message() +.. automethod:: pyrogram.Client.on_callback_query() +.. automethod:: pyrogram.Client.on_inline_query() +.. automethod:: pyrogram.Client.on_deleted_messages() +.. automethod:: pyrogram.Client.on_user_status() +.. automethod:: pyrogram.Client.on_poll() +.. automethod:: pyrogram.Client.on_disconnect() +.. automethod:: pyrogram.Client.on_raw_update() \ No newline at end of file diff --git a/docs/source/api/errors.rst b/docs/source/api/errors.rst new file mode 100644 index 00000000..fad571e3 --- /dev/null +++ b/docs/source/api/errors.rst @@ -0,0 +1,72 @@ +RPC Errors +========== + +All Pyrogram API errors live inside the ``errors`` sub-package: ``pyrogram.errors``. +The errors ids listed here are shown as *UPPER_SNAKE_CASE*, but the actual exception names to import from Pyrogram +follow the usual *PascalCase* convention. + +.. code-block:: python + :emphasize-lines: 1, 5 + + from pyrogram.errors import FloodWait + + try: + ... + except FloodWait as e: + ... + +303 - SeeOther +-------------- + +.. csv-table:: + :file: ../../../compiler/error/source/303_SEE_OTHER.tsv + :delim: tab + :header-rows: 1 + +400 - BadRequest +---------------- + +.. csv-table:: + :file: ../../../compiler/error/source/400_BAD_REQUEST.tsv + :delim: tab + :header-rows: 1 + +401 - Unauthorized +------------------ + +.. csv-table:: + :file: ../../../compiler/error/source/401_UNAUTHORIZED.tsv + :delim: tab + :header-rows: 1 + +403 - Forbidden +--------------- + +.. csv-table:: + :file: ../../../compiler/error/source/403_FORBIDDEN.tsv + :delim: tab + :header-rows: 1 + +406 - NotAcceptable +------------------- + +.. csv-table:: + :file: ../../../compiler/error/source/406_NOT_ACCEPTABLE.tsv + :delim: tab + :header-rows: 1 + +420 - Flood +----------- + +.. csv-table:: + :file: ../../../compiler/error/source/420_FLOOD.tsv + :delim: tab + :header-rows: 1 + +500 - InternalServerError +------------------------- + +.. csv-table:: + :file: ../../../compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv + :delim: tab + :header-rows: 1 diff --git a/docs/source/pyrogram/Filters.rst b/docs/source/api/filters.rst similarity index 61% rename from docs/source/pyrogram/Filters.rst rename to docs/source/api/filters.rst index 091031ae..87faa801 100644 --- a/docs/source/pyrogram/Filters.rst +++ b/docs/source/api/filters.rst @@ -1,5 +1,5 @@ -Filters -======= +Update Filters +============== .. autoclass:: pyrogram.Filters :members: diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst new file mode 100644 index 00000000..90c8e614 --- /dev/null +++ b/docs/source/api/handlers.rst @@ -0,0 +1,47 @@ +Update Handlers +=============== + +Handlers are used to instruct Pyrogram about which kind of updates you'd like to handle with your callback functions. + +For a much more convenient way of registering callback functions have a look at `Decorators `_ instead. +In case you decided to manually create a handler, use :meth:`add_handler() ` to register +it. + +.. code-block:: python + :emphasize-lines: 1, 10 + + from pyrogram import Client, MessageHandler + + app = Client("my_account") + + + def dump(client, message): + print(message) + + + app.add_handler(MessageHandler(dump)) + + app.run() + +.. currentmodule:: pyrogram + +.. autosummary:: + :nosignatures: + + MessageHandler + DeletedMessagesHandler + CallbackQueryHandler + InlineQueryHandler + UserStatusHandler + PollHandler + DisconnectHandler + RawUpdateHandler + +.. autoclass:: MessageHandler() +.. autoclass:: DeletedMessagesHandler() +.. autoclass:: CallbackQueryHandler() +.. autoclass:: InlineQueryHandler() +.. autoclass:: UserStatusHandler() +.. autoclass:: PollHandler() +.. autoclass:: DisconnectHandler() +.. autoclass:: RawUpdateHandler() diff --git a/docs/source/api/methods.rst b/docs/source/api/methods.rst new file mode 100644 index 00000000..7c061d3a --- /dev/null +++ b/docs/source/api/methods.rst @@ -0,0 +1,265 @@ +Available Methods +================= + +All Pyrogram methods listed here are bound to a :obj:`Client ` instance. + +.. code-block:: python + :emphasize-lines: 6 + + from pyrogram import Client + + app = Client("my_account") + + with app: + app.send_message("haskell", "hi") + +.. currentmodule:: pyrogram.Client + +Utilities +--------- + +.. autosummary:: + :nosignatures: + + start + stop + restart + idle + run + add_handler + remove_handler + send + resolve_peer + save_file + stop_transmission + +Messages +-------- + +.. autosummary:: + :nosignatures: + + send_message + forward_messages + send_photo + send_audio + send_document + send_sticker + send_video + send_animation + send_voice + send_video_note + send_media_group + send_location + send_venue + send_contact + send_cached_media + send_chat_action + edit_message_text + edit_message_caption + edit_message_reply_markup + edit_message_media + delete_messages + get_messages + get_history + get_history_count + iter_history + send_poll + vote_poll + stop_poll + retract_vote + download_media + +Chats +----- + +.. autosummary:: + :nosignatures: + + join_chat + leave_chat + kick_chat_member + unban_chat_member + restrict_chat_member + promote_chat_member + export_chat_invite_link + set_chat_photo + delete_chat_photo + set_chat_title + set_chat_description + pin_chat_message + unpin_chat_message + get_chat + get_chat_member + get_chat_members + get_chat_members_count + iter_chat_members + get_dialogs + iter_dialogs + get_dialogs_count + restrict_chat + update_chat_username + +Users +----- + +.. autosummary:: + :nosignatures: + + get_me + get_users + get_user_profile_photos + get_user_profile_photos_count + set_user_profile_photo + delete_user_profile_photos + update_username + +Contacts +-------- + +.. autosummary:: + :nosignatures: + + add_contacts + get_contacts + get_contacts_count + delete_contacts + +Password +-------- + +.. autosummary:: + :nosignatures: + + enable_cloud_password + change_cloud_password + remove_cloud_password + +Bots +---- + +.. autosummary:: + :nosignatures: + + get_inline_bot_results + send_inline_bot_result + answer_callback_query + answer_inline_query + request_callback_answer + send_game + set_game_score + get_game_high_scores + +.. Utilities + --------- + +.. automethod:: pyrogram.Client.start() +.. automethod:: pyrogram.Client.stop() +.. automethod:: pyrogram.Client.restart() +.. automethod:: pyrogram.Client.idle() +.. automethod:: pyrogram.Client.run() +.. automethod:: pyrogram.Client.add_handler() +.. automethod:: pyrogram.Client.remove_handler() +.. automethod:: pyrogram.Client.send() +.. automethod:: pyrogram.Client.resolve_peer() +.. automethod:: pyrogram.Client.save_file() +.. automethod:: pyrogram.Client.stop_transmission() + +.. Messages + -------- + +.. automethod:: pyrogram.Client.send_message() +.. automethod:: pyrogram.Client.forward_messages() +.. automethod:: pyrogram.Client.send_photo() +.. automethod:: pyrogram.Client.send_audio() +.. automethod:: pyrogram.Client.send_document() +.. automethod:: pyrogram.Client.send_sticker() +.. automethod:: pyrogram.Client.send_video() +.. automethod:: pyrogram.Client.send_animation() +.. automethod:: pyrogram.Client.send_voice() +.. automethod:: pyrogram.Client.send_video_note() +.. automethod:: pyrogram.Client.send_media_group() +.. automethod:: pyrogram.Client.send_location() +.. automethod:: pyrogram.Client.send_venue() +.. automethod:: pyrogram.Client.send_contact() +.. automethod:: pyrogram.Client.send_cached_media() +.. automethod:: pyrogram.Client.send_chat_action() +.. automethod:: pyrogram.Client.edit_message_text() +.. automethod:: pyrogram.Client.edit_message_caption() +.. automethod:: pyrogram.Client.edit_message_reply_markup() +.. automethod:: pyrogram.Client.edit_message_media() +.. automethod:: pyrogram.Client.delete_messages() +.. automethod:: pyrogram.Client.get_messages() +.. automethod:: pyrogram.Client.get_history() +.. automethod:: pyrogram.Client.get_history_count() +.. automethod:: pyrogram.Client.iter_history() +.. automethod:: pyrogram.Client.send_poll() +.. automethod:: pyrogram.Client.vote_poll() +.. automethod:: pyrogram.Client.stop_poll() +.. automethod:: pyrogram.Client.retract_vote() +.. automethod:: pyrogram.Client.download_media() + +.. Chats + ----- + +.. automethod:: pyrogram.Client.join_chat() +.. automethod:: pyrogram.Client.leave_chat() +.. automethod:: pyrogram.Client.kick_chat_member() +.. automethod:: pyrogram.Client.unban_chat_member() +.. automethod:: pyrogram.Client.restrict_chat_member() +.. automethod:: pyrogram.Client.promote_chat_member() +.. automethod:: pyrogram.Client.export_chat_invite_link() +.. automethod:: pyrogram.Client.set_chat_photo() +.. automethod:: pyrogram.Client.delete_chat_photo() +.. automethod:: pyrogram.Client.set_chat_title() +.. automethod:: pyrogram.Client.set_chat_description() +.. automethod:: pyrogram.Client.pin_chat_message() +.. automethod:: pyrogram.Client.unpin_chat_message() +.. automethod:: pyrogram.Client.get_chat() +.. automethod:: pyrogram.Client.get_chat_member() +.. automethod:: pyrogram.Client.get_chat_members() +.. automethod:: pyrogram.Client.get_chat_members_count() +.. automethod:: pyrogram.Client.iter_chat_members() +.. automethod:: pyrogram.Client.get_dialogs() +.. automethod:: pyrogram.Client.iter_dialogs() +.. automethod:: pyrogram.Client.get_dialogs_count() +.. automethod:: pyrogram.Client.restrict_chat() +.. automethod:: pyrogram.Client.update_chat_username() + +.. Users + ----- + +.. automethod:: pyrogram.Client.get_me() +.. automethod:: pyrogram.Client.get_users() +.. automethod:: pyrogram.Client.get_user_profile_photos() +.. automethod:: pyrogram.Client.get_user_profile_photos_count() +.. automethod:: pyrogram.Client.set_user_profile_photo() +.. automethod:: pyrogram.Client.delete_user_profile_photos() +.. automethod:: pyrogram.Client.update_username() + +.. Contacts + -------- + +.. automethod:: pyrogram.Client.add_contacts() +.. automethod:: pyrogram.Client.get_contacts() +.. automethod:: pyrogram.Client.get_contacts_count() +.. automethod:: pyrogram.Client.delete_contacts() + +.. Password + -------- + +.. automethod:: pyrogram.Client.enable_cloud_password() +.. automethod:: pyrogram.Client.change_cloud_password() +.. automethod:: pyrogram.Client.remove_cloud_password() + +.. Bots + ---- + +.. automethod:: pyrogram.Client.get_inline_bot_results() +.. automethod:: pyrogram.Client.send_inline_bot_result() +.. automethod:: pyrogram.Client.answer_callback_query() +.. automethod:: pyrogram.Client.answer_inline_query() +.. automethod:: pyrogram.Client.request_callback_answer() +.. automethod:: pyrogram.Client.send_game() +.. automethod:: pyrogram.Client.set_game_score() +.. automethod:: pyrogram.Client.get_game_high_scores() diff --git a/docs/source/api/types.rst b/docs/source/api/types.rst new file mode 100644 index 00000000..d911520c --- /dev/null +++ b/docs/source/api/types.rst @@ -0,0 +1,184 @@ +Available Types +=============== + +All Pyrogram types listed here are accessible through the main package directly. + +.. code-block:: python + :emphasize-lines: 1 + + from pyrogram import User, Message, ... + +.. note:: + + **Optional** fields may not exist when irrelevant -- i.e.: they will contain the value of ``None`` and aren't shown + when, for example, using ``print()``. + +.. currentmodule:: pyrogram + +Users & Chats +------------- + +.. autosummary:: + :nosignatures: + + User + UserStatus + Chat + ChatPreview + ChatPhoto + ChatMember + ChatMembers + ChatPermissions + Dialog + Dialogs + +Messages & Media +---------------- + +.. autosummary:: + :nosignatures: + + Message + Messages + MessageEntity + Photo + PhotoSize + UserProfilePhotos + Audio + Document + Animation + Video + Voice + VideoNote + Contact + Location + Venue + Sticker + Game + Poll + PollOption + +Keyboards +--------- + +.. autosummary:: + :nosignatures: + + ReplyKeyboardMarkup + KeyboardButton + ReplyKeyboardRemove + InlineKeyboardMarkup + InlineKeyboardButton + ForceReply + CallbackQuery + GameHighScore + GameHighScores + CallbackGame + +Input Media +----------- + +.. autosummary:: + :nosignatures: + + InputMedia + InputMediaPhoto + InputMediaVideo + InputMediaAudio + InputMediaAnimation + InputMediaDocument + InputPhoneContact + +Inline Mode +------------ + +.. autosummary:: + :nosignatures: + + InlineQuery + InlineQueryResult + InlineQueryResultArticle + +InputMessageContent +------------------- + +.. autosummary:: + :nosignatures: + + InputMessageContent + InputTextMessageContent + +.. User & Chats + ------------ + +.. autoclass:: User() +.. autoclass:: UserStatus() +.. autoclass:: Chat() +.. autoclass:: ChatPreview() +.. autoclass:: ChatPhoto() +.. autoclass:: ChatMember() +.. autoclass:: ChatMembers() +.. autoclass:: ChatPermissions() +.. autoclass:: Dialog() +.. autoclass:: Dialogs() + +.. Messages & Media + ---------------- + +.. autoclass:: Message() +.. autoclass:: Messages() +.. autoclass:: MessageEntity() +.. autoclass:: Photo() +.. autoclass:: PhotoSize() +.. autoclass:: UserProfilePhotos() +.. autoclass:: Audio() +.. autoclass:: Document() +.. autoclass:: Animation() +.. autoclass:: Video() +.. autoclass:: Voice() +.. autoclass:: VideoNote() +.. autoclass:: Contact() +.. autoclass:: Location() +.. autoclass:: Venue() +.. autoclass:: Sticker() +.. autoclass:: Game() +.. autoclass:: Poll() +.. autoclass:: PollOption() + +.. Keyboards + --------- + +.. autoclass:: ReplyKeyboardMarkup() +.. autoclass:: KeyboardButton() +.. autoclass:: ReplyKeyboardRemove() +.. autoclass:: InlineKeyboardMarkup() +.. autoclass:: InlineKeyboardButton() +.. autoclass:: ForceReply() +.. autoclass:: CallbackQuery() +.. autoclass:: GameHighScore() +.. autoclass:: GameHighScores() +.. autoclass:: CallbackGame() + +.. Input Media + ----------- + +.. autoclass:: InputMedia() +.. autoclass:: InputMediaPhoto() +.. autoclass:: InputMediaVideo() +.. autoclass:: InputMediaAudio() +.. autoclass:: InputMediaAnimation() +.. autoclass:: InputMediaDocument() +.. autoclass:: InputPhoneContact() + +.. Inline Mode + ----------- + +.. autoclass:: InlineQuery() +.. autoclass:: InlineQueryResult() +.. autoclass:: InlineQueryResultArticle() + +.. InputMessageContent + ------------------- + +.. autoclass:: InputMessageContent() +.. autoclass:: InputTextMessageContent() diff --git a/docs/source/conf.py b/docs/source/conf.py index 8acfde42..e079ec68 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,198 +1,68 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2019 Dan Tès # -# Pyrogram documentation build configuration file, created by -# sphinx-quickstart on Fri Dec 29 11:35:55 2017. +# This file is part of Pyrogram. # -# This file is execfile()d with the current directory set to its -# containing dir. +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# Note that not all possible configuration values are present in this -# autogenerated file. +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. # -# All configuration values have a default; values that are commented out -# serve to show the default. +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# import os import sys -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath("../..")) -# Import after sys.path.insert() to avoid issues from pyrogram import __version__ from pygments.styles.friendly import FriendlyStyle FriendlyStyle.background_color = "#f3f2f1" -# -- General configuration ------------------------------------------------ +project = "Pyrogram" +copyright = "2017-2019, Dan" +author = "Dan" -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', - 'sphinx.ext.autosummary' + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx.ext.autosummary" ] -# Don't show source files on docs -html_show_sourcelink = True +master_doc = "index" +source_suffix = ".rst" +autodoc_member_order = "bysource" -# Order by source, not alphabetically -autodoc_member_order = 'bysource' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'Pyrogram' -copyright = '2017-2019, Dan Tès' -author = 'Dan Tès' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = "version " + __version__ -# The full version, including alpha/beta/rc tags. +version = __version__ release = version +version_rst = ".. |version| replace:: {}".format(version) -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None +templates_path = ["_templates"] -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = [] +napoleon_use_rtype = False -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'friendly' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# -- Options for HTML output ---------------------------------------------- +pygments_style = "friendly" html_title = "Pyrogram Documentation" - -# Overridden by template +html_theme = "sphinx_rtd_theme" +html_static_path = ["_static"] +html_show_sourcelink = True html_show_copyright = False - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = { - 'canonical_url': "https://docs.pyrogram.ml/", - 'collapse_navigation': False, - 'sticky_navigation': False, - 'logo_only': True, - 'display_version': True + "canonical_url": "https://docs.pyrogram.org/", + "collapse_navigation": True, + "sticky_navigation": False, + "logo_only": True, + "display_version": True } -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -html_logo = '_images/logo.png' - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -html_favicon = '_images/favicon.ico' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'relations.html', # needs 'show_related': True theme option to display - 'searchbox.html', - ] -} - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Pyrogramdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'Pyrogram.tex', 'Pyrogram Documentation', - 'Dan Tès', 'manual'), -] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pyrogram', 'Pyrogram Documentation', - [author], 1) -] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'Pyrogram', 'Pyrogram Documentation', - author, 'Pyrogram', 'One line description of project.', - 'Miscellaneous'), -] +html_logo = "_images/pyrogram.png" +html_favicon = "_images/favicon.ico" diff --git a/docs/source/errors/BadRequest.rst b/docs/source/errors/BadRequest.rst deleted file mode 100644 index 2d56434c..00000000 --- a/docs/source/errors/BadRequest.rst +++ /dev/null @@ -1,7 +0,0 @@ -400 - Bad Request -================= - -.. module:: pyrogram.errors.BadRequest - -.. automodule:: pyrogram.errors.exceptions.bad_request_400 - :members: diff --git a/docs/source/errors/Flood.rst b/docs/source/errors/Flood.rst deleted file mode 100644 index 55098cbb..00000000 --- a/docs/source/errors/Flood.rst +++ /dev/null @@ -1,7 +0,0 @@ -420 - Flood -=========== - -.. module:: pyrogram.errors.Flood - -.. automodule:: pyrogram.errors.exceptions.flood_420 - :members: diff --git a/docs/source/errors/Forbidden.rst b/docs/source/errors/Forbidden.rst deleted file mode 100644 index cd794979..00000000 --- a/docs/source/errors/Forbidden.rst +++ /dev/null @@ -1,7 +0,0 @@ -403 - Forbidden -=============== - -.. module:: pyrogram.errors.Forbidden - -.. automodule:: pyrogram.errors.exceptions.forbidden_403 - :members: diff --git a/docs/source/errors/InternalServerError.rst b/docs/source/errors/InternalServerError.rst deleted file mode 100644 index 7f78d519..00000000 --- a/docs/source/errors/InternalServerError.rst +++ /dev/null @@ -1,7 +0,0 @@ -500 - Internal Server Error -=========================== - -.. module:: pyrogram.errors.InternalServerError - -.. automodule:: pyrogram.errors.exceptions.internal_server_error_500 - :members: diff --git a/docs/source/errors/NotAcceptable.rst b/docs/source/errors/NotAcceptable.rst deleted file mode 100644 index 5a8365fc..00000000 --- a/docs/source/errors/NotAcceptable.rst +++ /dev/null @@ -1,7 +0,0 @@ -406 - Not Acceptable -==================== - -.. module:: pyrogram.errors.NotAcceptable - -.. automodule:: pyrogram.errors.exceptions.not_acceptable_406 - :members: diff --git a/docs/source/errors/SeeOther.rst b/docs/source/errors/SeeOther.rst deleted file mode 100644 index f90902d0..00000000 --- a/docs/source/errors/SeeOther.rst +++ /dev/null @@ -1,7 +0,0 @@ -303 - See Other -=============== - -.. module:: pyrogram.errors.SeeOther - -.. automodule:: pyrogram.errors.exceptions.see_other_303 - :members: diff --git a/docs/source/errors/Unauthorized.rst b/docs/source/errors/Unauthorized.rst deleted file mode 100644 index d47ed3fb..00000000 --- a/docs/source/errors/Unauthorized.rst +++ /dev/null @@ -1,7 +0,0 @@ -401 - Unauthorized -================== - -.. module:: pyrogram.errors.Unauthorized - -.. automodule:: pyrogram.errors.exceptions.unauthorized_401 - :members: diff --git a/docs/source/errors/UnknownError.rst b/docs/source/errors/UnknownError.rst deleted file mode 100644 index 21495957..00000000 --- a/docs/source/errors/UnknownError.rst +++ /dev/null @@ -1,7 +0,0 @@ -520 - Unknown Error -=================== - -.. module:: pyrogram.errors.UnknownError - -.. autoexception:: pyrogram.errors.rpc_error.UnknownError - :members: diff --git a/docs/source/faq.rst b/docs/source/faq.rst new file mode 100644 index 00000000..b42332cd --- /dev/null +++ b/docs/source/faq.rst @@ -0,0 +1,201 @@ +Pyrogram FAQ +============ + +This FAQ page provides answers to common questions about Pyrogram and, to some extent, Telegram in general. + +.. tip:: + + If you think something interesting could be added here, feel free to propose it by opening a `Feature Request`_. + +.. contents:: Contents + :backlinks: none + :local: + :depth: 1 + +What is Pyrogram? +----------------- + +**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and +C. It enables you to easily create custom applications for both user and bot identities (bot API alternative) via the +`MTProto API`_ with the Python programming language. + +.. _Telegram: https://telegram.org +.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api + +Where does the name come from? +------------------------------ + +The name "Pyrogram" is composed by **pyro**, which comes from the Greek word *πῦρ (pyr)*, meaning fire, and **gram**, +from *Telegram*. The word *pyro* itself is built from *Python*, **py** for short, and the suffix **ro** to come up with +the word *fire*, which also inspired the project logo. + +How old is Pyrogram? +-------------------- + +Pyrogram was first released on December 12, 2017. The actual work on the framework began roughly three months prior the +initial public release on `GitHub`_. + +.. _GitHub: https://github.com/pyrogram/pyrogram + +Why Pyrogram? +------------- + +- **Easy**: You can install Pyrogram with pip and start building your applications right away. +- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way. +- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C. +- **Documented**: Pyrogram API methods, types and public interfaces are well documented. +- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. +- **Updated**, to make use of the latest Telegram API version and features. +- **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed. +- **Pluggable**: The `Smart Plugin`_ system allows to write components with minimal boilerplate code. +- **Comprehensive**: Execute any `advanced action`_ an official client is able to do, and even more. + +.. _TgCrypto: https://github.com/pyrogram/tgcrypto +.. _Smart Plugin: topics/smart-plugins +.. _advanced action: topics/advanced-usage + +What can MTProto do more than the Bot API? +------------------------------------------ + +For a detailed answer, please refer to the `MTProto vs. Bot API`_ page. + +.. _MTProto vs. Bot API: topics/mtproto-vs-botapi + +Why do I need an API key for bots? +---------------------------------- + +Requests against the official bot API endpoint are made via JSON/HTTP, but are handled by an intermediate server +application that implements the MTProto protocol -- just like Pyrogram -- and uses its own API key, which is always +required, but hidden to the public. + +.. figure:: https://i.imgur.com/C108qkX.png + :align: center + +Using MTProto is the only way to communicate with the actual Telegram servers, and the main API requires developers to +identify applications by means of a unique key; the bot token identifies a bot as a user and replaces the user's phone +number only. + +Can I use the same file_id across different accounts? +----------------------------------------------------- + +No, Telegram doesn't allow this. + +File ids are personal and bound to a specific user/bot -- and an attempt in using a foreign file id will result in +errors such as ``[400 MEDIA_EMPTY]``. + +The only exception are stickers' file ids; you can use them across different accounts without any problem, like this +one: ``CAADBAADyg4AAvLQYAEYD4F7vcZ43AI``. + +Can I use Bot API's file_ids in Pyrogram? +----------------------------------------- + +Definitely! All file ids you might have taken from the Bot API are 100% compatible and re-usable in Pyrogram... + +...at least for now. + +Telegram is slowly changing some server's internals and it's doing it in such a way that file ids are going to break +inevitably. Not only this, but it seems that the new, hypothetical, file ids could also possibly expire at anytime, thus +losing the *persistence* feature. + +This change will most likely affect the official `Bot API `_ too +(unless Telegram implements some workarounds server-side to keep backwards compatibility, which Pyrogram could in turn +make use of) and we can expect a proper notice from Telegram. + +Can I use multiple clients at once on the same account? +------------------------------------------------------- + +Yes, you can. Both user and bot accounts are able to run multiple sessions in parallel (up to 10 per account). However, +you must pay attention and not use the *same* exact session in more than one client at the same time. In other words: + +- Avoid copying your session file: even if you rename the file, the copied sessions will still point to a specific one + stored in the server. + +- Make sure that only one instance of your script runs, using your session file. + +If you -- even accidentally -- fail to do so, all the previous session copies will immediately stop receiving updates +and eventually the server will start throwing the error ``[406 AUTH_KEY_DUPLICATED]``, inviting you to login again. + +Why is that so? Because the server has recognized two identical sessions are running in two different locations, and +concludes it could possibly be due to a cloned/stolen device. Having the session ended in such occasions will protect +the user's privacy. + +So, the only correct way to run multiple clients on the same account is authorizing your account (either user or bot) +from the beginning every time, and use one separate session for each parallel client you are going to use. + +I started a client and nothing happens! +--------------------------------------- + +If you are connecting from Russia, China or Iran `you need a proxy`_, because Telegram could be partially or +totally blocked in those countries. + +Another possible cause might be network issues, either yours or Telegram's. To confirm this, add the following code on +the top of your script and run it again. You should see some error mentioning a socket timeout or an unreachable network +in a bunch of seconds: + +.. code-block:: python + + import logging + logging.basicConfig(level=logging.INFO) + +Another way to confirm you aren't able to connect to Telegram is by pinging these IP addresses and see whether ping +fails or not: + +- DC1: ``149.154.175.50`` +- DC2: ``149.154.167.51`` +- DC3: ``149.154.175.100`` +- DC4: ``149.154.167.91`` +- DC5: ``91.108.56.149`` + +.. _you need a proxy: topics/proxy + +I keep getting PEER_ID_INVALID error! +------------------------------------------- + +The error in question is ``[400 PEER_ID_INVALID]``, and could mean several +things: + +- The chat id you tried to use is simply wrong, double check it. +- The chat id refers to a group or channel you are not a member of. +- The chat id refers to a user you have't seen yet (from contacts, groups in common, forwarded messages or private + chats). +- The chat id argument you passed is in form of a string; you have to convert it into an integer with ``int(chat_id)``. + +My account has been deactivated/limited! +---------------------------------------- + +First of all, you should understand that Telegram wants to be a safe place for people to stay in, and to pursue this +goal there are automatic protection systems running to prevent flood and spam, as well as a moderation team of humans +who review reports. + +.. centered:: Pyrogram is a tool at your commands; it only does what you tell it to do, the rest is up to you. + +Having said that, here's a list of what Telegram definitely doesn't like: + +- Flood, abusing the API. +- Spam, sending unsolicited messages or adding people to unwanted groups and channels. +- Virtual/VoIP and cheap real numbers, because they are relatively easy to get and likely used for spam/flood. + +However, you might be right, and your account was deactivated/limited without any reason. This could happen because of +mistakes by either the automatic systems or a moderator. In such cases you can kindly email Telegram at +recover@telegram.org, contact `@smstelegram`_ on Twitter or use `this form`_. + +.. _@smstelegram: https://twitter.com/smstelegram +.. _this form: https://telegram.org/support + +About the License +----------------- + +.. image:: https://www.gnu.org/graphics/lgplv3-with-text-154x68.png + :align: left + +Pyrogram is free software and is currently licensed under the terms of the +`GNU Lesser General Public License v3 or later (LGPLv3+)`_. In short: you may use, redistribute and/or modify it +provided that modifications are described and licensed for free under LGPLv3+. + +In other words: you can use and integrate Pyrogram into your own code --- either open source, under the same or +different license, or even proprietary --- without being required to release the source code of your own applications. +However, any modifications to the library itself are required to be published for free under the same LGPLv3+ license. + +.. _GNU Lesser General Public License v3 or later (LGPLv3+): https://github.com/pyrogram/pyrogram/blob/develop/COPYING.lesser +.. _Bug Report: https://github.com/pyrogram/pyrogram/issues/new?labels=bug&template=bug_report.md +.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst new file mode 100644 index 00000000..5f00cbfd --- /dev/null +++ b/docs/source/glossary.rst @@ -0,0 +1,75 @@ +Pyrogram Glossary +================= + +This page contains a list of common words with brief explanations related to Pyrogram and, to some extent, Telegram in +general. Some words may as well link to dedicated articles in case the topic is covered in a more detailed fashion. + +.. tip:: + + If you think something interesting could be added here, feel free to propose it by opening a `Feature Request`_. + + +.. glossary:: + + API + Application Programming Interface: a set of methods, protocols and tools that make it easier to develop programs + by providing useful building blocks to the developer. + + API key + A secret code used to authenticate and/or authorize a specific application to Telegram in order for it to + control how the API is being used, for example, to prevent abuses of the API. + `More on API keys `_. + + DC + Also known as *data center*, is a place where lots of computer systems are housed and used together in order to + achieve high quality and availability for services. + + RPC + Acronym for Remote Procedure call, that is, a function which gets executed at some remote place (i.e. Telegram + server) and not in your local machine. + + RPCError + An error caused by an RPC which must be returned in place of the successful result in order to let the caller + know something went wrong. `More on RPCError `_. + + MTProto + The name of the custom-made, open and encrypted protocol by Telegram, implemented in Pyrogram. + `More on MTProto `_. + + MTProto API + The Telegram main API Pyrogram makes use of, which is able to connect both users and normal bots to Telegram + using MTProto as application layer protocol and execute any method Telegram provides from its public TL-schema. + `More on MTProto API `_. + + Bot API + The Telegram Bot API that is able to only connect normal bots only to Telegram using HTTP as application layer + protocol and allows to execute a sub-set of the main Telegram API. + `More on Bot API `_. + + Pyrogrammer + A developer that uses Pyrogram to build Telegram applications. + + Userbot + Also known as *user bot* or *ubot* for short, is a user logged in by third-party Telegram libraries --- such as + Pyrogram --- to automate some behaviours, like sending messages or reacting to text commands or any other event. + + Session + Also known as *login session*, is a strictly personal piece of information created and held by both parties + (client and server) which is used to grant permission into a single account without having to start a new + authorization process from scratch. + + Callback + Also known as *callback function*, is a user-defined generic function that *can be* registered to and then + called-back by the framework when specific events occurs. + + Handler + An object that wraps around a callback function that is *actually meant* to be registered into the framework, + which will then be able to handle a specific kind of events, such as a new incoming message, for example. + `More on Handlers `_. + + Decorator + Also known as *function decorator*, in Python, is a callable object that is used to modify another function. + Decorators in Pyrogram are used to automatically register callback functions for handling updates. + `More on Decorators `_. + +.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md diff --git a/docs/source/index.rst b/docs/source/index.rst index bd62547e..de91015f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,8 +4,8 @@ Welcome to Pyrogram .. raw:: html @@ -13,26 +13,17 @@ Welcome to Pyrogram Telegram MTProto API Framework for Python
- - Documentation + + Source Code - Changelog + Releases • - + Community -
- - Schema Layer - - - TgCrypto Version -

.. code-block:: python @@ -49,73 +40,133 @@ Welcome to Pyrogram app.run() -Welcome to Pyrogram's Documentation! Here you can find resources for learning how to use the framework. -Contents are organized into self-contained topics and can be accessed from the sidebar, or by following them in order -using the Next button at the end of each page. But first, here's a brief overview of what is this all about. +**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and +C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the +`MTProto API`_. -About ------ +.. _Telegram: https://telegram.org +.. _MTProto API: topics/mtproto-vs-botapi#what-is-the-mtproto-api -**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and C. -It enables you to easily create custom apps using both user and bot identities (bot API alternative) via the `MTProto API`_. +How the Documentation is Organized +---------------------------------- -Features --------- +Contents are organized into self-contained topics and can be all accessed from the sidebar, or by following them in +order using the Next button at the end of each page. Here below you can, instead, find a list of the most relevant +pages for a quick access. -- **Easy**: You can install Pyrogram with pip and start building your applications right away. -- **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way. -- **Fast**: Crypto parts are boosted up by TgCrypto_, a high-performance library written in pure C. -- **Documented**: Pyrogram API methods, types and public interfaces are well documented. -- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. -- **Updated**, to the latest Telegram API version, currently Layer 97 on top of `MTProto 2.0`_. -- **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code. -- **Comprehensive**: Execute any advanced action an official client is able to do, and even more. +First Steps +----------- -To get started, press the Next button. +.. hlist:: + :columns: 2 + + - `Quick Start`_: Overview to get you started quickly. + - `Calling Methods`_: How to call Pyrogram's methods. + - `Handling Updates`_: How to handle Telegram updates. + - `Error Handling`_: How to handle API errors correctly. + +.. _Quick Start: intro/quickstart +.. _Calling Methods: start/invoking +.. _Handling Updates: start/updates +.. _Error Handling: start/errors + +API Reference +------------- + +.. hlist:: + :columns: 2 + + - `Pyrogram Client`_: Reference details about the Client class. + - `Available Methods`_: List of available high-level methods. + - `Available Types`_: List of available high-level types. + - `Bound Methods`_: List of convenient bound methods. + +.. _Pyrogram Client: ./api/client +.. _Available Methods: api/methods +.. _Available Types: api/types +.. _Bound Methods: api/bound-methods + +Meta +---- + +.. hlist:: + :columns: 2 + + - `Pyrogram FAQ`_: Answers to common Pyrogram questions. + - `Pyrogram Glossary`_: List of words with brief explanations. + - `Release Notes`_: Release notes for Pyrogram releases. + - `Powered by Pyrogram`_: Collection of Pyrogram Projects. + - `Support Pyrogram`_: Ways to show your appreciation. + +.. _Pyrogram FAQ: faq +.. _Pyrogram Glossary: glossary +.. _Release Notes: releases +.. _Powered by Pyrogram: powered-by +.. _Support Pyrogram: support-pyrogram .. toctree:: :hidden: - :caption: Quick Start + :caption: Introduction - start/Installation - start/Setup - start/Usage + intro/quickstart + intro/install + intro/setup .. toctree:: :hidden: - :caption: Resources + :caption: Getting Started - resources/UpdateHandling - resources/UsingFilters - resources/MoreOnUpdates - resources/ConfigurationFile - resources/SmartPlugins - resources/AutoAuthorization - resources/CustomizeSessions - resources/TgCrypto - resources/TextFormatting - resources/SOCKS5Proxy - resources/BotsInteraction - resources/ErrorHandling - resources/TestServers - resources/AdvancedUsage - resources/VoiceCalls - resources/Changelog + start/auth + start/invoking + start/updates + start/errors .. toctree:: :hidden: - :caption: Main Package + :caption: API Reference - pyrogram/index + api/client + api/methods + api/types + api/bound-methods + api/handlers + api/decorators + api/filters + api/errors + +.. toctree:: + :hidden: + :caption: Topic Guides + + topics/filters + topics/more-on-updates + topics/config-file + topics/smart-plugins + topics/auto-auth + topics/session-settings + topics/tgcrypto + topics/text-formatting + topics/serialize + topics/proxy + topics/bots-interaction + topics/mtproto-vs-botapi + topics/test-servers + topics/advanced-usage + topics/voice-calls + +.. toctree:: + :hidden: + :caption: Meta + + faq + glossary + releases + powered-by + support-pyrogram .. toctree:: :hidden: :caption: Telegram API - functions/index - types/index - -.. _`Telegram`: https://telegram.org -.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto -.. _`MTProto API`: https://core.telegram.org/api#telegram-api -.. _`MTProto 2.0`: https://core.telegram.org/mtproto + telegram/functions/index + telegram/types/index \ No newline at end of file diff --git a/docs/source/start/Installation.rst b/docs/source/intro/install.rst similarity index 72% rename from docs/source/start/Installation.rst rename to docs/source/intro/install.rst index 079e1b1f..fe804e79 100644 --- a/docs/source/start/Installation.rst +++ b/docs/source/intro/install.rst @@ -1,8 +1,8 @@ -Installation -============ +Install Guide +============= Being a Python library, **Pyrogram** requires Python to be installed in your system. -We recommend using the latest version of Python 3 and pip. +We recommend using the latest versions of both Python 3 and pip. - Get **Python 3** from https://www.python.org/downloads/ (or with your package manager) - Get **pip** by following the instructions at https://pip.pypa.io/en/latest/installing/. @@ -29,12 +29,12 @@ Install Pyrogram Bleeding Edge ------------- -Things are constantly evolving in Pyrogram, although new releases are published only when enough changes are added, -but this doesn't mean you can't try new features right now! +Pyrogram is always evolving, although new releases on PyPI are published only when enough changes are added, but this +doesn't mean you can't try new features right now! -In case you would like to try out the latest Pyrogram features and additions, the `GitHub repo`_ is always kept updated -with new changes; you can install the development version straight from the ``develop`` branch using this command -(note "develop.zip" in the link): +In case you'd like to try out the latest Pyrogram features, the `GitHub repo`_ is always kept updated with new changes; +you can install the development version straight from the ``develop`` branch using this command (note "develop.zip" in +the link): .. code-block:: text @@ -44,7 +44,8 @@ Asynchronous ------------ Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging framework after all), and here's -where asyncio shines the most by providing extra performance while running on a single OS-level thread only. +where asyncio shines the most by providing extra performance and efficiency while running on a single OS-level thread +only. **A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5.3+ required). Use this command to install (note "asyncio.zip" in the link): @@ -54,7 +55,7 @@ Use this command to install (note "asyncio.zip" in the link): $ pip3 install -U https://github.com/pyrogram/pyrogram/archive/asyncio.zip -Pyrogram API remains the same and features are kept up to date from the non-async, default develop branch, but you +Pyrogram's API remains the same and features are kept up to date from the non-async, default develop branch, but you are obviously required Python asyncio knowledge in order to take full advantage of it. @@ -82,11 +83,11 @@ Verifying To verify that Pyrogram is correctly installed, open a Python shell and import it. If no error shows up you are good to go. -.. code-block:: python +.. parsed-literal:: >>> import pyrogram >>> pyrogram.__version__ - '0.12.0' + '|version|' -.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto +.. _TgCrypto: ../topics/tgcrypto .. _`Github repo`: http://github.com/pyrogram/pyrogram diff --git a/docs/source/intro/quickstart.rst b/docs/source/intro/quickstart.rst new file mode 100644 index 00000000..1aa7989e --- /dev/null +++ b/docs/source/intro/quickstart.rst @@ -0,0 +1,49 @@ +Quick Start +=========== + +The next few steps serve as a quick start for all new Pyrogrammers that want to get something done as fast as possible. +Let's go! + +Get Pyrogram Real Fast +---------------------- + +1. Install Pyrogram with ``pip3 install -U pyrogram``. + +2. Get your own Telegram API key from https://my.telegram.org/apps. + +3. Open your best text editor and paste the following: + + .. code-block:: python + + from pyrogram import Client + + api_id = 12345 + api_hash = "0123456789abcdef0123456789abcdef" + + with Client("my_account", api_id, api_hash) as app: + app.send_message("me", "Greetings from **Pyrogram**!") + +4. Replace *api_id* and *api_hash* values with your own. + +5. Save the file as ``pyro.py``. + +6. Run the script with ``python3 pyro.py`` + +7. Follow the instructions on your terminal to login. + +8. Watch Pyrogram send a message to yourself. + +9. Join our `community`_. + +10. Say, "hi!". + +Enjoy the API +------------- + +That was just a quick overview that barely scratched the surface! +In the next few pages of the introduction, we'll take a much more in-depth look of what we have just done above. + +Feeling eager to continue? You can take a shortcut to `Calling Methods`_ and come back later to learn some more details. + +.. _community: //t.me/Pyrogram +.. _Calling Methods: ../start/invoking \ No newline at end of file diff --git a/docs/source/intro/setup.rst b/docs/source/intro/setup.rst new file mode 100644 index 00000000..9c0cc6d4 --- /dev/null +++ b/docs/source/intro/setup.rst @@ -0,0 +1,61 @@ +Project Setup +============= + +We have just `installed Pyrogram`_. In this page we'll discuss what you need to do in order to set up a project with +the library. Let's see how it's done. + +API Keys +-------- + +The very first step requires you to obtain a valid Telegram API key (API id/hash pair): + +#. Visit https://my.telegram.org/apps and log in with your Telegram Account. +#. Fill out the form to register a new Telegram application. +#. Done! The API key consists of two parts: **api_id** and **api_hash**. + +.. important:: + + The API key is personal and must be kept secret. + +.. note:: + + The API key is unique for each user, but defines a token for a Telegram *application* you are going to build. This + means that you are able to authorize multiple users (and bots too) to access the Telegram database through the + MTProto API by a single API key. + +Configuration +------------- + +Having the API key from the `previous step <#api-keys>`_ in handy, we can now begin to configure a Pyrogram project. +There are two ways to do so, and you can choose what fits better for you: + +- First option (recommended): create a new ``config.ini`` file at the root of your working directory, copy-paste the + following and replace the **api_id** and **api_hash** values with your own. This is the preferred method because + allows you to keep your credentials out of your code without having to deal with how to load them: + + .. code-block:: ini + + [pyrogram] + api_id = 12345 + api_hash = 0123456789abcdef0123456789abcdef + +- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* parameters of the + Client class. This way you can have full control on how to store and load your credentials (e.g., you can load the + credentials from the environment variables and directly pass the values into Pyrogram): + + .. code-block:: python + + from pyrogram import Client + + app = Client( + "my_account", + api_id=12345, + api_hash="0123456789abcdef0123456789abcdef" + ) + +.. note:: + + To keep code snippets clean and concise, from now on it is assumed you are making use of the ``config.ini`` file, + thus, the *api_id* and *api_hash* parameters usage won't be shown anymore. + +.. _installed Pyrogram: install.html diff --git a/docs/source/powered-by.rst b/docs/source/powered-by.rst new file mode 100644 index 00000000..03e6decd --- /dev/null +++ b/docs/source/powered-by.rst @@ -0,0 +1,69 @@ +Powered by Pyrogram +=================== + +This is a collection of remarkable projects made with Pyrogram. + +.. A collection of Pyrojects :^) + +.. tip:: + + If you'd like to propose a project that's worth being listed here, feel free to open a `Feature Request`_. + +Projects Showcase +----------------- + +`YTAudioBot `_ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| **A YouTube audio downloader on Telegram, serving over 200k MAU.** +| --- by `Dan `_ + +- Main: https://t.me/ytaudiobot +- Mirror: https://t.me/ytaudio_bot +- Website: https://ytaudiobot.ml + +----- + +`Pyrogram Assistant `_ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| **The assistant bot that helps people with Pyrogram directly on Telegram** +| --- by `Dan `_ + +- Bot: https://t.me/pyrogrambot +- Source Code: https://github.com/pyrogram/assistant + +----- + +`PyroBot `_ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| **A Telegram userbot based on Pyrogram** +| --- by `Colin `_ + +- Source Code: https://git.colinshark.de/PyroBot/PyroBot + +----- + +`TgIntegration `_ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| **Integration Test Library for Telegram Messenger Bots in Python** +| --- by `JosXa `_ + +- Source Code: https://github.com/JosXa/tgintegration + +----- + +`BotListBot `_ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| **A bot which partly uses Pyrogram to check if other bots are still alive** +| --- by `JosXa `_ + +- Source Code: https://github.com/JosXa/BotListBot + +----- + +.. _Feature Request: https://github.com/pyrogram/pyrogram/issues/new?labels=enhancement&template=feature_request.md + diff --git a/docs/source/pyrogram/ChatAction.rst b/docs/source/pyrogram/ChatAction.rst deleted file mode 100644 index dfa56945..00000000 --- a/docs/source/pyrogram/ChatAction.rst +++ /dev/null @@ -1,5 +0,0 @@ -ChatAction -========== - -.. autoclass:: pyrogram.ChatAction - :members: diff --git a/docs/source/pyrogram/Client.rst b/docs/source/pyrogram/Client.rst deleted file mode 100644 index 5adf4956..00000000 --- a/docs/source/pyrogram/Client.rst +++ /dev/null @@ -1,162 +0,0 @@ -Client -====== - -.. currentmodule:: pyrogram.Client - -.. autoclass:: pyrogram.Client - -Utilities ---------- - -.. autosummary:: - :nosignatures: - - start - stop - restart - idle - run - add_handler - remove_handler - send - resolve_peer - save_file - stop_transmission - -Decorators ----------- - -.. autosummary:: - :nosignatures: - - on_message - on_callback_query - on_inline_query - on_deleted_messages - on_user_status - on_disconnect - on_raw_update - -Messages --------- - -.. autosummary:: - :nosignatures: - - send_message - forward_messages - send_photo - send_audio - send_document - send_sticker - send_video - send_animation - send_voice - send_video_note - send_media_group - send_location - send_venue - send_contact - send_cached_media - send_chat_action - edit_message_text - edit_message_caption - edit_message_reply_markup - edit_message_media - delete_messages - get_messages - get_history - get_history_count - iter_history - send_poll - vote_poll - stop_poll - retract_vote - download_media - -Chats ------ - -.. autosummary:: - :nosignatures: - - join_chat - leave_chat - kick_chat_member - unban_chat_member - restrict_chat_member - promote_chat_member - export_chat_invite_link - set_chat_photo - delete_chat_photo - set_chat_title - set_chat_description - pin_chat_message - unpin_chat_message - get_chat - get_chat_preview - get_chat_member - get_chat_members - get_chat_members_count - iter_chat_members - get_dialogs - iter_dialogs - get_dialogs_count - restrict_chat - update_chat_username - -Users ------ - -.. autosummary:: - :nosignatures: - - get_me - get_users - get_user_profile_photos - get_user_profile_photos_count - set_user_profile_photo - delete_user_profile_photos - update_username - -Contacts --------- - -.. autosummary:: - :nosignatures: - - add_contacts - get_contacts - get_contacts_count - delete_contacts - -Password --------- - -.. autosummary:: - :nosignatures: - - enable_cloud_password - change_cloud_password - remove_cloud_password - -Bots ----- - -.. autosummary:: - :nosignatures: - - get_inline_bot_results - send_inline_bot_result - answer_callback_query - answer_inline_query - request_callback_answer - send_game - set_game_score - get_game_high_scores - answer_inline_query - - -.. autoclass:: pyrogram.Client - :inherited-members: - :members: diff --git a/docs/source/pyrogram/Handlers.rst b/docs/source/pyrogram/Handlers.rst deleted file mode 100644 index 1bb16ece..00000000 --- a/docs/source/pyrogram/Handlers.rst +++ /dev/null @@ -1,37 +0,0 @@ -Handlers -======== - -.. currentmodule:: pyrogram - -.. autosummary:: - :nosignatures: - - MessageHandler - DeletedMessagesHandler - CallbackQueryHandler - InlineQueryHandler - UserStatusHandler - DisconnectHandler - RawUpdateHandler - -.. autoclass:: MessageHandler - :members: - -.. autoclass:: DeletedMessagesHandler - :members: - -.. autoclass:: CallbackQueryHandler - :members: - -.. autoclass:: InlineQueryHandler - :members: - -.. autoclass:: UserStatusHandler - :members: - -.. autoclass:: DisconnectHandler - :members: - -.. autoclass:: RawUpdateHandler - :members: - diff --git a/docs/source/pyrogram/ParseMode.rst b/docs/source/pyrogram/ParseMode.rst deleted file mode 100644 index 6a4e0bbb..00000000 --- a/docs/source/pyrogram/ParseMode.rst +++ /dev/null @@ -1,6 +0,0 @@ -ParseMode -========= - -.. autoclass:: pyrogram.ParseMode - :members: - :undoc-members: diff --git a/docs/source/pyrogram/RPCError.rst b/docs/source/pyrogram/RPCError.rst deleted file mode 100644 index a47c9b9c..00000000 --- a/docs/source/pyrogram/RPCError.rst +++ /dev/null @@ -1,15 +0,0 @@ -RPCError -======== - -.. autoexception:: pyrogram.RPCError - :members: - -.. toctree:: - ../errors/SeeOther - ../errors/BadRequest - ../errors/Unauthorized - ../errors/Forbidden - ../errors/NotAcceptable - ../errors/Flood - ../errors/InternalServerError - ../errors/UnknownError diff --git a/docs/source/pyrogram/Types.rst b/docs/source/pyrogram/Types.rst deleted file mode 100644 index 5deb58b2..00000000 --- a/docs/source/pyrogram/Types.rst +++ /dev/null @@ -1,263 +0,0 @@ -Types -===== - -.. currentmodule:: pyrogram - -Users & Chats -------------- - -.. autosummary:: - :nosignatures: - - User - UserStatus - Chat - ChatPreview - ChatPhoto - ChatMember - ChatMembers - ChatPermissions - Dialog - Dialogs - -Messages & Media ----------------- - -.. autosummary:: - :nosignatures: - - Message - Messages - MessageEntity - Photo - PhotoSize - UserProfilePhotos - Audio - Document - Animation - Video - Voice - VideoNote - Contact - Location - Venue - Sticker - Poll - PollOption - -Bots ----- - -.. autosummary:: - :nosignatures: - - ReplyKeyboardMarkup - KeyboardButton - ReplyKeyboardRemove - InlineKeyboardMarkup - InlineKeyboardButton - ForceReply - CallbackQuery - Game - -Input Media ------------ - -.. autosummary:: - :nosignatures: - - InputMedia - InputMediaPhoto - InputMediaVideo - InputMediaAudio - InputMediaAnimation - InputMediaDocument - InputPhoneContact - -Inline Mode ------------- - -.. autosummary:: - :nosignatures: - - InlineQuery - InlineQueryResult - InlineQueryResultArticle - -InputMessageContent -------------------- - -.. autosummary:: - :nosignatures: - - InputMessageContent - InputTextMessageContent - -.. User & Chats - ------------ - -.. autoclass:: User - :members: - -.. autoclass:: UserStatus - :members: - -.. autoclass:: Chat - :members: - -.. autoclass:: ChatPreview - :members: - -.. autoclass:: ChatPhoto - :members: - -.. autoclass:: ChatMember - :members: - -.. autoclass:: ChatMembers - :members: - -.. autoclass:: ChatPermissions - :members: - -.. autoclass:: Dialog - :members: - -.. autoclass:: Dialogs - :members: - -.. Messages & Media - ---------------- - -.. autoclass:: Message - :members: - -.. autoclass:: Messages - :members: - -.. autoclass:: MessageEntity - :members: - -.. autoclass:: Photo - :members: - -.. autoclass:: PhotoSize - :members: - -.. autoclass:: UserProfilePhotos - :members: - -.. autoclass:: Audio - :members: - -.. autoclass:: Document - :members: - -.. autoclass:: Animation - :members: - -.. autoclass:: Video - :members: - -.. autoclass:: Voice - :members: - -.. autoclass:: VideoNote - :members: - -.. autoclass:: Contact - :members: - -.. autoclass:: Location - :members: - -.. autoclass:: Venue - :members: - -.. autoclass:: Sticker - :members: - -.. autoclass:: Poll - :members: - -.. autoclass:: PollOption - :members: - -.. Bots - ---- - -.. autoclass:: ReplyKeyboardMarkup - :members: - -.. autoclass:: KeyboardButton - :members: - -.. autoclass:: ReplyKeyboardRemove - :members: - -.. autoclass:: InlineKeyboardMarkup - :members: - -.. autoclass:: InlineKeyboardButton - :members: - -.. autoclass:: ForceReply - :members: - -.. autoclass:: CallbackQuery - :members: - -.. autoclass:: Game - :members: - -.. autoclass:: GameHighScore - :members: - -.. autoclass:: GameHighScores - :members: - -.. Input Media - ----------- - -.. autoclass:: InputMedia - :members: - -.. autoclass:: InputMediaPhoto - :members: - -.. autoclass:: InputMediaVideo - :members: - -.. autoclass:: InputMediaAudio - :members: - -.. autoclass:: InputMediaAnimation - :members: - -.. autoclass:: InputMediaDocument - :members: - -.. autoclass:: InputPhoneContact - :members: - - -.. Inline Mode - ----------- - -.. autoclass:: InlineQuery - :members: - -.. autoclass:: InlineQueryResult - :members: - -.. autoclass:: InlineQueryResultArticle - :members: - -.. InputMessageContent - ------------------- - -.. autoclass:: InputMessageContent - :members: - -.. autoclass:: InputTextMessageContent - :members: diff --git a/docs/source/pyrogram/index.rst b/docs/source/pyrogram/index.rst deleted file mode 100644 index 286b5db1..00000000 --- a/docs/source/pyrogram/index.rst +++ /dev/null @@ -1,20 +0,0 @@ -Pyrogram -======== - -In this section you can find a detailed description of the Pyrogram package and its API. - -:class:`Client ` is the main class. It exposes easy-to-use methods that are named -after the well established `Telegram Bot API`_ methods, thus offering a familiar look to Bot developers. - -.. toctree:: - :maxdepth: 1 - - Client - Types - Handlers - Filters - ChatAction - ParseMode - RPCError - -.. _Telegram Bot API: https://core.telegram.org/bots/api#available-methods diff --git a/docs/source/releases.rst b/docs/source/releases.rst new file mode 100644 index 00000000..6c3b5b75 --- /dev/null +++ b/docs/source/releases.rst @@ -0,0 +1,13 @@ +Release Notes +============= + +Release notes for Pyrogram releases will describe what's new in each version, and will also make you aware of any +backwards-incompatible changes made in that version. + +When upgrading to a new version of Pyrogram, you will need to check all the breaking changes in order to find +incompatible code in your application, but also to take advantage of new features and improvements. + +.. note:: + + Currently, all Pyrogram release notes live inside the GitHub repository web page: + https://github.com/pyrogram/pyrogram/releases. diff --git a/docs/source/resources/Changelog.rst b/docs/source/resources/Changelog.rst deleted file mode 100644 index 732a1311..00000000 --- a/docs/source/resources/Changelog.rst +++ /dev/null @@ -1,11 +0,0 @@ -Changelog -========= - -Currently, all Pyrogram release notes live inside the GitHub repository web page: -https://github.com/pyrogram/pyrogram/releases - -(You will be automatically redirected in 10 seconds.) - -.. raw:: html - - \ No newline at end of file diff --git a/docs/source/resources/ErrorHandling.rst b/docs/source/resources/ErrorHandling.rst deleted file mode 100644 index 7e87b94a..00000000 --- a/docs/source/resources/ErrorHandling.rst +++ /dev/null @@ -1,59 +0,0 @@ -Error Handling -============== - -Errors are inevitable when working with the API, and they must be correctly handled with ``try..except`` blocks. - -There are many errors that Telegram could return, but they all fall in one of these categories -(which are in turn children of the :obj:`RPCError ` superclass): - -- :obj:`303 - See Other ` -- :obj:`400 - Bad Request ` -- :obj:`401 - Unauthorized ` -- :obj:`403 - Forbidden ` -- :obj:`406 - Not Acceptable ` -- :obj:`420 - Flood ` -- :obj:`500 - Internal Server Error ` - -As stated above, there are really many (too many) errors, and in case Pyrogram does not know anything yet about a -specific one, it raises a special :obj:`520 Unknown Error ` exception and logs it -in the ``unknown_errors.txt`` file. Users are invited to report these unknown errors; in later versions of Pyrogram -some kind of automatic error reporting module might be implemented. - -Examples --------- - -.. code-block:: python - - from pyrogram.errors import ( - BadRequest, Flood, InternalServerError, - SeeOther, Unauthorized, UnknownError - ) - - try: - ... - except BadRequest: - pass - except Flood: - pass - except InternalServerError: - pass - except SeeOther: - pass - except Unauthorized: - pass - except UnknownError: - pass - -Exception objects may also contain some informative values. -E.g.: :obj:`FloodWait ` holds the amount of seconds you have to wait -before you can try again. The value is always stored in the ``x`` field of the returned exception object: - -.. code-block:: python - - import time - from pyrogram.errors import FloodWait - - try: - ... - except FloodWait as e: - time.sleep(e.x) diff --git a/docs/source/resources/UpdateHandling.rst b/docs/source/resources/UpdateHandling.rst deleted file mode 100644 index ed0ad909..00000000 --- a/docs/source/resources/UpdateHandling.rst +++ /dev/null @@ -1,72 +0,0 @@ -Update Handling -=============== - -Let's now dive right into the core of the framework. - -Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...) -and are handled by registering one or more callback functions in your app using `Handlers <../pyrogram/Handlers.html>`_. - -Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback -function will be called. - -Registering an Handler ----------------------- - -To explain how handlers work let's have a look at the most used one, the -:obj:`MessageHandler `, which will be in charge for handling :obj:`Message ` -updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles -settings them up once you learn from this section. - -Using add_handler() -------------------- - -The :meth:`add_handler() ` method takes any handler instance that wraps around your defined -callback function and registers it in your Client. Here's a full example that prints out the content of a message as -soon as it arrives: - -.. code-block:: python - - from pyrogram import Client, MessageHandler - - - def my_function(client, message): - print(message) - - - app = Client("my_account") - - my_handler = MessageHandler(my_function) - app.add_handler(my_handler) - - app.run() - -Using Decorators ----------------- - -A much nicer way to register a MessageHandler is by decorating your callback function with the -:meth:`on_message() ` decorator, which will still make use of add_handler() under the hood. - -.. code-block:: python - - from pyrogram import Client - - app = Client("my_account") - - - @app.on_message() - def my_handler(client, message): - print(message) - - - app.run() - - -.. note:: - - Due to how these decorators work in Pyrogram, they will wrap your defined callback function in a tuple consisting of - ``(handler, group)``; this will be the value held by your function identifier (e.g.: *my_function* from the example - above). - - In case, for some reason, you want to get your own function back after it has been decorated, you need to access - ``my_function[0].callback``, that is, the *callback* field of the *handler* object which is the first element in the - tuple. \ No newline at end of file diff --git a/docs/source/start/Setup.rst b/docs/source/start/Setup.rst deleted file mode 100644 index 45a40d16..00000000 --- a/docs/source/start/Setup.rst +++ /dev/null @@ -1,120 +0,0 @@ -Setup -===== - -Once you successfully `installed Pyrogram`_, you will still have to follow a few steps before you can actually use -the library to make API calls. This section provides all the information you need in order to set up a project -with Pyrogram. - -API Keys --------- - -The very first step requires you to obtain a valid Telegram API key (API id/hash pair). -If you already have one you can skip this step, otherwise: - -#. Visit https://my.telegram.org/apps and log in with your Telegram Account. -#. Fill out the form to register a new Telegram application. -#. Done. The API key consists of two parts: **App api_id** and **App api_hash**. - -.. important:: - - This API key is personal and must be kept secret. - -Configuration -------------- - -The API key obtained in the `previous step <#api-keys>`_ defines a token for your application allowing you to access -the Telegram database using the MTProto API — **it is therefore required for all authorizations of both users and bots**. - -Having it handy, it's time to configure your Pyrogram project. There are two ways to do so, and you can choose what -fits better for you: - -- Create a new ``config.ini`` file at the root of your working directory, copy-paste the following and replace the - **api_id** and **api_hash** values with your own. This is the preferred method because allows you to keep your - credentials out of your code without having to deal with how to load them: - - .. code-block:: ini - - [pyrogram] - api_id = 12345 - api_hash = 0123456789abcdef0123456789abcdef - -- Alternatively, you can pass your API key to Pyrogram by simply using the *api_id* and *api_hash* parameters of the - Client class. This way you can have full control on how to store and load your credentials: - - .. code-block:: python - - from pyrogram import Client - - app = Client( - "my_account", - api_id=12345, - api_hash="0123456789abcdef0123456789abcdef" - ) - -.. note:: - - From now on, the code snippets assume you are using the ``config.ini`` file, thus they won't show the *api_id* and - *api_hash* parameters usage to keep them as clean as possible. - -User Authorization ------------------- - -In order to use the API, Telegram requires that users be authorized via their phone numbers. -Pyrogram automatically manages this access, all you need to do is create an instance of the -:class:`Client ` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call -the :meth:`run() ` method: - -.. code-block:: python - - from pyrogram import Client - - app = Client("my_account") - app.run() - -This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_) -and the **phone code** you will receive: - -.. code-block:: text - - Enter phone number: +39********** - Is "+39**********" correct? (y/n): y - Enter phone code: 32768 - Logged in successfully as Dan - -After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing Pyrogram -executing API calls with your identity. This file will be loaded again when you restart your app, and as long as you -keep the session alive, Pyrogram won't ask you again to enter your phone number. - -.. important:: - - Your ``*.session`` files are personal and must be kept secret. - -.. note:: - - The code above does nothing except asking for credentials and keeping the client online, hit ``CTRL+C`` now to stop - your application and keep reading. - -Bot Authorization ------------------ - -Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by -BotFather_. Bot tokens replace the users' phone numbers only — you still need to -`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using bots. - -The authorization process is automatically managed. All you need to do is choose a ``session_name`` (can be anything, -usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named -after the session name, which will be ``pyrogrambot.session`` for the example below. - -.. code-block:: python - - from pyrogram import Client - - app = Client( - "pyrogrambot", - bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" - ) - app.run() - -.. _installed Pyrogram: Installation.html -.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes -.. _BotFather: https://t.me/botfather \ No newline at end of file diff --git a/docs/source/start/Usage.rst b/docs/source/start/Usage.rst deleted file mode 100644 index 35ae79a0..00000000 --- a/docs/source/start/Usage.rst +++ /dev/null @@ -1,51 +0,0 @@ -Usage -===== - -Having your `project set up`_ and your account authorized_, it's time to start playing with the API. Let's start! - -High-level API --------------- - -The easiest and recommended way to interact with Telegram is via the high-level Pyrogram methods_ and types_, which are -named after the `Telegram Bot API`_. - -Here's a simple example: - -.. code-block:: python - - from pyrogram import Client - - app = Client("my_account") - - app.start() - - print(app.get_me()) - app.send_message("me", "Hi there! I'm using **Pyrogram**") - app.send_location("me", 51.500729, -0.124583) - app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") - - app.stop() - -You can also use Pyrogram in a context manager with the ``with`` statement. The Client will automatically -:meth:`start ` and :meth:`stop ` gracefully, even in case of unhandled -exceptions in your code: - -.. code-block:: python - - from pyrogram import Client - - app = Client("my_account") - - with app: - print(app.get_me()) - app.send_message("me", "Hi there! I'm using **Pyrogram**") - app.send_location("me", 51.500729, -0.124583) - app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") - -More examples on `GitHub `_. - -.. _project set up: Setup.html -.. _authorized: Setup.html#user-authorization -.. _Telegram Bot API: https://core.telegram.org/bots/api -.. _methods: ../pyrogram/Client.html#messages -.. _types: ../pyrogram/Types.html diff --git a/docs/source/start/auth.rst b/docs/source/start/auth.rst new file mode 100644 index 00000000..e00b08a0 --- /dev/null +++ b/docs/source/start/auth.rst @@ -0,0 +1,69 @@ +Authorization +============= + +Once a `project is set up`_, you will still have to follow a few steps before you can actually use Pyrogram to make +API calls. This section provides all the information you need in order to authorize yourself as user or bot. + +User Authorization +------------------ + +In order to use the API, Telegram requires that users be authorized via their phone numbers. +Pyrogram automatically manages this process, all you need to do is create an instance of the +:class:`Client ` class by passing to it a ``session_name`` of your choice (e.g.: "my_account") and call +the :meth:`run() ` method: + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + app.run() + +This starts an interactive shell asking you to input your **phone number** (including your `Country Code`_) and the +**phone code** you will receive in your devices that are already authorized or via SMS: + +.. code-block:: text + + Enter phone number: +39********** + Is "+39**********" correct? (y/n): y + Enter phone code: 32768 + Logged in successfully as Dan + +After successfully authorizing yourself, a new file called ``my_account.session`` will be created allowing Pyrogram to +execute API calls with your identity. This file will be loaded again when you restart your app, and as long as you +keep the session alive, Pyrogram won't ask you again to enter your phone number. + +.. important:: + + Your ``*.session`` files are personal and must be kept secret. + +.. note:: + + The code above does nothing except asking for credentials and keeping the client online, hit ``CTRL+C`` now to stop + your application and keep reading. + +Bot Authorization +----------------- + +Bots are a special kind of users that are authorized via their tokens (instead of phone numbers), which are created by +the `Bot Father`_. Bot tokens replace the users' phone numbers only — you still need to +`configure a Telegram API key <../intro/setup#configuration>`_ with Pyrogram, even when using bots. + +The authorization process is automatically managed. All you need to do is choose a ``session_name`` (can be anything, +usually your bot username) and pass your bot token using the ``bot_token`` parameter. The session file will be named +after the session name, which will be ``my_bot.session`` for the example below. + +.. code-block:: python + + from pyrogram import Client + + app = Client( + "my_bot", + bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" + ) + + app.run() + +.. _project is set up: ../intro/setup +.. _Country Code: https://en.wikipedia.org/wiki/List_of_country_calling_codes +.. _Bot Father: https://t.me/botfather \ No newline at end of file diff --git a/docs/source/start/errors.rst b/docs/source/start/errors.rst new file mode 100644 index 00000000..cf329947 --- /dev/null +++ b/docs/source/start/errors.rst @@ -0,0 +1,91 @@ +Error Handling +============== + +Errors are inevitable when working with the API, and they must be correctly handled with ``try..except`` blocks in order +to control the behaviour of your application. Pyrogram errors all live inside the ``errors`` package: + +.. code-block:: python + + from pyrogram import errors + +RPCError +-------- + +The father of all errors is named ``RPCError``. This error exists in form of a Python exception which is directly +subclass-ed from Python's main ``Exception`` and is able to catch all Telegram API related errors. This error is raised +every time a method call against Telegram's API was unsuccessful. + +.. code-block:: python + + from pyrogram.errors import RPCError + +.. warning:: + + It must be noted that catching this error is bad practice, especially when no feedback is given (i.e. by + logging/printing the full error traceback), because it makes it impossible to understand what went wrong. + +Error Categories +---------------- + +The ``RPCError`` packs together all the possible errors Telegram could raise, but to make things tidier, Pyrogram +provides categories of errors, which are named after the common HTTP errors and subclass-ed from the RPCError: + +.. code-block:: python + + from pyrogram.errors import BadRequest, Forbidden, ... + +- `303 - SeeOther <../api/errors#seeother>`_ +- `400 - BadRequest <../api/errors#badrequest>`_ +- `401 - Unauthorized <../api/errors#unauthorized>`_ +- `403 - Forbidden <../api/errors#forbidden>`_ +- `406 - NotAcceptable <../api/errors#notacceptable>`_ +- `420 - Flood <../api/errors#flood>`_ +- `500 - InternalServerError <../api/errors#internalservererror>`_ + +Single Errors +------------- + +For a fine-grained control over every single error, Pyrogram does also expose errors that deal each with a specific +issue. For example: + +.. code-block:: python + + from pyrogram.errors import FloodWait + +These errors subclass directly from the category of errors they belong to, which in turn subclass from the father +RPCError, thus building a class of error hierarchy such as this: + +- RPCError + - BadRequest + - ``MessageEmpty`` + - ``UsernameOccupied`` + - ``...`` + - InternalServerError + - ``RpcCallFail`` + - ``InterDcCallError`` + - ``...`` + - ``...`` + +.. _Errors: api/errors + +Unknown Errors +-------------- + +In case Pyrogram does not know anything yet about a specific error, it raises a special ``520 - UnknownError`` exception +and logs it in the ``unknown_errors.txt`` file. Users are invited to report these unknown errors. + +Errors with Values +------------------ + +Exception objects may also contain some informative values. For example, ``FloodWait`` holds the amount of seconds you +have to wait before you can try again. The value is always stored in the ``x`` field of the returned exception object: + +.. code-block:: python + + import time + from pyrogram.errors import FloodWait + + try: + ... + except FloodWait as e: + time.sleep(e.x) # Wait before trying again diff --git a/docs/source/start/invoking.rst b/docs/source/start/invoking.rst new file mode 100644 index 00000000..ef9bc373 --- /dev/null +++ b/docs/source/start/invoking.rst @@ -0,0 +1,84 @@ +Calling Methods +=============== + +At this point, we have successfully `installed Pyrogram`_ and authorized_ our account; we are now aiming towards the +core of the library. It's time to start playing with the API! + +Basic Usage +----------- + +Making API method calls with Pyrogram is very simple. Here's an example we are going to examine: + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + app.start() + + print(app.get_me()) + app.send_message("me", "Hi, it's me!") + app.send_location("me", 51.500729, -0.124583) + app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") + + app.stop() + +Let's begin by importing the Client class from the Pyrogram package: + +.. code-block:: python + + from pyrogram import Client + +Now instantiate a new Client object, "my_account" is a session name of your choice: + +.. code-block:: python + + app = Client("my_account") + +To actually make use of any method, the client has to be started first: + +.. code-block:: python + + app.start() + +Now, you can call any method you like: + +.. code-block:: python + + print(app.get_me()) # Print information about yourself + + # Send messages to yourself: + app.send_message("me", "Hi!") # Text message + app.send_location("me", 51.500729, -0.124583) # Location + app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") # Sticker + +Finally, when done, simply stop the client: + +.. code-block:: python + + app.stop() + +Context Manager +--------------- + +You can also use Pyrogram's Client in a context manager with the ``with`` statement. The client will automatically +:meth:`start() ` and :meth:`stop() ` gracefully, even in case of unhandled +exceptions in your code. The example above can be therefore rewritten in a much nicer way: + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + with app: + print(app.get_me()) + app.send_message("me", "Hi there! I'm using **Pyrogram**") + app.send_location("me", 51.500729, -0.124583) + app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") + +More examples can be found on `GitHub `_. + +.. _installed Pyrogram: ../intro/install.html +.. _authorized: ../intro/setup.html diff --git a/docs/source/start/updates.rst b/docs/source/start/updates.rst new file mode 100644 index 00000000..a0f2ca0c --- /dev/null +++ b/docs/source/start/updates.rst @@ -0,0 +1,112 @@ +Handling Updates +================ + +Calling `API methods`_ sequentially is cool, but how to react when, for example, a new message arrives? This page deals +with updates and how to handle such events in Pyrogram. Let's have a look at how they work. + +Defining Updates +---------------- + +First, let's define what are these updates. As hinted already, updates are simply events that happen in your Telegram +account (incoming messages, new members join, bot button presses, etc...), which are meant to notify you about a new +specific state that has changed. These updates are handled by registering one or more callback functions in your app +using `Handlers <../api/handlers>`_. + +Each handler deals with a specific event and once a matching update arrives from Telegram, your registered callback +function will be called back by the framework and its body executed. + +Registering a Handler +--------------------- + +To explain how handlers work let's have a look at the most used one, the +:obj:`MessageHandler `, which will be in charge for handling :obj:`Message ` +updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles +settings them up once you learn from this section. + +Using add_handler() +------------------- + +The :meth:`add_handler() ` method takes any handler instance that wraps around your defined +callback function and registers it in your Client. Here's a full example that prints out the content of a message as +soon as it arrives: + +.. code-block:: python + + from pyrogram import Client, MessageHandler + + + def my_function(client, message): + print(message) + + + app = Client("my_account") + + my_handler = MessageHandler(my_function) + app.add_handler(my_handler) + + app.run() + +Let's examine these four new pieces. First one: a callback function we defined which accepts two arguments - +*(client, message)*. This will be the function that gets executed every time a new message arrives and Pyrogram will +call that function by passing the client instance and the new message instance as argument. + +.. code-block:: python + + def my_function(client, message): + print(message) + +Second one: the :obj:`MessageHandler `. This object tells Pyrogram the function we defined +above must only handle updates that are in form of a :obj:`Message `: + +.. code-block:: python + + my_handler = MessageHandler(my_function) + +Third: the method :meth:`add_handler() `. This method is used to actually register the +handler and let Pyrogram know it needs to be taken into consideration when new updates arrive and the internal +dispatching phase begins. + +.. code-block:: python + + app.add_handler(my_handler) + +Last one, the :meth:`run() ` method. What this does is simply call +:meth:`start() ` and a special method :meth:`idle() ` that keeps your main +scripts alive until you press ``CTRL+C``; the client will be automatically stopped after that. + +.. code-block:: python + + app.run() + +Using Decorators +---------------- + +All of the above will become quite verbose, especially in case you have lots of handlers to register. A much nicer way +to do so is by decorating your callback function with the :meth:`on_message() ` decorator. + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + + @app.on_message() + def my_handler(client, message): + print(message) + + + app.run() + + +.. note:: + + Due to how these decorators work in Pyrogram, they will wrap your defined callback function in a tuple consisting of + ``(handler, group)``; this will be the value held by your function identifier (e.g.: *my_function* from the example + above). + + In case, for some reason, you want to get your own function back after it has been decorated, you need to access + ``my_function[0].callback``, that is, the *callback* field of the *handler* object which is the first element in the + tuple, accessed by bracket notation *[0]*. + +.. _API methods: invoking \ No newline at end of file diff --git a/docs/source/support-pyrogram.rst b/docs/source/support-pyrogram.rst new file mode 100644 index 00000000..c867b706 --- /dev/null +++ b/docs/source/support-pyrogram.rst @@ -0,0 +1,26 @@ +Support Pyrogram +================ + +Pyrogram is free and open source software, and thus supported by your love! If you like the project and have found it to +be useful, give Pyrogram a `Star on GitHub`_. Your appreciation means a lot and helps staying motivated. + +.. raw:: html + + Star +

+ +Donate +------ + +If you'd also like to donate in order to support Pyrogram -- or any of my `other works`_ -- you can use the PayPal +button below. Thank you. + +.. image:: https://i.imgur.com/fasFTzK.png + :target: https://paypal.me/delivrance + :width: 128 + +--- `Dan`_ + +.. _Star on GitHub: https://github.com/pyrogram/pyrogram +.. _other works: https://github.com/delivrance +.. _Dan: https://t.me/haskell diff --git a/docs/source/resources/AdvancedUsage.rst b/docs/source/topics/advanced-usage.rst similarity index 90% rename from docs/source/resources/AdvancedUsage.rst rename to docs/source/topics/advanced-usage.rst index 8b722b2a..4032783f 100644 --- a/docs/source/resources/AdvancedUsage.rst +++ b/docs/source/topics/advanced-usage.rst @@ -101,9 +101,9 @@ sending messages with IDs only thanks to cached access hashes. There are three different InputPeer types, one for each kind of Telegram entity. Whenever an InputPeer is needed you must pass one of these: - - `InputPeerUser `_ - Users - - `InputPeerChat `_ - Basic Chats - - `InputPeerChannel `_ - Either Channels or Supergroups + - :obj:`InputPeerUser <../telegram/types/InputPeerUser>` - Users + - :obj:`InputPeerChat <../telegram/types/InputPeerChat>` - Basic Chats + - :obj:`InputPeerChannel <../telegram/types/InputPeerChannel>` - Either Channels or Supergroups But you don't necessarily have to manually instantiate each object because, luckily for you, Pyrogram already provides :meth:`resolve_peer() ` as a convenience utility method that returns the correct InputPeer @@ -125,12 +125,9 @@ For example, given the ID *123456789*, here's how Pyrogram can tell entities apa So, every time you take a raw ID, make sure to translate it into the correct ID when you want to use it with an high-level method. - - - -.. _methods: ../pyrogram/Client.html#messages -.. _types: ../pyrogram/Types.html -.. _plenty of them: ../pyrogram/Client.html#messages -.. _raw functions: ../pyrogram/functions -.. _raw types: ../pyrogram/types -.. _Community: https://t.me/PyrogramChat \ No newline at end of file +.. _methods: ../api/methods +.. _types: ../api/types +.. _plenty of them: ../api/methods +.. _raw functions: ../telegram/functions +.. _raw types: ../telegram/types +.. _Community: https://t.me/Pyrogram \ No newline at end of file diff --git a/docs/source/resources/AutoAuthorization.rst b/docs/source/topics/auto-auth.rst similarity index 100% rename from docs/source/resources/AutoAuthorization.rst rename to docs/source/topics/auto-auth.rst diff --git a/docs/source/resources/BotsInteraction.rst b/docs/source/topics/bots-interaction.rst similarity index 100% rename from docs/source/resources/BotsInteraction.rst rename to docs/source/topics/bots-interaction.rst diff --git a/docs/source/resources/ConfigurationFile.rst b/docs/source/topics/config-file.rst similarity index 93% rename from docs/source/resources/ConfigurationFile.rst rename to docs/source/topics/config-file.rst index 2a50277f..14ae9fb6 100644 --- a/docs/source/resources/ConfigurationFile.rst +++ b/docs/source/topics/config-file.rst @@ -54,7 +54,7 @@ The ``[pyrogram]`` section contains your Telegram API credentials: *api_id* and api_id = 12345 api_hash = 0123456789abcdef0123456789abcdef -`More info about API Key. <../start/Setup.html#configuration>`_ +`More info about API Key. <../intro/setup#api-keys>`_ Proxy ^^^^^ @@ -70,7 +70,7 @@ The ``[proxy]`` section contains settings about your SOCKS5 proxy. username = password = -`More info about SOCKS5 Proxy. `_ +`More info about SOCKS5 Proxy. `_ Plugins ^^^^^^^ @@ -87,4 +87,4 @@ The ``[plugins]`` section contains settings about Smart Plugins. exclude = module fn2 -`More info about Smart Plugins. `_ +`More info about Smart Plugins. `_ diff --git a/docs/source/resources/UsingFilters.rst b/docs/source/topics/filters.rst similarity index 99% rename from docs/source/resources/UsingFilters.rst rename to docs/source/topics/filters.rst index ec3e2e10..cb2e2a4c 100644 --- a/docs/source/resources/UsingFilters.rst +++ b/docs/source/topics/filters.rst @@ -7,6 +7,9 @@ but there's much more than that to come. Here we'll discuss about :class:`Filters `. Filters enable a fine-grain control over what kind of updates are allowed or not to be passed in your callback functions, based on their inner details. +Single Filters +-------------- + Let's start right away with a simple example: - This example will show you how to **only** handle messages containing an :obj:`Audio ` object and diff --git a/docs/source/resources/MoreOnUpdates.rst b/docs/source/topics/more-on-updates.rst similarity index 94% rename from docs/source/resources/MoreOnUpdates.rst rename to docs/source/topics/more-on-updates.rst index f3658c6e..cb319ee1 100644 --- a/docs/source/resources/MoreOnUpdates.rst +++ b/docs/source/topics/more-on-updates.rst @@ -151,9 +151,9 @@ Continue Propagation As opposed to `stopping the update propagation <#stop-propagation>`_ and also as an alternative to the `handler groups <#handler-groups>`_, you can signal the internal dispatcher to continue the update propagation within -**the same group** regardless of the next handler's filters. This allows you to register multiple handlers with -overlapping filters in the same group; to let the dispatcher process the next handler you can do *one* of the following -in each handler you want to grant permission to continue: +**the same group** despite having conflicting filters in the next registered handler. This allows you to register +multiple handlers with overlapping filters in the same group; to let the dispatcher process the next handler you can do +*one* of the following in each handler you want to grant permission to continue: - Call the update's bound-method ``.continue_propagation()`` (preferred way). - Manually ``raise ContinuePropagation`` exception (more suitable for raw updates only). @@ -218,5 +218,5 @@ The output of both (equivalent) examples will be: 1 2 -.. _`update handlers`: UpdateHandling.html -.. _`filters`: UsingFilters.html \ No newline at end of file +.. _`update handlers`: ../start/updates +.. _`filters`: filters \ No newline at end of file diff --git a/docs/source/topics/mtproto-vs-botapi.rst b/docs/source/topics/mtproto-vs-botapi.rst new file mode 100644 index 00000000..cad84251 --- /dev/null +++ b/docs/source/topics/mtproto-vs-botapi.rst @@ -0,0 +1,110 @@ +MTProto vs. Bot API +=================== + +Pyrogram is a framework that acts as a fully-fledged Telegram client based on MTProto, and this very feature makes it +already superior to, what is usually called, the official Bot API, in many respects. This page will therefore show you +why Pyrogram might be a better choice for your project by comparing the two APIs, but first, let's make it clear what +actually is the MTProto and the Bot API. + +What is the MTProto API? +------------------------ + +`MTProto`_, took alone, is the name of the custom-made, open and encrypted communication protocol created by Telegram +itself --- it's the only protocol used to exchange information between a client and the actual Telegram servers. + +The MTProto **API** on the other hand, is what people, for convenience, call the main Telegram API as a whole. This API +is able to authorize both users and bots and is built on top of the MTProto encryption protocol by means of +`binary data serialized`_ in a specific way, as described by the `TL language`_, and delivered using UDP, TCP or even +HTTP as transport-layer protocol. + +.. _MTProto: https://core.telegram.org/mtproto +.. _binary data serialized: https://core.telegram.org/mtproto/serialize +.. _TL language: https://core.telegram.org/mtproto/TL + +What is the Bot API? +-------------------- + +The `Bot API`_ is an HTTP(S) interface for building normal bots using a sub-set of the main MTProto API. Bots are special +accounts that are authorized via tokens instead of phone numbers. The Bot API is built yet again on top of the main +Telegram API, but runs on an intermediate server application that in turn communicates with the actual Telegram servers +using MTProto. + +.. figure:: https://i.imgur.com/C108qkX.png + :align: center + +.. _Bot API: https://core.telegram.org/bots/api + +Advantages of the MTProto API +----------------------------- + +Here is a list of all the advantages in using MTProto-based libraries -- such as Pyrogram -- instead of the official +HTTP Bot API. Using Pyrogram you can: + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Authorize both user and bot identities** + - :guilabel:`--` The Bot API only allows bot accounts + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Upload & download any file, up to 1500 MB each (~1.5 GB)** + - :guilabel:`--` The Bot API allows uploads and downloads of files only up to 50 MB / 20 MB in size (respectively). + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Has less overhead due to direct connections to Telegram** + - :guilabel:`--` The Bot API uses an intermediate server to handle HTTP requests before they are sent to the actual + Telegram servers. + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Run multiple sessions at once, up to 10 per account (either bot or user)** + - :guilabel:`--` The Bot API intermediate server will terminate any other session in case you try to use the same + bot again in a parallel connection. + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Has much more detailed types and powerful methods** + - :guilabel:`--` The Bot API types often miss some useful information about Telegram entities and some of the + methods are limited as well. + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Get information about any public chat by usernames, even if not a member** + - :guilabel:`--` The Bot API simply doesn't support this + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Obtain information about any message existing in a chat using their ids** + - :guilabel:`--` The Bot API simply doesn't support this + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Retrieve the whole chat members list of either public or private chats** + - :guilabel:`--` The Bot API simply doesn't support this + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Receive extra updates, such as the one about a user name change** + - :guilabel:`--` The Bot API simply doesn't support this + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Has more meaningful errors in case something went wrong** + - :guilabel:`--` The Bot API reports less detailed errors + +.. hlist:: + :columns: 1 + + - :guilabel:`+` **Get API version updates, and thus new features, sooner** + - :guilabel:`--` The Bot API is simply slower in implementing new features diff --git a/docs/source/resources/SOCKS5Proxy.rst b/docs/source/topics/proxy.rst similarity index 100% rename from docs/source/resources/SOCKS5Proxy.rst rename to docs/source/topics/proxy.rst diff --git a/docs/source/topics/serialize.rst b/docs/source/topics/serialize.rst new file mode 100644 index 00000000..32208199 --- /dev/null +++ b/docs/source/topics/serialize.rst @@ -0,0 +1,55 @@ +Object Serialization +==================== + +Serializing means converting a Pyrogram object, which exists as Python class instance, to a text string that can be +easily shared and stored anywhere. Pyrogram provides two formats for serializing its objects: one good looking for +humans and another more compact for machines that is able to recover the original structures. + +For Humans - str(obj) +--------------------- + +If you want a nicely formatted, human readable JSON representation of any object in the API -- namely, any object from +`Pyrogram types`_, `raw functions`_ and `raw types`_ -- you can use use ``str(obj)``. + +.. code-block:: python + + ... + + with app: + r = app.get_chat("haskell") + + print(str(r)) + +.. tip:: + + When using ``print()`` you don't actually need to use ``str()`` on the object because it is called automatically, we + have done that above just to show you how to explicitly convert a Pyrogram object to JSON. + +.. _Pyrogram types: ../api/types +.. _raw functions: ../telegram/functions +.. _raw types: ../telegram/types + +For Machines - repr(obj) +------------------------ + +If you want to share or store objects for future references in a more compact way, you can use ``repr(obj)``. While +still pretty much readable, this format is not intended for humans. The advantage of this format is that once you +serialize your object, you can use ``eval()`` to get back the original structure; just make sure to ``import pyrogram``, +as the process requires the package to be in scope. + +.. code-block:: python + + import pyrogram + + ... + + with app: + r = app.get_chat("haskell") + + print(repr(r)) + print(eval(repr(r)) == r) # True + +.. note:: + + Type definitions are subject to changes between versions. You should make sure to store and load objects using the + same Pyrogram version. \ No newline at end of file diff --git a/docs/source/resources/CustomizeSessions.rst b/docs/source/topics/session-settings.rst similarity index 75% rename from docs/source/resources/CustomizeSessions.rst rename to docs/source/topics/session-settings.rst index 77765287..91e3f050 100644 --- a/docs/source/resources/CustomizeSessions.rst +++ b/docs/source/topics/session-settings.rst @@ -1,24 +1,23 @@ -Customize Sessions -================== +Session Settings +================ As you may probably know, Telegram allows users (and bots) having more than one session (authorizations) registered in the system at the same time. Briefly explaining, sessions are simply new logins in your account. They can be reviewed in the settings of an official -app (or by invoking `GetAuthorizations <../functions/account/GetAuthorizations.html>`_ with Pyrogram). They store some -useful information such as the client who's using them and from which country and IP address. +app (or by invoking `GetAuthorizations <../telegram/functions/account/GetAuthorizations.html>`_ with Pyrogram). They +store some useful information such as the client who's using them and from which country and IP address. - -.. figure:: https://i.imgur.com/lzGPCdZ.png - :width: 70% +.. figure:: https://i.imgur.com/YaqtMLO.png + :width: 600 :align: center - **A Pyrogram session running on Linux, Python 3.6.** + **A Pyrogram session running on Linux, Python 3.7.** That's how a session looks like on the Android app, showing the three main pieces of information. -- ``app_version``: **Pyrogram 🔥 0.7.5** -- ``device_model``: **CPython 3.6.5** +- ``app_version``: **Pyrogram 0.13.0** +- ``device_model``: **CPython 3.7.2** - ``system_version``: **Linux 4.15.0-23-generic** Set Custom Values diff --git a/docs/source/resources/SmartPlugins.rst b/docs/source/topics/smart-plugins.rst similarity index 93% rename from docs/source/resources/SmartPlugins.rst rename to docs/source/topics/smart-plugins.rst index 6f266590..9f1592d1 100644 --- a/docs/source/resources/SmartPlugins.rst +++ b/docs/source/topics/smart-plugins.rst @@ -30,7 +30,7 @@ after importing your modules, like this: handlers.py main.py -- ``handlers.py`` +- ``handlers.py`` .. code-block:: python @@ -41,7 +41,7 @@ after importing your modules, like this: def echo_reversed(client, message): message.reply(message.text[::-1]) -- ``main.py`` +- ``main.py`` .. code-block:: python @@ -65,7 +65,7 @@ after importing your modules, like this: app.run() This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to -manually ``import``, manually :meth:`add_handler ` and manually instantiate each +manually ``import``, manually :meth:`add_handler() ` and manually instantiate each :obj:`MessageHandler ` object because **you can't use those cool decorators** for your functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically. @@ -91,7 +91,7 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight config.ini main.py -- ``plugins/handlers.py`` +- ``plugins/handlers.py`` .. code-block:: python :emphasize-lines: 4, 9 @@ -108,14 +108,14 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight def echo_reversed(client, message): message.reply(message.text[::-1]) -- ``config.ini`` +- ``config.ini`` .. code-block:: ini [plugins] root = plugins -- ``main.py`` +- ``main.py`` .. code-block:: python @@ -156,7 +156,7 @@ found inside each module will be, instead, loaded in the order they are defined, .. note:: Remember: there can be at most one handler, within a group, dealing with a specific update. Plugins with overlapping - filters included a second time will not work. Learn more at `More on Updates `_. + filters included a second time will not work. Learn more at `More on Updates `_. This default loading behaviour is usually enough, but sometimes you want to have more control on what to include (or exclude) and in which exact order to load plugins. The way to do this is to make use of ``include`` and ``exclude`` @@ -199,8 +199,8 @@ also organized in subfolders: ... ... -- Load every handler from every module, namely *plugins0.py*, *plugins1.py* and *plugins2.py* in alphabetical order - (files) and definition order (handlers inside files): +- Load every handler from every module, namely *plugins0.py*, *plugins1.py* and *plugins2.py* in alphabetical order + (files) and definition order (handlers inside files): Using *config.ini* file: @@ -217,7 +217,7 @@ also organized in subfolders: Client("my_account", plugins=plugins).run() -- Load only handlers defined inside *plugins2.py* and *plugins0.py*, in this order: +- Load only handlers defined inside *plugins2.py* and *plugins0.py*, in this order: Using *config.ini* file: @@ -243,7 +243,7 @@ also organized in subfolders: Client("my_account", plugins=plugins).run() -- Load everything except the handlers inside *plugins2.py*: +- Load everything except the handlers inside *plugins2.py*: Using *config.ini* file: @@ -264,7 +264,7 @@ also organized in subfolders: Client("my_account", plugins=plugins).run() -- Load only *fn3*, *fn1* and *fn2* (in this order) from *plugins1.py*: +- Load only *fn3*, *fn1* and *fn2* (in this order) from *plugins1.py*: Using *config.ini* file: @@ -297,7 +297,7 @@ Each function decorated with the usual ``on_message`` decorator (or any other de *(handler: Handler, group: int)*. The actual callback function is therefore stored inside the handler's *callback* attribute. Here's an example: -- ``plugins/handlers.py`` +- ``plugins/handlers.py`` .. code-block:: python :emphasize-lines: 5, 6 @@ -321,7 +321,7 @@ In order to unload a plugin, or any other handler, all you need to do is obtain relevant module and call :meth:`remove_handler() ` Client's method with your function name preceded by the star ``*`` operator as argument. Example: -- ``main.py`` +- ``main.py`` .. code-block:: python @@ -345,7 +345,7 @@ Loading Similarly to the unloading process, in order to load again a previously unloaded plugin you do the same, but this time using :meth:`add_handler() ` instead. Example: -- ``main.py`` +- ``main.py`` .. code-block:: python diff --git a/docs/source/resources/TestServers.rst b/docs/source/topics/test-servers.rst similarity index 100% rename from docs/source/resources/TestServers.rst rename to docs/source/topics/test-servers.rst diff --git a/docs/source/resources/TextFormatting.rst b/docs/source/topics/text-formatting.rst similarity index 78% rename from docs/source/resources/TextFormatting.rst rename to docs/source/topics/text-formatting.rst index 0ab08694..8f2292d0 100644 --- a/docs/source/resources/TextFormatting.rst +++ b/docs/source/topics/text-formatting.rst @@ -11,7 +11,7 @@ Beside bold, italic, and pre-formatted code, **Pyrogram does also support inline Markdown Style -------------- -To use this mode, pass :obj:`MARKDOWN ` or "markdown" in the *parse_mode* field when using +To use this mode, pass "markdown" in the *parse_mode* field when using :obj:`send_message() `. Use the following syntax in your message: .. code-block:: text @@ -20,7 +20,7 @@ To use this mode, pass :obj:`MARKDOWN ` or "markdow __italic text__ - [inline URL](https://docs.pyrogram.ml/) + [inline URL](https://docs.pyrogram.org/) [inline mention of a user](tg://user?id=23122162) @@ -34,8 +34,8 @@ To use this mode, pass :obj:`MARKDOWN ` or "markdow HTML Style ---------- -To use this mode, pass :obj:`HTML ` or "html" in the *parse_mode* field when using -:obj:`send_message() `. The following tags are currently supported: +To use this mode, pass "html" in the *parse_mode* field when using :obj:`send_message() `. +The following tags are currently supported: .. code-block:: text @@ -43,7 +43,7 @@ To use this mode, pass :obj:`HTML ` or "html" in the *p italic, italic - inline URL + inline URL inline mention of a user @@ -66,7 +66,7 @@ Examples "**bold**, " "__italic__, " "[mention](tg://user?id=23122162), " - "[URL](https://docs.pyrogram.ml), " + "[URL](https://docs.pyrogram.org), " "`code`, " "```" "for i in range(10):\n" @@ -84,7 +84,7 @@ Examples "bold, " "italic, " "mention, " - "URL, " + "URL, " "code, " "
"
                 "for i in range(10):\n"
diff --git a/docs/source/resources/TgCrypto.rst b/docs/source/topics/tgcrypto.rst
similarity index 87%
rename from docs/source/resources/TgCrypto.rst
rename to docs/source/topics/tgcrypto.rst
index 2af09a06..454bf05c 100644
--- a/docs/source/resources/TgCrypto.rst
+++ b/docs/source/topics/tgcrypto.rst
@@ -2,7 +2,7 @@ Fast Crypto
 ===========
 
 Pyrogram's speed can be *dramatically* boosted up by TgCrypto_, a high-performance, easy-to-install Telegram Crypto
-Library specifically written in C for Pyrogram [#f1]_ as a Python extension.
+Library specifically written in C for Pyrogram [1]_ as a Python extension.
 
 TgCrypto is a replacement for the much slower PyAES and implements the crypto algorithms Telegram requires, namely
 **AES-IGE 256 bit** (used in MTProto v2.0) and **AES-CTR 256 bit** (used for CDN encrypted files).
@@ -28,5 +28,5 @@ what you should do next:
 
 .. _TgCrypto: https://github.com/pyrogram/tgcrypto
 
-.. [#f1] Although TgCrypto is intended for Pyrogram, it is shipped as a standalone package and can thus be used for
+.. [1] Although TgCrypto is intended for Pyrogram, it is shipped as a standalone package and can thus be used for
    other Python projects too.
diff --git a/docs/source/resources/VoiceCalls.rst b/docs/source/topics/voice-calls.rst
similarity index 100%
rename from docs/source/resources/VoiceCalls.rst
rename to docs/source/topics/voice-calls.rst
diff --git a/examples/README.md b/examples/README.md
index 643fe56d..b8898a71 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -12,12 +12,12 @@ Example | Description
 ---: | :---
 [**hello_world**](hello_world.py) | Demonstration of basic API usage
 [**echobot**](echobot.py) | Echo every private text message
-[**welcome**](welcome.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat)
-[**history**](history.py) | Get the full message history of a chat
-[**chat_members**](chat_members.py) | Get all the members of a chat
-[**dialogs**](dialogs.py) | Get all of your dialog chats
-[**using_inline_bots**](using_inline_bots.py) | Query an inline bot (as user) and send a result to a chat
-[**keyboards**](keyboards.py) | Send normal and inline keyboards using regular bots
-[**callback_queries**](callback_queries.py) | Handle queries coming from inline button presses
-[**inline_queries**](inline_queries.py) | Handle inline queries
+[**welcomebot**](welcomebot.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat)
+[**get_history**](get_history.py) | Get the full message history of a chat
+[**get_chat_members**](get_chat_members.py) | Get all the members of a chat
+[**get_dialogs**](get_dialogs.py) | Get all of your dialog chats
+[**callback_queries**](callback_queries.py) | Handle callback queries (as bot) coming from inline button presses
+[**inline_queries**](inline_queries.py) | Handle inline queries (as bot) and answer with results
+[**use_inline_bots**](use_inline_bots.py) | Query an inline bot (as user) and send a result to a chat
+[**bot_keyboards**](bot_keyboards.py) | Send normal and inline keyboards using regular bots
 [**raw_updates**](raw_updates.py) | Handle raw updates (old, should be avoided)
diff --git a/examples/keyboards.py b/examples/bot_keyboards.py
similarity index 96%
rename from examples/keyboards.py
rename to examples/bot_keyboards.py
index 1a1140b6..e1ff1e7e 100644
--- a/examples/keyboards.py
+++ b/examples/bot_keyboards.py
@@ -1,4 +1,4 @@
-"""This example will show you how to send normal and inline keyboards.
+"""This example will show you how to send normal and inline keyboards (as bot).
 
 You must log-in as a regular bot in order to send keyboards (use the token from @BotFather).
 Any attempt in sending keyboards with a user account will be simply ignored by the server.
@@ -39,7 +39,7 @@ with app:
                     ),
                     InlineKeyboardButton(  # Opens a web URL
                         "URL",
-                        url="https://docs.pyrogram.ml"
+                        url="https://docs.pyrogram.org"
                     ),
                 ],
                 [  # Second row
diff --git a/examples/chat_members.py b/examples/get_chat_members.py
similarity index 100%
rename from examples/chat_members.py
rename to examples/get_chat_members.py
diff --git a/examples/dialogs.py b/examples/get_dialogs.py
similarity index 72%
rename from examples/dialogs.py
rename to examples/get_dialogs.py
index 08c769e2..92da8834 100644
--- a/examples/dialogs.py
+++ b/examples/get_dialogs.py
@@ -1,4 +1,4 @@
-"""This example shows how to get the full dialogs list of a user."""
+"""This example shows how to get the full dialogs list (as user)."""
 
 from pyrogram import Client
 
diff --git a/examples/history.py b/examples/get_history.py
similarity index 100%
rename from examples/history.py
rename to examples/get_history.py
diff --git a/examples/inline_queries.py b/examples/inline_queries.py
index c1727fe6..d86d90d5 100644
--- a/examples/inline_queries.py
+++ b/examples/inline_queries.py
@@ -22,12 +22,12 @@ def answer(client, inline_query):
                 input_message_content=InputTextMessageContent(
                     "Here's how to install **Pyrogram**"
                 ),
-                url="https://docs.pyrogram.ml/start/Installation",
+                url="https://docs.pyrogram.org/intro/install",
                 description="How to install Pyrogram",
                 thumb_url="https://i.imgur.com/JyxrStE.png",
                 reply_markup=InlineKeyboardMarkup(
                     [
-                        [InlineKeyboardButton("Open website", url="https://docs.pyrogram.ml/start/Installation")]
+                        [InlineKeyboardButton("Open website", url="https://docs.pyrogram.org/intro/install")]
                     ]
                 )
             ),
@@ -37,12 +37,12 @@ def answer(client, inline_query):
                 input_message_content=InputTextMessageContent(
                     "Here's how to use **Pyrogram**"
                 ),
-                url="https://docs.pyrogram.ml/start/Usage",
+                url="https://docs.pyrogram.org/start/invoking",
                 description="How to use Pyrogram",
                 thumb_url="https://i.imgur.com/JyxrStE.png",
                 reply_markup=InlineKeyboardMarkup(
                     [
-                        [InlineKeyboardButton("Open website", url="https://docs.pyrogram.ml/start/Usage")]
+                        [InlineKeyboardButton("Open website", url="https://docs.pyrogram.org/start/invoking")]
                     ]
                 )
             )
diff --git a/examples/use_inline_bots.py b/examples/use_inline_bots.py
new file mode 100644
index 00000000..5681df87
--- /dev/null
+++ b/examples/use_inline_bots.py
@@ -0,0 +1,13 @@
+"""This example shows how to query an inline bot (as user)"""
+
+from pyrogram import Client
+
+# Create a new Client
+app = Client("my_account")
+
+with app:
+    # Get bot results for "Fuzz Universe" from the inline bot @vid
+    bot_results = app.get_inline_bot_results("vid", "Fuzz Universe")
+
+    # Send the first result (bot_results.results[0]) to your own chat (Saved Messages)
+    app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id)
diff --git a/examples/using_inline_bots.py b/examples/using_inline_bots.py
deleted file mode 100644
index c3b48874..00000000
--- a/examples/using_inline_bots.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""This example shows how to query an inline bot"""
-
-from pyrogram import Client
-
-# Create a new Client
-app = Client("my_account")
-
-# Start the Client
-app.start()
-
-# Get bot results for "Fuzz Universe" from the inline bot @vid
-bot_results = app.get_inline_bot_results("vid", "Fuzz Universe")
-# Send the first result (bot_results.results[0]) to your own chat (Saved Messages)
-app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id)
-
-# Stop the client
-app.stop()
diff --git a/examples/welcome.py b/examples/welcomebot.py
similarity index 91%
rename from examples/welcome.py
rename to examples/welcomebot.py
index ab252672..35f72aff 100644
--- a/examples/welcome.py
+++ b/examples/welcomebot.py
@@ -8,7 +8,7 @@ from pyrogram import Client, Emoji, Filters
 
 TARGET = "PyrogramChat"  # Target chat. Can also be a list of multiple chat ids/usernames
 MENTION = "[{}](tg://user?id={})"  # User mention markup
-MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {}!"  # Welcome message
+MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.org/)'s group chat {}!"  # Welcome message
 
 app = Client("my_account")
 
diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py
index 4bf8f069..317e9df2 100644
--- a/pyrogram/__init__.py
+++ b/pyrogram/__init__.py
@@ -26,9 +26,7 @@ if sys.version_info[:3] in [(3, 5, 0), (3, 5, 1), (3, 5, 2)]:
 
 __version__ = "0.13.0.async"
 __license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
-__copyright__ = "Copyright (C) 2017-2019 Dan Tès ".replace(
-    "\xe8", "e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
-)
+__copyright__ = "Copyright (C) 2017-2019 Dan "
 
 try:
     import uvloop
diff --git a/pyrogram/api/core/object.py b/pyrogram/api/core/object.py
index a479fb6e..ace7a59a 100644
--- a/pyrogram/api/core/object.py
+++ b/pyrogram/api/core/object.py
@@ -30,43 +30,51 @@ class Object:
     QUALNAME = "Base"
 
     @staticmethod
-    def read(b: BytesIO, *args):
+    def read(b: BytesIO, *args):  # TODO: Rename b -> data
         return Object.all[int.from_bytes(b.read(4), "little")].read(b, *args)
 
     def write(self, *args) -> bytes:
         pass
 
+    def __eq__(self, other: "Object") -> bool:
+        for attr in self.__slots__:
+            try:
+                if getattr(self, attr) != getattr(other, attr):
+                    return False
+            except AttributeError:
+                return False
+
+        return True
+
     def __str__(self) -> str:
+        def default(obj: Object):
+            try:
+                return OrderedDict(
+                    [("_", obj.QUALNAME)]
+                    + [(attr, getattr(obj, attr))
+                       for attr in obj.__slots__
+                       if getattr(obj, attr) is not None]
+                )
+            except AttributeError:
+                if isinstance(obj, datetime):
+                    return obj.strftime("%d-%b-%Y %H:%M:%S")
+                else:
+                    return repr(obj)
+
         return dumps(self, indent=4, default=default, ensure_ascii=False)
 
+    def __repr__(self) -> str:
+        return "pyrogram.api.{}({})".format(
+            self.QUALNAME,
+            ", ".join(
+                "{}={}".format(attr, repr(getattr(self, attr)))
+                for attr in self.__slots__
+                if getattr(self, attr) is not None
+            )
+        )
+
     def __len__(self) -> int:
         return len(self.write())
 
     def __getitem__(self, item):
         return getattr(self, item)
-
-
-def remove_none(obj):
-    if isinstance(obj, (list, tuple, set)):
-        return type(obj)(remove_none(x) for x in obj if x is not None)
-    elif isinstance(obj, dict):
-        return type(obj)((remove_none(k), remove_none(v)) for k, v in obj.items() if k is not None and v is not None)
-    else:
-        return obj
-
-
-def default(o: "Object"):
-    try:
-        content = {i: getattr(o, i) for i in o.__slots__}
-
-        return remove_none(
-            OrderedDict(
-                [("_", o.QUALNAME)]
-                + [i for i in content.items()]
-            )
-        )
-    except AttributeError:
-        if isinstance(o, datetime):
-            return o.strftime("%d-%b-%Y %H:%M:%S")
-        else:
-            return repr(o)
diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py
index d43511d2..f4a954c6 100644
--- a/pyrogram/client/__init__.py
+++ b/pyrogram/client/__init__.py
@@ -17,9 +17,9 @@
 # along with Pyrogram.  If not, see .
 
 from .client import Client
-from .ext import BaseClient, ChatAction, Emoji, ParseMode
+from .ext import BaseClient, Emoji
 from .filters import Filters
 
 __all__ = [
-    "Client", "BaseClient", "ChatAction", "Emoji", "ParseMode", "Filters",
+    "Client", "BaseClient", "Emoji", "Filters",
 ]
diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py
index ce8ae2fd..dd9cc3dd 100644
--- a/pyrogram/client/client.py
+++ b/pyrogram/client/client.py
@@ -61,27 +61,23 @@ log = logging.getLogger(__name__)
 
 
 class Client(Methods, BaseClient):
-    """This class represents a Client, the main mean for interacting with Telegram.
-    It exposes bot-like methods for an easy access to the API as well as a simple way to
-    invoke every single Telegram API method available.
+    """Pyrogram Client, the main means for interacting with Telegram.
 
-    Args:
+    Parameters:
         session_name (``str``):
             Name to uniquely identify a session of either a User or a Bot, e.g.: "my_account". This name will be used
             to save a file to disk that stores details needed for reconnecting without asking again for credentials.
-            Note for bots: You can pass a bot token here, but this usage will be deprecated in next releases.
-            Use *bot_token* instead.
 
         api_id (``int``, *optional*):
             The *api_id* part of your Telegram API Key, as integer. E.g.: 12345
             This is an alternative way to pass it if you don't want to use the *config.ini* file.
 
         api_hash (``str``, *optional*):
-            The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef"
+            The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef".
             This is an alternative way to pass it if you don't want to use the *config.ini* file.
 
         app_version (``str``, *optional*):
-            Application version. Defaults to "Pyrogram \U0001f525 vX.Y.Z"
+            Application version. Defaults to "Pyrogram X.Y.Z"
             This is an alternative way to set it if you don't want to use the *config.ini* file.
 
         device_model (``str``, *optional*):
@@ -107,10 +103,14 @@ class Client(Methods, BaseClient):
             This is an alternative way to setup a proxy if you don't want to use the *config.ini* file.
 
         test_mode (``bool``, *optional*):
-            Enable or disable log-in to testing servers. Defaults to False.
+            Enable or disable login to the test servers. Defaults to False.
             Only applicable for new sessions and will be ignored in case previously
             created sessions are loaded.
 
+        bot_token (``str``, *optional*):
+            Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
+            Only applicable for new sessions.
+
         phone_number (``str`` | ``callable``, *optional*):
             Pass your phone number as string (with your Country Code prefix included) to avoid entering it manually.
             Or pass a callback function which accepts no arguments and must return the correct phone number as string
@@ -144,10 +144,6 @@ class Client(Methods, BaseClient):
             a new Telegram account in case the phone number you passed is not registered yet.
             Only applicable for new sessions.
 
-        bot_token (``str``, *optional*):
-            Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
-            Only applicable for new sessions.
-
         last_name (``str``, *optional*):
             Same purpose as *first_name*; pass a Last Name to avoid entering it manually. It can
             be an empty string: "". Only applicable for new sessions.
@@ -173,7 +169,7 @@ class Client(Methods, BaseClient):
             Defaults to False (updates enabled and always received).
 
         takeout (``bool``, *optional*):
-            Pass True to let the client use a takeout session instead of a normal one, implies no_updates.
+            Pass True to let the client use a takeout session instead of a normal one, implies *no_updates=True*.
             Useful for exporting your Telegram data. Methods invoked inside a takeout session (such as get_history,
             download_media, ...) are less prone to throw FloodWait exceptions.
             Only available for users, bots will ignore this parameter.
@@ -194,12 +190,12 @@ class Client(Methods, BaseClient):
         ipv6: bool = False,
         proxy: dict = None,
         test_mode: bool = False,
+        bot_token: str = None,
         phone_number: str = None,
         phone_code: Union[str, callable] = None,
         password: str = None,
         recovery_code: callable = None,
         force_sms: bool = False,
-        bot_token: str = None,
         first_name: str = None,
         last_name: str = None,
         workers: int = BaseClient.WORKERS,
@@ -222,12 +218,12 @@ class Client(Methods, BaseClient):
         # TODO: Make code consistent, use underscore for private/protected fields
         self._proxy = proxy
         self.test_mode = test_mode
+        self.bot_token = bot_token
         self.phone_number = phone_number
         self.phone_code = phone_code
         self.password = password
         self.recovery_code = recovery_code
         self.force_sms = force_sms
-        self.bot_token = bot_token
         self.first_name = first_name
         self.last_name = last_name
         self.workers = workers
@@ -268,12 +264,11 @@ class Client(Methods, BaseClient):
         self._proxy.update(value)
 
     async def start(self):
-        """Use this method to start the Client after creating it.
-        Requires no parameters.
+        """Start the Client.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ConnectionError`` in case you try to start an already started Client.
+            RPCError: In case of a Telegram RPC error.
+            ConnectionError: In case you try to start an already started Client.
         """
         if self.is_started:
             raise ConnectionError("Client has already been started")
@@ -285,7 +280,7 @@ class Client(Methods, BaseClient):
             log.warning('\nWARNING: You are using a bot token as session name!\n'
                         'This usage will be deprecated soon. Please use a session file name to load '
                         'an existing session and the bot_token argument to create new sessions.\n'
-                        'More info: https://docs.pyrogram.ml/start/Setup#bot-authorization\n')
+                        'More info: https://docs.pyrogram.org/intro/auth#bot-authorization\n')
 
         self.load_config()
         await self.load_session()
@@ -351,11 +346,10 @@ class Client(Methods, BaseClient):
         return self
 
     async def stop(self):
-        """Use this method to manually stop the Client.
-        Requires no parameters.
+        """Stop the Client.
 
         Raises:
-            ``ConnectionError`` in case you try to stop an already stopped Client.
+            ConnectionError: In case you try to stop an already stopped Client.
         """
         if not self.is_started:
             raise ConnectionError("Client is already stopped")
@@ -391,25 +385,34 @@ class Client(Methods, BaseClient):
         return self
 
     async def restart(self):
-        """Use this method to restart the Client.
-        Requires no parameters.
+        """Restart the Client.
 
         Raises:
-            ``ConnectionError`` in case you try to restart a stopped Client.
+            ConnectionError: In case you try to restart a stopped Client.
         """
         await self.stop()
         await self.start()
 
     async def idle(self, stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)):
-        """Blocks the program execution until one of the signals are received,
-        then gently stop the Client by closing the underlying connection.
+        """Block the main script execution until a signal (e.g.: from CTRL+C) is received.
+        Once the signal is received, the client will automatically stop and the main script will continue its execution.
 
-        Args:
+        This is used after starting one or more clients and is useful for event-driven applications only, that are,
+        applications which react upon incoming Telegram updates through handlers, rather than executing a set of methods
+        sequentially.
+
+        The way Pyrogram works, will keep your handlers in a pool of workers, which are executed concurrently outside
+        the main script; calling idle() will ensure the client(s) will be kept alive by not letting the main script to
+        end, until you decide to quit.
+
+        Parameters:
             stop_signals (``tuple``, *optional*):
                 Iterable containing signals the signal handler will listen to.
                 Defaults to (SIGINT, SIGTERM, SIGABRT).
         """
 
+        # TODO: Maybe make this method static and don't automatically stop
+
         def signal_handler(*args):
             log.info("Stop signal received ({}). Exiting...".format(args[0]))
             self.is_idle = False
@@ -425,16 +428,18 @@ class Client(Methods, BaseClient):
         await self.stop()
 
     def run(self, coroutine=None):
-        """Use this method to automatically start and idle a Client.
-        If a coroutine is passed as argument this method will start the client, run the coroutine
-        until is complete and then stop the client automatically.
+        """Start the Client and automatically idle the main script.
+
+        This is a convenience method that literally just calls :meth:`start` and :meth:`idle`. It makes running a client
+        less verbose, but is not suitable in case you want to run more than one client in a single main script,
+        since :meth:`idle` will block.
 
         Args:
             coroutine: (``Coroutine``, *optional*):
                 Pass a coroutine to run it until is complete.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         run = asyncio.get_event_loop().run_until_complete
 
@@ -452,13 +457,13 @@ class Client(Methods, BaseClient):
         return coroutine
 
     def add_handler(self, handler: Handler, group: int = 0):
-        """Use this method to register an update handler.
+        """Register an update handler.
 
         You can register multiple handlers, but at most one handler within a group
         will be used for a single update. To handle the same update more than once, register
         your handler using a different group id (lower group id == higher priority).
 
-        Args:
+        Parameters:
             handler (``Handler``):
                 The handler to be registered.
 
@@ -466,7 +471,7 @@ class Client(Methods, BaseClient):
                 The group identifier, defaults to 0.
 
         Returns:
-            A tuple of (handler, group)
+            ``tuple``: A tuple consisting of (handler, group).
         """
         if isinstance(handler, DisconnectHandler):
             self.disconnect_handler = handler.callback
@@ -476,13 +481,13 @@ class Client(Methods, BaseClient):
         return handler, group
 
     def remove_handler(self, handler: Handler, group: int = 0):
-        """Removes a previously-added update handler.
+        """Remove a previously-registered update handler.
 
         Make sure to provide the right group that the handler was added in. You can use
         the return value of the :meth:`add_handler` method, a tuple of (handler, group), and
         pass it directly.
 
-        Args:
+        Parameters:
             handler (``Handler``):
                 The handler to be removed.
 
@@ -495,7 +500,7 @@ class Client(Methods, BaseClient):
             self.dispatcher.remove_handler(handler, group)
 
     def stop_transmission(self):
-        """Use this method to stop downloading or uploading a file.
+        """Stop downloading or uploading a file.
         Must be called inside a progress callback function.
         """
         raise Client.StopTransmission
@@ -763,9 +768,16 @@ class Client(Methods, BaseClient):
 
         print("Logged in successfully as {}".format(r.user.first_name))
 
-    def fetch_peers(self, entities: List[Union[types.User,
-                                               types.Chat, types.ChatForbidden,
-                                               types.Channel, types.ChannelForbidden]]):
+    def fetch_peers(
+        self,
+        entities: List[
+            Union[
+                types.User,
+                types.Chat, types.ChatForbidden,
+                types.Channel, types.ChannelForbidden
+            ]
+        ]
+    ):
         for entity in entities:
             if isinstance(entity, types.User):
                 user_id = entity.id
@@ -1027,14 +1039,20 @@ class Client(Methods, BaseClient):
                    data: Object,
                    retries: int = Session.MAX_RETRIES,
                    timeout: float = Session.WAIT_TIMEOUT):
-        """Use this method to send Raw Function queries.
+        """Send raw Telegram queries.
 
-        This method makes possible to manually call every single Telegram API method in a low-level manner.
+        This method makes it possible to manually call every single Telegram API method in a low-level manner.
         Available functions are listed in the :obj:`functions ` package and may accept compound
         data types from :obj:`types ` as well as bare types such as ``int``, ``str``, etc...
 
-        Args:
-            data (``Object``):
+        .. note::
+
+            This is a utility method intended to be used **only** when working with raw
+            :obj:`functions ` (i.e: a Telegram API method you wish to use which is not
+            available yet in the Client class as an easy-to-use method).
+
+        Parameters:
+            data (``RawFunction``):
                 The API Schema function filled with proper arguments.
 
             retries (``int``):
@@ -1043,8 +1061,11 @@ class Client(Methods, BaseClient):
             timeout (``float``):
                 Timeout in seconds.
 
+        Returns:
+            ``RawType``: The raw type response generated by the query.
+
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if not self.is_started:
             raise ConnectionError("Client has not been started")
@@ -1075,7 +1096,7 @@ class Client(Methods, BaseClient):
             else:
                 raise AttributeError(
                     "No API Key found. "
-                    "More info: https://docs.pyrogram.ml/start/ProjectSetup#configuration"
+                    "More info: https://docs.pyrogram.org/intro/setup#configuration"
                 )
 
         for option in ["app_version", "device_model", "system_version", "lang_code"]:
@@ -1325,23 +1346,26 @@ class Client(Methods, BaseClient):
 
     async def resolve_peer(self,
                            peer_id: Union[int, str]):
-        """Use this method to get the InputPeer of a known peer_id.
+        """Get the InputPeer of a known peer id.
+        Useful whenever an InputPeer type is required.
 
-        This is a utility method intended to be used **only** when working with Raw Functions (i.e: a Telegram API
-        method you wish to use which is not available yet in the Client class as an easy-to-use method), whenever an
-        InputPeer type is required.
+        .. note::
 
-        Args:
+            This is a utility method intended to be used **only** when working with raw
+            :obj:`functions ` (i.e: a Telegram API method you wish to use which is not
+            available yet in the Client class as an easy-to-use method).
+
+        Parameters:
             peer_id (``int`` | ``str``):
                 The peer id you want to extract the InputPeer from.
                 Can be a direct id (int), a username (str) or a phone number (str).
 
         Returns:
-            On success, the resolved peer id is returned in form of an InputPeer object.
+            ``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``KeyError`` in case the peer doesn't exist in the internal database.
+            RPCError: In case of a Telegram RPC error.
+            KeyError: In case the peer doesn't exist in the internal database.
         """
         try:
             return self.peers_by_id[peer_id]
@@ -1399,14 +1423,18 @@ class Client(Methods, BaseClient):
                         file_id: int = None,
                         file_part: int = 0,
                         progress: callable = None,
-                        progress_args: tuple = ()):
-        """Use this method to upload a file onto Telegram servers, without actually sending the message to anyone.
+                        progress_args: tuple = ()
+    ):
+        """Upload a file onto Telegram servers, without actually sending the message to anyone.
+        Useful whenever an InputFile type is required.
 
-        This is a utility method intended to be used **only** when working with Raw Functions (i.e: a Telegram API
-        method you wish to use which is not available yet in the Client class as an easy-to-use method), whenever an
-        InputFile type is required.
+        .. note::
 
-        Args:
+            This is a utility method intended to be used **only** when working with raw
+            :obj:`functions ` (i.e: a Telegram API method you wish to use which is not
+            available yet in the Client class as an easy-to-use method).
+
+        Parameters:
             path (``str``):
                 The path of the file you want to upload that exists on your local machine.
 
@@ -1426,7 +1454,7 @@ class Client(Methods, BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -1440,10 +1468,10 @@ class Client(Methods, BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the uploaded file is returned in form of an InputFile object.
+            ``InputFile``: On success, the uploaded file is returned in form of an InputFile object.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         async def worker(session):
diff --git a/pyrogram/client/ext/__init__.py b/pyrogram/client/ext/__init__.py
index 18c28ac3..917c9e62 100644
--- a/pyrogram/client/ext/__init__.py
+++ b/pyrogram/client/ext/__init__.py
@@ -17,8 +17,6 @@
 # along with Pyrogram.  If not, see .
 
 from .base_client import BaseClient
-from .chat_action import ChatAction
 from .dispatcher import Dispatcher
 from .emoji import Emoji
-from .parse_mode import ParseMode
 from .syncer import Syncer
diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/client/ext/base_client.py
index 3c2311fe..9377cce8 100644
--- a/pyrogram/client/ext/base_client.py
+++ b/pyrogram/client/ext/base_client.py
@@ -30,7 +30,7 @@ class BaseClient:
     class StopTransmission(StopAsyncIteration):
         pass
 
-    APP_VERSION = "Pyrogram \U0001f525 {}".format(__version__)
+    APP_VERSION = "Pyrogram {}".format(__version__)
 
     DEVICE_MODEL = "{} {}".format(
         platform.python_implementation(),
diff --git a/pyrogram/client/ext/chat_action.py b/pyrogram/client/ext/chat_action.py
deleted file mode 100644
index c0ee0585..00000000
--- a/pyrogram/client/ext/chat_action.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2019 Dan Tès 
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram.  If not, see .
-
-from enum import Enum
-
-from pyrogram.api import types
-
-
-class ChatAction(Enum):
-    """This enumeration provides a convenient access to all Chat Actions available.
-    Chat Actions are intended to be used with
-    :meth:`send_chat_action() `.
-    """
-
-    CANCEL = types.SendMessageCancelAction
-    """Cancels any chat action currently displayed."""
-
-    TYPING = types.SendMessageTypingAction
-    """User is typing a text message."""
-
-    PLAYING = types.SendMessageGamePlayAction
-    """User is playing a game."""
-
-    CHOOSE_CONTACT = types.SendMessageChooseContactAction
-    """User is choosing a contact to share."""
-
-    UPLOAD_PHOTO = types.SendMessageUploadPhotoAction
-    """User is uploading a photo."""
-
-    RECORD_VIDEO = types.SendMessageRecordVideoAction
-    """User is recording a video."""
-
-    UPLOAD_VIDEO = types.SendMessageUploadVideoAction
-    """User is uploading a video."""
-
-    RECORD_AUDIO = types.SendMessageRecordAudioAction
-    """User is recording an audio message."""
-
-    UPLOAD_AUDIO = types.SendMessageUploadAudioAction
-    """User is uploading an audio message."""
-
-    UPLOAD_DOCUMENT = types.SendMessageUploadDocumentAction
-    """User is uploading a generic document."""
-
-    FIND_LOCATION = types.SendMessageGeoLocationAction
-    """User is searching for a location on the map."""
-
-    RECORD_VIDEO_NOTE = types.SendMessageRecordRoundAction
-    """User is recording a round video note."""
-
-    UPLOAD_VIDEO_NOTE = types.SendMessageUploadRoundAction
-    """User is uploading a round video note."""
-
-    @staticmethod
-    def from_string(action: str) -> "ChatAction":
-        for a in ChatAction:
-            if a.name.lower() == action.lower():
-                return a
-
-        raise ValueError("Invalid ChatAction: '{}'. Possible types are {}".format(
-            action, [x.name.lower() for x in ChatAction]
-        ))
diff --git a/pyrogram/client/ext/parse_mode.py b/pyrogram/client/ext/parse_mode.py
deleted file mode 100644
index 46ed97e3..00000000
--- a/pyrogram/client/ext/parse_mode.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2019 Dan Tès 
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram.  If not, see .
-
-
-class ParseMode:
-    """This class provides a convenient access to Parse Modes.
-    Parse Modes are intended to be used with any method that accepts the optional argument **parse_mode**.
-    """
-
-    HTML = "html"
-    """Set the parse mode to HTML style"""
-
-    MARKDOWN = "markdown"
-    """Set the parse mode to Markdown style"""
diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py
index 4c6f0ce3..169193a0 100644
--- a/pyrogram/client/filters/filters.py
+++ b/pyrogram/client/filters/filters.py
@@ -19,15 +19,15 @@
 import re
 
 from .filter import Filter
-from ..types.bots import InlineKeyboardMarkup, ReplyKeyboardMarkup
+from ..types.keyboards import InlineKeyboardMarkup, ReplyKeyboardMarkup
 
 
 def create(name: str, func: callable, **kwargs) -> type:
-    """Use this method to create a Filter.
+    """Create a Filter.
 
     Custom filters give you extra control over which updates are allowed or not to be processed by your handlers.
 
-    Args:
+    Parameters:
         name (``str``):
             Your filter's name. Can be anything you like.
 
@@ -35,9 +35,9 @@ def create(name: str, func: callable, **kwargs) -> type:
             A function that accepts two arguments *(filter, update)* and returns a Boolean: True if the update should be
             handled, False otherwise.
             The "update" argument type will vary depending on which `Handler `_ is coming from.
-            For example, in a :obj:`MessageHandler ` the update type will be
-            a :obj:`Message `; in a :obj:`CallbackQueryHandler ` the
-            update type will be a :obj:`CallbackQuery `. Your function body can then access the
+            For example, in a :obj:`MessageHandler` the update type will be
+            a :obj:`Message`; in a :obj:`CallbackQueryHandler` the
+            update type will be a :obj:`CallbackQuery`. Your function body can then access the
             incoming update and decide whether to allow it or not.
 
         **kwargs (``any``, *optional*):
@@ -54,7 +54,7 @@ def create(name: str, func: callable, **kwargs) -> type:
 class Filters:
     """This class provides access to all library-defined Filters available in Pyrogram.
 
-    The Filters listed here are intended to be used with the :obj:`MessageHandler ` only.
+    The Filters listed here are intended to be used with the :obj:`MessageHandler` only.
     At the moment, if you want to filter updates coming from different `Handlers `_ you have to create
     your own filters with :meth:`Filters.create` and use them in the same way.
     """
@@ -89,49 +89,49 @@ class Filters:
     """Filter edited messages."""
 
     audio = create("Audio", lambda _, m: bool(m.audio))
-    """Filter messages that contain :obj:`Audio ` objects."""
+    """Filter messages that contain :obj:`Audio` objects."""
 
     document = create("Document", lambda _, m: bool(m.document))
-    """Filter messages that contain :obj:`Document ` objects."""
+    """Filter messages that contain :obj:`Document` objects."""
 
     photo = create("Photo", lambda _, m: bool(m.photo))
-    """Filter messages that contain :obj:`Photo ` objects."""
+    """Filter messages that contain :obj:`Photo` objects."""
 
     sticker = create("Sticker", lambda _, m: bool(m.sticker))
-    """Filter messages that contain :obj:`Sticker ` objects."""
+    """Filter messages that contain :obj:`Sticker` objects."""
 
     animation = create("Animation", lambda _, m: bool(m.animation))
-    """Filter messages that contain :obj:`Animation ` objects."""
+    """Filter messages that contain :obj:`Animation` objects."""
 
     game = create("Game", lambda _, m: bool(m.game))
-    """Filter messages that contain :obj:`Game ` objects."""
+    """Filter messages that contain :obj:`Game` objects."""
 
     video = create("Video", lambda _, m: bool(m.video))
-    """Filter messages that contain :obj:`Video ` objects."""
+    """Filter messages that contain :obj:`Video` objects."""
 
     media_group = create("MediaGroup", lambda _, m: bool(m.media_group_id))
     """Filter messages containing photos or videos being part of an album."""
 
     voice = create("Voice", lambda _, m: bool(m.voice))
-    """Filter messages that contain :obj:`Voice ` note objects."""
+    """Filter messages that contain :obj:`Voice` note objects."""
 
     video_note = create("VideoNote", lambda _, m: bool(m.video_note))
-    """Filter messages that contain :obj:`VideoNote ` objects."""
+    """Filter messages that contain :obj:`VideoNote` objects."""
 
     contact = create("Contact", lambda _, m: bool(m.contact))
-    """Filter messages that contain :obj:`Contact ` objects."""
+    """Filter messages that contain :obj:`Contact` objects."""
 
     location = create("Location", lambda _, m: bool(m.location))
-    """Filter messages that contain :obj:`Location ` objects."""
+    """Filter messages that contain :obj:`Location` objects."""
 
     venue = create("Venue", lambda _, m: bool(m.venue))
-    """Filter messages that contain :obj:`Venue ` objects."""
+    """Filter messages that contain :obj:`Venue` objects."""
 
     web_page = create("WebPage", lambda _, m: m.web_page)
     """Filter messages sent with a webpage preview."""
 
     poll = create("Poll", lambda _, m: m.poll)
-    """Filter messages that contain :obj:`Poll ` objects."""
+    """Filter messages that contain :obj:`Poll` objects."""
 
     private = create("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
     """Filter messages sent in private chats."""
@@ -191,35 +191,19 @@ class Filters:
     """Filter messages sent via inline bots"""
 
     service = create("Service", lambda _, m: bool(m.service))
-    """Filter service messages. A service message contains any of the following fields set
+    """Filter service messages.
     
-    - left_chat_member
-    - new_chat_title
-    - new_chat_photo
-    - delete_chat_photo
-    - group_chat_created
-    - supergroup_chat_created
-    - channel_chat_created
-    - migrate_to_chat_id
-    - migrate_from_chat_id
-    - pinned_message
-    - game_score"""
+    A service message contains any of the following fields set: *left_chat_member*,
+    *new_chat_title*, *new_chat_photo*, *delete_chat_photo*, *group_chat_created*, *supergroup_chat_created*,
+    *channel_chat_created*, *migrate_to_chat_id*, *migrate_from_chat_id*, *pinned_message*, *game_score*.
+    """
 
     media = create("Media", lambda _, m: bool(m.media))
-    """Filter media messages. A media message contains any of the following fields set
+    """Filter media messages.
     
-    - audio
-    - document
-    - photo
-    - sticker
-    - video
-    - animation
-    - voice
-    - video_note
-    - contact
-    - location
-    - venue
-    - poll"""
+    A media message contains any of the following fields set: *audio*, *document*, *photo*, *sticker*, *video*,
+    *animation*, *voice*, *video_note*, *contact*, *location*, *venue*, *poll*.
+    """
 
     @staticmethod
     def command(
@@ -230,12 +214,12 @@ class Filters:
     ):
         """Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
 
-        Args:
+        Parameters:
             commands (``str`` | ``list``):
                 The command or list of commands as string the filter should look for.
                 Examples: "start", ["start", "help", "settings"]. When a message text containing
                 a command arrives, the command itself and its arguments will be stored in the *command*
-                field of the :class:`Message `.
+                field of the :class:`Message`.
 
             prefix (``str`` | ``list``, *optional*):
                 A prefix or a list of prefixes as string the filter should look for.
@@ -275,11 +259,11 @@ class Filters:
     def regex(pattern, flags: int = 0):
         """Filter messages that match a given RegEx pattern.
 
-        Args:
+        Parameters:
             pattern (``str``):
                 The RegEx pattern as string, it will be applied to the text of a message. When a pattern matches,
                 all the `Match Objects `_
-                are stored in the *matches* field of the :class:`Message ` itself.
+                are stored in the *matches* field of the :class:`Message` itself.
 
             flags (``int``, *optional*):
                 RegEx flags.
@@ -298,7 +282,7 @@ class Filters:
         You can use `set bound methods `_ to manipulate the
         users container.
 
-        Args:
+        Parameters:
             users (``int`` | ``str`` | ``list``):
                 Pass one or more user ids/usernames to filter users.
                 For you yourself, "me" or "self" can be used as well. 
@@ -329,7 +313,7 @@ class Filters:
         You can use `set bound methods `_ to manipulate the
         chats container.
 
-        Args:
+        Parameters:
             chats (``int`` | ``str`` | ``list``):
                 Pass one or more chat ids/usernames to filter chats.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/client/handlers/callback_query_handler.py
index 88ddd5a0..feb46cb0 100644
--- a/pyrogram/client/handlers/callback_query_handler.py
+++ b/pyrogram/client/handlers/callback_query_handler.py
@@ -26,17 +26,17 @@ class CallbackQueryHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_callback_query() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a new CallbackQuery arrives. It takes *(client, callback_query)*
             as positional arguments (look at the section below for a detailed description).
 
-        filters (:obj:`Filters `):
+        filters (:obj:`Filters`):
             Pass one or more filters to allow only a subset of callback queries to be passed
             in your callback function.
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself, useful when you want to call other API methods inside the message handler.
 
         callback_query (:obj:`CallbackQuery `):
diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py
index 52177dcc..f37caaed 100644
--- a/pyrogram/client/handlers/deleted_messages_handler.py
+++ b/pyrogram/client/handlers/deleted_messages_handler.py
@@ -27,20 +27,20 @@ class DeletedMessagesHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_deleted_messages() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when one or more Messages have been deleted.
             It takes *(client, messages)* as positional arguments (look at the section below for a detailed description).
 
-        filters (:obj:`Filters `):
+        filters (:obj:`Filters`):
             Pass one or more filters to allow only a subset of messages to be passed
             in your callback function.
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself, useful when you want to call other API methods inside the message handler.
 
-        messages (:obj:`Messages `):
+        messages (:obj:`Messages`):
             The deleted messages.
     """
 
diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/client/handlers/disconnect_handler.py
index 1e88a7ee..b9e6350a 100644
--- a/pyrogram/client/handlers/disconnect_handler.py
+++ b/pyrogram/client/handlers/disconnect_handler.py
@@ -26,13 +26,13 @@ class DisconnectHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_disconnect() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a disconnection occurs. It takes *(client)*
             as positional argument (look at the section below for a detailed description).
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself. Useful, for example, when you want to change the proxy before a new connection
             is established.
     """
diff --git a/pyrogram/client/handlers/inline_query_handler.py b/pyrogram/client/handlers/inline_query_handler.py
index c64d49c8..98a25652 100644
--- a/pyrogram/client/handlers/inline_query_handler.py
+++ b/pyrogram/client/handlers/inline_query_handler.py
@@ -26,20 +26,20 @@ class InlineQueryHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_inline_query() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a new InlineQuery arrives. It takes *(client, inline_query)*
             as positional arguments (look at the section below for a detailed description).
 
-        filters (:obj:`Filters `):
+        filters (:obj:`Filters`):
             Pass one or more filters to allow only a subset of inline queries to be passed
             in your callback function.
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself, useful when you want to call other API methods inside the inline query handler.
 
-        inline_query (:obj:`InlineQuery `):
+        inline_query (:obj:`InlineQuery`):
             The received inline query.
     """
 
diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/client/handlers/message_handler.py
index 67b4587e..10fff479 100644
--- a/pyrogram/client/handlers/message_handler.py
+++ b/pyrogram/client/handlers/message_handler.py
@@ -27,20 +27,20 @@ class MessageHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_message() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a new Message arrives. It takes *(client, message)*
             as positional arguments (look at the section below for a detailed description).
 
-        filters (:obj:`Filters `):
+        filters (:obj:`Filters`):
             Pass one or more filters to allow only a subset of messages to be passed
             in your callback function.
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself, useful when you want to call other API methods inside the message handler.
 
-        message (:obj:`Message `):
+        message (:obj:`Message`):
             The received message.
     """
 
diff --git a/pyrogram/client/handlers/poll_handler.py b/pyrogram/client/handlers/poll_handler.py
index 567fcec0..9e97f2ac 100644
--- a/pyrogram/client/handlers/poll_handler.py
+++ b/pyrogram/client/handlers/poll_handler.py
@@ -27,7 +27,7 @@ class PollHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_poll() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a new poll update arrives. It takes *(client, poll)*
             as positional arguments (look at the section below for a detailed description).
diff --git a/pyrogram/client/handlers/raw_update_handler.py b/pyrogram/client/handlers/raw_update_handler.py
index 3a5dea50..f54d59b6 100644
--- a/pyrogram/client/handlers/raw_update_handler.py
+++ b/pyrogram/client/handlers/raw_update_handler.py
@@ -26,14 +26,14 @@ class RawUpdateHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_raw_update() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             A function that will be called when a new update is received from the server. It takes
             *(client, update, users, chats)* as positional arguments (look at the section below for
             a detailed description).
 
     Other Parameters:
-        client (:class:`Client `):
+        client (:class:`Client`):
             The Client itself, useful when you want to call other API methods inside the update handler.
 
         update (``Update``):
diff --git a/pyrogram/client/handlers/user_status_handler.py b/pyrogram/client/handlers/user_status_handler.py
index 856ef81d..1250cb19 100644
--- a/pyrogram/client/handlers/user_status_handler.py
+++ b/pyrogram/client/handlers/user_status_handler.py
@@ -26,20 +26,20 @@ class UserStatusHandler(Handler):
     For a nicer way to register this handler, have a look at the
     :meth:`on_user_status() ` decorator.
 
-    Args:
+    Parameters:
         callback (``callable``):
             Pass a function that will be called when a new UserStatus update arrives. It takes *(client, user_status)*
             as positional arguments (look at the section below for a detailed description).
 
-        filters (:obj:`Filters `):
+        filters (:obj:`Filters`):
             Pass one or more filters to allow only a subset of messages to be passed
             in your callback function.
 
     Other parameters:
-        client (:obj:`Client `):
+        client (:obj:`Client`):
             The Client itself, useful when you want to call other API methods inside the user status handler.
 
-        user_status (:obj:`UserStatus `):
+        user_status (:obj:`UserStatus`):
             The received UserStatus update.
     """
 
diff --git a/pyrogram/client/methods/bots/answer_callback_query.py b/pyrogram/client/methods/bots/answer_callback_query.py
index 7c8754e2..3dab25d2 100644
--- a/pyrogram/client/methods/bots/answer_callback_query.py
+++ b/pyrogram/client/methods/bots/answer_callback_query.py
@@ -29,10 +29,10 @@ class AnswerCallbackQuery(BaseClient):
         url: str = None,
         cache_time: int = 0
     ):
-        """Use this method to send answers to callback queries sent from inline keyboards.
+        """Send answers to callback queries sent from inline keyboards.
         The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
 
-        Args:
+        Parameters:
             callback_query_id (``str``):
                 Unique identifier for the query to be answered.
 
@@ -54,10 +54,10 @@ class AnswerCallbackQuery(BaseClient):
                 Telegram apps will support caching starting in version 3.14. Defaults to 0.
 
         Returns:
-            True, on success.
+            ``bool``: True, on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self.send(
             functions.messages.SetBotCallbackAnswer(
diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/client/methods/bots/answer_inline_query.py
index 88a661d0..daf8423b 100644
--- a/pyrogram/client/methods/bots/answer_inline_query.py
+++ b/pyrogram/client/methods/bots/answer_inline_query.py
@@ -34,10 +34,10 @@ class AnswerInlineQuery(BaseClient):
         switch_pm_text: str = "",
         switch_pm_parameter: str = ""
     ):
-        """Use this method to send answers to an inline query.
+        """Send answers to an inline query.
         No more than 50 results per query are allowed.
 
-        Args:
+        Parameters:
             inline_query_id (``str``):
                 Unique identifier for the answered query.
 
@@ -73,7 +73,10 @@ class AnswerInlineQuery(BaseClient):
                 where they wanted to use the bot's inline capabilities.
 
         Returns:
-            On success, True is returned.
+            ``bool``: True, on success.
+
+        Raises:
+            RPCError: In case of a Telegram RPC error.
         """
         written_results = []  # Py 3.5 doesn't support await inside comprehensions
 
diff --git a/pyrogram/client/methods/bots/get_game_high_scores.py b/pyrogram/client/methods/bots/get_game_high_scores.py
index 40e68dda..a11eaba3 100644
--- a/pyrogram/client/methods/bots/get_game_high_scores.py
+++ b/pyrogram/client/methods/bots/get_game_high_scores.py
@@ -29,10 +29,10 @@ class GetGameHighScores(BaseClient):
         user_id: Union[int, str],
         chat_id: Union[int, str],
         message_id: int = None
-    ):
-        """Use this method to get data for high score tables.
+    ) -> "pyrogram.GameHighScores":
+        """Get data for high score tables.
 
-        Args:
+        Parameters:
             user_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -49,10 +49,10 @@ class GetGameHighScores(BaseClient):
                 Required if inline_message_id is not specified.
 
         Returns:
-            On success, a :obj:`GameHighScores ` object is returned.
+            :obj:`GameHighScores`: On success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         # TODO: inline_message_id
 
diff --git a/pyrogram/client/methods/bots/get_inline_bot_results.py b/pyrogram/client/methods/bots/get_inline_bot_results.py
index c523d9a7..d5dbd9f2 100644
--- a/pyrogram/client/methods/bots/get_inline_bot_results.py
+++ b/pyrogram/client/methods/bots/get_inline_bot_results.py
@@ -32,10 +32,10 @@ class GetInlineBotResults(BaseClient):
         latitude: float = None,
         longitude: float = None
     ):
-        """Use this method to get bot results via inline queries.
+        """Get bot results via inline queries.
         You can then send a result using :obj:`send_inline_bot_result `
 
-        Args:
+        Parameters:
             bot (``int`` | ``str``):
                 Unique identifier of the inline bot you want to get results from. You can specify
                 a @username (str) or a bot ID (int).
@@ -55,11 +55,11 @@ class GetInlineBotResults(BaseClient):
                 Useful for location-based results only.
 
         Returns:
-            On Success, :obj:`BotResults ` is returned.
+            :obj:`BotResults `: On Success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``TimeoutError`` if the bot fails to answer within 10 seconds
+            RPCError: In case of a Telegram RPC error.
+            TimeoutError: In case the bot fails to answer within 10 seconds.
         """
         # TODO: Don't return the raw type
 
diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/client/methods/bots/request_callback_answer.py
index 6afe8551..86855a92 100644
--- a/pyrogram/client/methods/bots/request_callback_answer.py
+++ b/pyrogram/client/methods/bots/request_callback_answer.py
@@ -27,12 +27,13 @@ class RequestCallbackAnswer(BaseClient):
         self,
         chat_id: Union[int, str],
         message_id: int,
-        callback_data: bytes
+        callback_data: Union[str, bytes],
+        timeout: int = 10
     ):
-        """Use this method to request a callback answer from bots.
+        """Request a callback answer from bots.
         This is the equivalent of clicking an inline button containing callback data.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -41,23 +42,30 @@ class RequestCallbackAnswer(BaseClient):
             message_id (``int``):
                 The message id the inline keyboard is attached on.
 
-            callback_data (``bytes``):
+            callback_data (``str`` | ``bytes``):
                 Callback data associated with the inline button you want to get the answer from.
 
+            timeout (``int``, *optional*):
+                Timeout in seconds.
+
         Returns:
             The answer containing info useful for clients to display a notification at the top of the chat screen
             or as an alert.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``TimeoutError`` if the bot fails to answer within 10 seconds.
+            RPCError: In case of a Telegram RPC error.
+            TimeoutError: In case the bot fails to answer within 10 seconds.
         """
+
+        # Telegram only wants bytes, but we are allowed to pass strings too.
+        data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data
+
         return await self.send(
             functions.messages.GetBotCallbackAnswer(
-                peer=self.resolve_peer(chat_id),
+                peer=await self.resolve_peer(chat_id),
                 msg_id=message_id,
-                data=callback_data
+                data=data
             ),
             retries=0,
-            timeout=10
+            timeout=timeout
         )
diff --git a/pyrogram/client/methods/bots/send_game.py b/pyrogram/client/methods/bots/send_game.py
index 91ce1402..f579630d 100644
--- a/pyrogram/client/methods/bots/send_game.py
+++ b/pyrogram/client/methods/bots/send_game.py
@@ -37,9 +37,9 @@ class SendGame(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send a game.
+        """Send a game.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -60,10 +60,10 @@ class SendGame(BaseClient):
                 If not empty, the first button must launch the game.
 
         Returns:
-            On success, the sent :obj:`Message` is returned.
+            :obj:`Message`: On success, the sent game message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SendMedia(
diff --git a/pyrogram/client/methods/bots/send_inline_bot_result.py b/pyrogram/client/methods/bots/send_inline_bot_result.py
index a881e8c7..64f90529 100644
--- a/pyrogram/client/methods/bots/send_inline_bot_result.py
+++ b/pyrogram/client/methods/bots/send_inline_bot_result.py
@@ -32,10 +32,10 @@ class SendInlineBotResult(BaseClient):
         reply_to_message_id: int = None,
         hide_via: bool = None
     ):
-        """Use this method to send an inline bot result.
+        """Send an inline bot result.
         Bot results can be retrieved using :obj:`get_inline_bot_results `
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -58,10 +58,10 @@ class SendInlineBotResult(BaseClient):
                 Sends the message with *via @bot* hidden.
 
         Returns:
-            On success, the sent Message is returned.
+            :obj:`Message`: On success, the sent inline result message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self.send(
             functions.messages.SendInlineBotResult(
diff --git a/pyrogram/client/methods/bots/set_game_score.py b/pyrogram/client/methods/bots/set_game_score.py
index 5c871b4b..757eba3f 100644
--- a/pyrogram/client/methods/bots/set_game_score.py
+++ b/pyrogram/client/methods/bots/set_game_score.py
@@ -32,11 +32,11 @@ class SetGameScore(BaseClient):
         disable_edit_message: bool = None,
         chat_id: Union[int, str] = None,
         message_id: int = None
-    ):
+    ) -> Union["pyrogram.Message", bool]:
         # inline_message_id: str = None):  TODO Add inline_message_id
-        """Use this method to set the score of the specified user in a game.
+        """Set the score of the specified user in a game.
 
-        Args:
+        Parameters:
             user_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -63,12 +63,11 @@ class SetGameScore(BaseClient):
                 Required if inline_message_id is not specified.
 
         Returns:
-            On success, if the message was sent by the bot, returns the edited :obj:`Message `,
-            otherwise returns True.
+            :obj:`Message` | ``bool``: On success, if the message was sent by the bot, the edited message is returned,
+            True otherwise.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            :class:`BotScoreNotModified` if the new score is not greater than the user's current score in the chat and force is False.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SetGameScore(
diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/client/methods/chats/__init__.py
index 8db44abe..698255f5 100644
--- a/pyrogram/client/methods/chats/__init__.py
+++ b/pyrogram/client/methods/chats/__init__.py
@@ -22,7 +22,6 @@ from .get_chat import GetChat
 from .get_chat_member import GetChatMember
 from .get_chat_members import GetChatMembers
 from .get_chat_members_count import GetChatMembersCount
-from .get_chat_preview import GetChatPreview
 from .get_dialogs import GetDialogs
 from .iter_chat_members import IterChatMembers
 from .iter_dialogs import IterDialogs
@@ -61,7 +60,6 @@ class Chats(
     UnpinChatMessage,
     GetDialogs,
     GetChatMembersCount,
-    GetChatPreview,
     IterDialogs,
     IterChatMembers,
     UpdateChatUsername,
diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/client/methods/chats/delete_chat_photo.py
index 1407f7e7..49f8e5fa 100644
--- a/pyrogram/client/methods/chats/delete_chat_photo.py
+++ b/pyrogram/client/methods/chats/delete_chat_photo.py
@@ -27,7 +27,7 @@ class DeleteChatPhoto(BaseClient):
         self,
         chat_id: Union[int, str]
     ) -> bool:
-        """Use this method to delete a chat photo.
+        """Delete a chat photo.
         Photos can't be changed for private chats.
         You must be an administrator in the chat for this to work and must have the appropriate admin rights.
 
@@ -35,15 +35,15 @@ class DeleteChatPhoto(BaseClient):
             In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
             setting is off.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
             ``ValueError`` if a chat_id belongs to user.
         """
         peer = await self.resolve_peer(chat_id)
diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/client/methods/chats/export_chat_invite_link.py
index 2744658e..1e533097 100644
--- a/pyrogram/client/methods/chats/export_chat_invite_link.py
+++ b/pyrogram/client/methods/chats/export_chat_invite_link.py
@@ -27,7 +27,7 @@ class ExportChatInviteLink(BaseClient):
         self,
         chat_id: Union[int, str]
     ) -> str:
-        """Use this method to generate a new invite link for a chat; any previously generated link is revoked.
+        """Generate a new invite link for a chat; any previously generated link is revoked.
 
         You must be an administrator in the chat for this to work and have the appropriate admin rights.
 
@@ -38,16 +38,16 @@ class ExportChatInviteLink(BaseClient):
             using this method – after this the link will become available to the bot via the :meth:`get_chat` method.
             If your bot needs to generate a new invite link replacing its previous one, use this method again.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier for the target chat or username of the target channel/supergroup
                 (in the format @username).
 
         Returns:
-            On success, the exported invite link as string is returned.
+            ``str``: On success, the exported invite link is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         peer = await self.resolve_peer(chat_id)
 
diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/client/methods/chats/get_chat.py
index dfc1dbbb..37a7ba13 100644
--- a/pyrogram/client/methods/chats/get_chat.py
+++ b/pyrogram/client/methods/chats/get_chat.py
@@ -27,37 +27,37 @@ class GetChat(BaseClient):
     async def get_chat(
         self,
         chat_id: Union[int, str]
-    ) -> "pyrogram.Chat":
-        """Use this method to get up to date information about the chat.
+    ) -> Union["pyrogram.Chat", "pyrogram.ChatPreview"]:
+        """Get up to date information about a chat.
+
         Information include current name of the user for one-on-one conversations, current username of a user, group or
         channel, etc.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 Unique identifier for the target chat in form of a *t.me/joinchat/* link, identifier (int) or username
                 of the target channel/supergroup (in the format @username).
 
         Returns:
-            On success, a :obj:`Chat ` object is returned.
+            :obj:`Chat` | :obj:`ChatPreview`: On success, if you've already joined the chat, a chat object is returned,
+            otherwise, a chat preview object is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` in case the chat invite link refers to a chat you haven't joined yet.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case the chat invite link points to a chat you haven't joined yet.
         """
         match = self.INVITE_LINK_RE.match(str(chat_id))
 
         if match:
-            h = match.group(1)
-
             r = await self.send(
                 functions.messages.CheckChatInvite(
-                    hash=h
+                    hash=match.group(1)
                 )
             )
 
             if isinstance(r, types.ChatInvite):
-                raise ValueError("You haven't joined \"t.me/joinchat/{}\" yet".format(h))
+                return pyrogram.ChatPreview._parse(self, r)
 
             self.fetch_peers([r.chat])
 
diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/client/methods/chats/get_chat_member.py
index 584f67a0..e0dfc67d 100644
--- a/pyrogram/client/methods/chats/get_chat_member.py
+++ b/pyrogram/client/methods/chats/get_chat_member.py
@@ -30,9 +30,9 @@ class GetChatMember(BaseClient):
         chat_id: Union[int, str],
         user_id: Union[int, str]
     ) -> "pyrogram.ChatMember":
-        """Use this method to get information about one member of a chat.
+        """Get information about one member of a chat.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -42,10 +42,10 @@ class GetChatMember(BaseClient):
                 For a contact that exists in your Telegram address book you can use his phone number (str).
 
         Returns:
-            On success, a :obj:`ChatMember ` object is returned.
+            :obj:`ChatMember`: On success, a chat member is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         chat_id = await self.resolve_peer(chat_id)
         user_id = await self.resolve_peer(user_id)
diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/client/methods/chats/get_chat_members.py
index 494ea472..28877b6d 100644
--- a/pyrogram/client/methods/chats/get_chat_members.py
+++ b/pyrogram/client/methods/chats/get_chat_members.py
@@ -46,14 +46,14 @@ class GetChatMembers(BaseClient):
         query: str = "",
         filter: str = Filters.ALL
     ) -> "pyrogram.ChatMembers":
-        """Use this method to get a chunk of the members list of a chat.
+        """Get a chunk of the members list of a chat.
 
         You can get up to 200 chat members at once.
         A chat can be either a basic group, a supergroup or a channel.
         You must be admin to retrieve the members list of a channel (also known as "subscribers").
         For a more convenient way of getting chat members see :meth:`iter_chat_members`.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -86,11 +86,11 @@ class GetChatMembers(BaseClient):
         .. [2] A query string is applicable only for *"all"*, *"kicked"* and *"restricted"* filters only.
 
         Returns:
-            On success, a :obj:`ChatMembers` object is returned.
+            :obj:`ChatMembers`: On success, an object containing a list of chat members is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if you used an invalid filter or a chat_id that belongs to a user.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case you used an invalid filter or a chat id that belongs to a user.
         """
         peer = await self.resolve_peer(chat_id)
 
diff --git a/pyrogram/client/methods/chats/get_chat_members_count.py b/pyrogram/client/methods/chats/get_chat_members_count.py
index ff01d359..118ff072 100644
--- a/pyrogram/client/methods/chats/get_chat_members_count.py
+++ b/pyrogram/client/methods/chats/get_chat_members_count.py
@@ -27,18 +27,18 @@ class GetChatMembersCount(BaseClient):
         self,
         chat_id: Union[int, str]
     ) -> int:
-        """Use this method to get the number of members in a chat.
+        """Get the number of members in a chat.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
         Returns:
-            On success, an integer is returned.
+            ``int``: On success, the chat members count is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if a chat_id belongs to user.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case a chat id belongs to user.
         """
         peer = await self.resolve_peer(chat_id)
 
diff --git a/pyrogram/client/methods/chats/get_chat_preview.py b/pyrogram/client/methods/chats/get_chat_preview.py
deleted file mode 100644
index 9b6c6955..00000000
--- a/pyrogram/client/methods/chats/get_chat_preview.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Pyrogram - Telegram MTProto API Client Library for Python
-# Copyright (C) 2017-2019 Dan Tès 
-#
-# This file is part of Pyrogram.
-#
-# Pyrogram is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pyrogram is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with Pyrogram.  If not, see .
-
-import pyrogram
-from pyrogram.api import functions, types
-from ...ext import BaseClient
-
-
-class GetChatPreview(BaseClient):
-    def get_chat_preview(
-        self,
-        invite_link: str
-    ):
-        """Use this method to get the preview of a chat using the invite link.
-
-        This method only returns a chat preview, if you want to join a chat use :meth:`join_chat`
-
-        Args:
-            invite_link (``str``):
-                Unique identifier for the target chat in form of *t.me/joinchat/* links.
-
-        Returns:
-            Either :obj:`Chat` or :obj:`ChatPreview`, depending on whether you already joined the chat or not.
-
-        Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` in case of an invalid invite_link.
-        """
-        match = self.INVITE_LINK_RE.match(invite_link)
-
-        if match:
-            r = self.send(
-                functions.messages.CheckChatInvite(
-                    hash=match.group(1)
-                )
-            )
-
-            if isinstance(r, types.ChatInvite):
-                return pyrogram.ChatPreview._parse(self, r)
-
-            if isinstance(r, types.ChatInviteAlready):
-                chat = r.chat
-
-                if isinstance(chat, types.Chat):
-                    return pyrogram.Chat._parse_chat_chat(self, chat)
-
-                if isinstance(chat, types.Channel):
-                    return pyrogram.Chat._parse_channel_chat(self, chat)
-        else:
-            raise ValueError("The invite_link is invalid")
diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/client/methods/chats/get_dialogs.py
index ef405f71..cf522dc0 100644
--- a/pyrogram/client/methods/chats/get_dialogs.py
+++ b/pyrogram/client/methods/chats/get_dialogs.py
@@ -34,12 +34,12 @@ class GetDialogs(BaseClient):
         limit: int = 100,
         pinned_only: bool = False
     ) -> "pyrogram.Dialogs":
-        """Use this method to get a chunk of the user's dialogs.
+        """Get a chunk of the user's dialogs.
 
         You can get up to 100 dialogs at once.
         For a more convenient way of getting a user's dialogs see :meth:`iter_dialogs`.
 
-        Args:
+        Parameters:
             offset_date (``int``):
                 The offset date in Unix time taken from the top message of a :obj:`Dialog`.
                 Defaults to 0. Valid for non-pinned dialogs only.
@@ -53,10 +53,10 @@ class GetDialogs(BaseClient):
                 Defaults to False.
 
         Returns:
-            On success, a :obj:`Dialogs` object is returned.
+            :obj:`Dialogs`: On success, an object containing a list of dialogs is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         while True:
diff --git a/pyrogram/client/methods/chats/get_dialogs_count.py b/pyrogram/client/methods/chats/get_dialogs_count.py
index 49e6eff3..5142211e 100644
--- a/pyrogram/client/methods/chats/get_dialogs_count.py
+++ b/pyrogram/client/methods/chats/get_dialogs_count.py
@@ -22,17 +22,17 @@ from ...ext import BaseClient
 
 class GetDialogsCount(BaseClient):
     async def get_dialogs_count(self, pinned_only: bool = False) -> int:
-        """Use this method to get the total count of your dialogs.
+        """Get the total count of your dialogs.
 
         pinned_only (``bool``, *optional*):
             Pass True if you want to count only pinned dialogs.
             Defaults to False.
 
         Returns:
-            On success, an integer is returned.
+            ``int``: On success, the dialogs count is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         if pinned_only:
diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/client/methods/chats/iter_chat_members.py
index 7a935cbd..79f5e8c3 100644
--- a/pyrogram/client/methods/chats/iter_chat_members.py
+++ b/pyrogram/client/methods/chats/iter_chat_members.py
@@ -48,13 +48,13 @@ class IterChatMembers(BaseClient):
         query: str = "",
         filter: str = Filters.ALL
     ) -> Optional[AsyncGenerator["pyrogram.ChatMember", None]]:
-        """Use this method to iterate through the members of a chat sequentially.
+        """Iterate through the members of a chat sequentially.
 
         This convenience method does the same as repeatedly calling :meth:`get_chat_members` in a loop, thus saving you
         from the hassle of setting up boilerplate code. It is useful for getting the whole members list of a chat with
         a single call.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -78,10 +78,10 @@ class IterChatMembers(BaseClient):
                 Defaults to *"all"*.
 
         Returns:
-            A generator yielding :obj:`ChatMember ` objects.
+            ``Generator``: A generator yielding :obj:`ChatMember` objects.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         current = 0
         yielded = set()
diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/client/methods/chats/iter_dialogs.py
index dfc7543e..e916bd47 100644
--- a/pyrogram/client/methods/chats/iter_dialogs.py
+++ b/pyrogram/client/methods/chats/iter_dialogs.py
@@ -31,12 +31,12 @@ class IterDialogs(BaseClient):
         limit: int = 0,
         offset_date: int = 0
     ) -> Optional[AsyncGenerator["pyrogram.Dialog", None]]:
-        """Use this method to iterate through a user's dialogs sequentially.
+        """Iterate through a user's dialogs sequentially.
 
         This convenience method does the same as repeatedly calling :meth:`get_dialogs` in a loop, thus saving you from
         the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a single call.
 
-        Args:
+        Parameters:
             limit (``str``, *optional*):
                 Limits the number of dialogs to be retrieved.
                 By default, no limit is applied and all dialogs are returned.
@@ -46,10 +46,10 @@ class IterDialogs(BaseClient):
                 Defaults to 0 (most recent dialog).
 
         Returns:
-            A generator yielding :obj:`Dialog ` objects.
+            ``Generator``: A generator yielding :obj:`Dialog` objects.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         current = 0
         total = limit or (1 << 31) - 1
diff --git a/pyrogram/client/methods/chats/join_chat.py b/pyrogram/client/methods/chats/join_chat.py
index ce506e74..8e38d4ff 100644
--- a/pyrogram/client/methods/chats/join_chat.py
+++ b/pyrogram/client/methods/chats/join_chat.py
@@ -26,18 +26,18 @@ class JoinChat(BaseClient):
         self,
         chat_id: str
     ):
-        """Use this method to join a group chat or channel.
+        """Join a group chat or channel.
 
-        Args:
+        Parameters:
             chat_id (``str``):
                 Unique identifier for the target chat in form of a *t.me/joinchat/* link or username of the target
                 channel/supergroup (in the format @username).
 
         Returns:
-            On success, a :obj:`Chat ` object is returned.
+            :obj:`Chat`: On success, a chat object is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         match = self.INVITE_LINK_RE.match(chat_id)
 
diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/client/methods/chats/kick_chat_member.py
index b59ea097..72a8b5d0 100644
--- a/pyrogram/client/methods/chats/kick_chat_member.py
+++ b/pyrogram/client/methods/chats/kick_chat_member.py
@@ -30,7 +30,7 @@ class KickChatMember(BaseClient):
         user_id: Union[int, str],
         until_date: int = 0
     ) -> Union["pyrogram.Message", bool]:
-        """Use this method to kick a user from a group, a supergroup or a channel.
+        """Kick a user from a group, a supergroup or a channel.
         In the case of supergroups and channels, the user will not be able to return to the group on their own using
         invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must
         have the appropriate admin rights.
@@ -40,7 +40,7 @@ class KickChatMember(BaseClient):
             off in the target group. Otherwise members may only be removed by the group's creator or by the member
             that added them.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -54,10 +54,11 @@ class KickChatMember(BaseClient):
                 considered to be banned forever. Defaults to 0 (ban forever).
 
         Returns:
-            On success, either True or a service :obj:`Message ` will be returned (when applicable).
+            :obj:`Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in
+            case a message object couldn't be returned, True is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         chat_peer = await self.resolve_peer(chat_id)
         user_peer = await self.resolve_peer(user_id)
diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/client/methods/chats/leave_chat.py
index aa2aa22e..e2b5cb4b 100644
--- a/pyrogram/client/methods/chats/leave_chat.py
+++ b/pyrogram/client/methods/chats/leave_chat.py
@@ -28,9 +28,9 @@ class LeaveChat(BaseClient):
         chat_id: Union[int, str],
         delete: bool = False
     ):
-        """Use this method to leave a group chat or channel.
+        """Leave a group chat or channel.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier for the target chat or username of the target channel/supergroup
                 (in the format @username).
@@ -39,7 +39,7 @@ class LeaveChat(BaseClient):
                 Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         peer = await self.resolve_peer(chat_id)
 
diff --git a/pyrogram/client/methods/chats/pin_chat_message.py b/pyrogram/client/methods/chats/pin_chat_message.py
index a0d0b831..6023f459 100644
--- a/pyrogram/client/methods/chats/pin_chat_message.py
+++ b/pyrogram/client/methods/chats/pin_chat_message.py
@@ -29,11 +29,11 @@ class PinChatMessage(BaseClient):
         message_id: int,
         disable_notification: bool = None
     ) -> bool:
-        """Use this method to pin a message in a group, channel or your own chat.
+        """Pin a message in a group, channel or your own chat.
         You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin right in
         the supergroup or "can_edit_messages" admin right in the channel.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -45,10 +45,10 @@ class PinChatMessage(BaseClient):
                 message. Notifications are always disabled in channels.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         await self.send(
             functions.messages.UpdatePinnedMessage(
diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/client/methods/chats/promote_chat_member.py
index 232bc62b..c7db62a5 100644
--- a/pyrogram/client/methods/chats/promote_chat_member.py
+++ b/pyrogram/client/methods/chats/promote_chat_member.py
@@ -36,12 +36,12 @@ class PromoteChatMember(BaseClient):
         can_pin_messages: bool = False,
         can_promote_members: bool = False
     ) -> bool:
-        """Use this method to promote or demote a user in a supergroup or a channel.
+        """Promote or demote a user in a supergroup or a channel.
 
         You must be an administrator in the chat for this to work and must have the appropriate admin rights.
         Pass False for all boolean parameters to demote a user.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -76,10 +76,10 @@ class PromoteChatMember(BaseClient):
                 were appointed by him).
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         await self.send(
             functions.channels.EditAdmin(
diff --git a/pyrogram/client/methods/chats/restrict_chat.py b/pyrogram/client/methods/chats/restrict_chat.py
index 40d46d34..8e63a9b2 100644
--- a/pyrogram/client/methods/chats/restrict_chat.py
+++ b/pyrogram/client/methods/chats/restrict_chat.py
@@ -36,10 +36,10 @@ class RestrictChat(BaseClient):
         can_invite_users: bool = False,
         can_pin_messages: bool = False
     ) -> Chat:
-        """Use this method to restrict a chat.
+        """Restrict a chat.
         Pass True for all boolean parameters to lift restrictions from a chat.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -70,10 +70,10 @@ class RestrictChat(BaseClient):
                 Pass True, if the user can pin messages.
 
         Returns:
-            On success, a :obj:`Chat ` object is returned.
+            :obj:`Chat`: On success, a chat object is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         send_messages = True
         send_media = True
diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/client/methods/chats/restrict_chat_member.py
index 6ed4fd68..54d12ecf 100644
--- a/pyrogram/client/methods/chats/restrict_chat_member.py
+++ b/pyrogram/client/methods/chats/restrict_chat_member.py
@@ -38,12 +38,12 @@ class RestrictChatMember(BaseClient):
         can_invite_users: bool = False,
         can_pin_messages: bool = False
     ) -> Chat:
-        """Use this method to restrict a user in a supergroup.
+        """Restrict a user in a supergroup.
 
         The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights.
         Pass True for all boolean parameters to lift restrictions from a user.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -83,10 +83,10 @@ class RestrictChatMember(BaseClient):
                 Pass True, if the user can pin messages.
 
         Returns:
-            On success, a :obj:`Chat ` object is returned.
+            :obj:`Chat`: On success, a chat object is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         send_messages = True
         send_media = True
diff --git a/pyrogram/client/methods/chats/set_chat_description.py b/pyrogram/client/methods/chats/set_chat_description.py
index 4c3a13ec..aedc3805 100644
--- a/pyrogram/client/methods/chats/set_chat_description.py
+++ b/pyrogram/client/methods/chats/set_chat_description.py
@@ -28,10 +28,10 @@ class SetChatDescription(BaseClient):
         chat_id: Union[int, str],
         description: str
     ) -> bool:
-        """Use this method to change the description of a supergroup or a channel.
+        """Change the description of a supergroup or a channel.
         You must be an administrator in the chat for this to work and must have the appropriate admin rights.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -39,10 +39,10 @@ class SetChatDescription(BaseClient):
                 New chat description, 0-255 characters.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
             ``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
         """
         peer = await self.resolve_peer(chat_id)
diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/client/methods/chats/set_chat_photo.py
index f76c313b..4d2b175a 100644
--- a/pyrogram/client/methods/chats/set_chat_photo.py
+++ b/pyrogram/client/methods/chats/set_chat_photo.py
@@ -31,7 +31,7 @@ class SetChatPhoto(BaseClient):
         chat_id: Union[int, str],
         photo: str
     ) -> bool:
-        """Use this method to set a new profile photo for the chat.
+        """Set a new profile photo for the chat.
         Photos can't be changed for private chats.
         You must be an administrator in the chat for this to work and must have the appropriate admin rights.
 
@@ -39,7 +39,7 @@ class SetChatPhoto(BaseClient):
             In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
             setting is off.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -47,10 +47,10 @@ class SetChatPhoto(BaseClient):
                 New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
             ``ValueError`` if a chat_id belongs to user.
         """
         peer = await self.resolve_peer(chat_id)
diff --git a/pyrogram/client/methods/chats/set_chat_title.py b/pyrogram/client/methods/chats/set_chat_title.py
index f6453b27..cb6664d1 100644
--- a/pyrogram/client/methods/chats/set_chat_title.py
+++ b/pyrogram/client/methods/chats/set_chat_title.py
@@ -28,7 +28,7 @@ class SetChatTitle(BaseClient):
         chat_id: Union[int, str],
         title: str
     ) -> bool:
-        """Use this method to change the title of a chat.
+        """Change the title of a chat.
         Titles can't be changed for private chats.
         You must be an administrator in the chat for this to work and must have the appropriate admin rights.
 
@@ -36,7 +36,7 @@ class SetChatTitle(BaseClient):
             In regular groups (non-supergroups), this method will only work if the "All Members Are Admins"
             setting is off.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -44,11 +44,11 @@ class SetChatTitle(BaseClient):
                 New chat title, 1-255 characters.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if a chat_id belongs to user.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case a chat id belongs to user.
         """
         peer = await self.resolve_peer(chat_id)
 
diff --git a/pyrogram/client/methods/chats/unban_chat_member.py b/pyrogram/client/methods/chats/unban_chat_member.py
index beeb8163..20af0a85 100644
--- a/pyrogram/client/methods/chats/unban_chat_member.py
+++ b/pyrogram/client/methods/chats/unban_chat_member.py
@@ -28,11 +28,11 @@ class UnbanChatMember(BaseClient):
         chat_id: Union[int, str],
         user_id: Union[int, str]
     ) -> bool:
-        """Use this method to unban a previously kicked user in a supergroup or channel.
+        """Unban a previously kicked user in a supergroup or channel.
         The user will **not** return to the group or channel automatically, but will be able to join via link, etc.
         You must be an administrator for this to work.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
@@ -41,10 +41,10 @@ class UnbanChatMember(BaseClient):
                 For a contact that exists in your Telegram address book you can use his phone number (str).
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         await self.send(
             functions.channels.EditBanned(
diff --git a/pyrogram/client/methods/chats/unpin_chat_message.py b/pyrogram/client/methods/chats/unpin_chat_message.py
index 757f1591..66e03ac1 100644
--- a/pyrogram/client/methods/chats/unpin_chat_message.py
+++ b/pyrogram/client/methods/chats/unpin_chat_message.py
@@ -27,19 +27,19 @@ class UnpinChatMessage(BaseClient):
         self,
         chat_id: Union[int, str]
     ) -> bool:
-        """Use this method to unpin a message in a group, channel or your own chat.
+        """Unpin a message in a group, channel or your own chat.
         You must be an administrator in the chat for this to work and must have the "can_pin_messages" admin
         right in the supergroup or "can_edit_messages" admin right in the channel.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         await self.send(
             functions.messages.UpdatePinnedMessage(
diff --git a/pyrogram/client/methods/chats/update_chat_username.py b/pyrogram/client/methods/chats/update_chat_username.py
index 12f5fe12..d5cdfac4 100644
--- a/pyrogram/client/methods/chats/update_chat_username.py
+++ b/pyrogram/client/methods/chats/update_chat_username.py
@@ -28,22 +28,22 @@ class UpdateChatUsername(BaseClient):
         chat_id: Union[int, str],
         username: Union[str, None]
     ) -> bool:
-        """Use this method to update a channel or a supergroup username.
+        """Update a channel or a supergroup username.
         
         To update your own username (for users only, not bots) you can use :meth:`update_username`.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``)
                 Unique identifier (int) or username (str) of the target chat.
             username (``str`` | ``None``):
                 Username to set. Pass "" (empty string) or None to remove the username.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if a chat_id belongs to a user or chat.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case a chat id belongs to a user or chat.
         """
 
         peer = await self.resolve_peer(chat_id)
diff --git a/pyrogram/client/methods/contacts/add_contacts.py b/pyrogram/client/methods/contacts/add_contacts.py
index 9ba2308c..fa3a5367 100644
--- a/pyrogram/client/methods/contacts/add_contacts.py
+++ b/pyrogram/client/methods/contacts/add_contacts.py
@@ -28,17 +28,14 @@ class AddContacts(BaseClient):
         self,
         contacts: List["pyrogram.InputPhoneContact"]
     ):
-        """Use this method to add contacts to your Telegram address book.
+        """Add contacts to your Telegram address book.
 
-        Args:
-            contacts (List of :obj:`InputPhoneContact `):
+        Parameters:
+            contacts (List of :obj:`InputPhoneContact`):
                 The contact list to be added
 
-        Returns:
-            On success, the added contacts are returned.
-
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         imported_contacts = await self.send(
             functions.contacts.ImportContacts(
diff --git a/pyrogram/client/methods/contacts/delete_contacts.py b/pyrogram/client/methods/contacts/delete_contacts.py
index 1c1e0dac..57850648 100644
--- a/pyrogram/client/methods/contacts/delete_contacts.py
+++ b/pyrogram/client/methods/contacts/delete_contacts.py
@@ -28,18 +28,18 @@ class DeleteContacts(BaseClient):
         self,
         ids: List[int]
     ):
-        """Use this method to delete contacts from your Telegram address book.
+        """Delete contacts from your Telegram address book.
 
-        Args:
+        Parameters:
             ids (List of ``int``):
                 A list of unique identifiers for the target users.
                 Can be an ID (int), a username (string) or phone number (string).
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         contacts = []
 
diff --git a/pyrogram/client/methods/contacts/get_contacts.py b/pyrogram/client/methods/contacts/get_contacts.py
index 5e9bff44..329b1a89 100644
--- a/pyrogram/client/methods/contacts/get_contacts.py
+++ b/pyrogram/client/methods/contacts/get_contacts.py
@@ -18,6 +18,7 @@
 
 import asyncio
 import logging
+from typing import List
 
 import pyrogram
 from pyrogram.api import functions
@@ -28,14 +29,15 @@ log = logging.getLogger(__name__)
 
 
 class GetContacts(BaseClient):
-    async def get_contacts(self):
-        """Use this method to get contacts from your Telegram address book.
+    async def get_contacts(self) -> List["pyrogram.User"]:
+        # TODO: Create a Users object and return that
+        """Get contacts from your Telegram address book.
 
         Returns:
-            On success, a list of :obj:`User` objects is returned.
+            List of :obj:`User`: On success, a list of users is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         while True:
             try:
diff --git a/pyrogram/client/methods/contacts/get_contacts_count.py b/pyrogram/client/methods/contacts/get_contacts_count.py
index f2b6fda0..45a7eb77 100644
--- a/pyrogram/client/methods/contacts/get_contacts_count.py
+++ b/pyrogram/client/methods/contacts/get_contacts_count.py
@@ -22,13 +22,13 @@ from ...ext import BaseClient
 
 class GetContactsCount(BaseClient):
     async def get_contacts_count(self) -> int:
-        """Use this method to get the total count of contacts from your Telegram address book.
+        """Get the total count of contacts from your Telegram address book.
 
         Returns:
-            On success, an integer is returned.
+            ``int``: On success, the contacts count is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         return len((await self.send(functions.contacts.GetContacts(hash=0))).contacts)
diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/client/methods/decorators/on_callback_query.py
index 3c747c5f..b76655fb 100644
--- a/pyrogram/client/methods/decorators/on_callback_query.py
+++ b/pyrogram/client/methods/decorators/on_callback_query.py
@@ -30,11 +30,12 @@ class OnCallbackQuery(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling callback queries.
+        """Decorator for handling callback queries.
+
         This does the same thing as :meth:`add_handler` using the :class:`CallbackQueryHandler`.
 
-        Args:
-            filters (:obj:`Filters `):
+        Parameters:
+            filters (:obj:`Filters`):
                 Pass one or more filters to allow only a subset of callback queries to be passed
                 in your function.
 
diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py
index cf8f9cf2..7637e6eb 100644
--- a/pyrogram/client/methods/decorators/on_deleted_messages.py
+++ b/pyrogram/client/methods/decorators/on_deleted_messages.py
@@ -30,11 +30,12 @@ class OnDeletedMessages(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling deleted messages.
+        """Decorator for handling deleted messages.
+
         This does the same thing as :meth:`add_handler` using the :class:`DeletedMessagesHandler`.
 
-        Args:
-            filters (:obj:`Filters `):
+        Parameters:
+            filters (:obj:`Filters`):
                 Pass one or more filters to allow only a subset of messages to be passed
                 in your function.
 
diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/client/methods/decorators/on_disconnect.py
index 515a28c1..9305808e 100644
--- a/pyrogram/client/methods/decorators/on_disconnect.py
+++ b/pyrogram/client/methods/decorators/on_disconnect.py
@@ -23,7 +23,8 @@ from ...ext import BaseClient
 
 class OnDisconnect(BaseClient):
     def on_disconnect(self=None) -> callable:
-        """Use this decorator to automatically register a function for handling disconnections.
+        """Decorator for handling disconnections.
+
         This does the same thing as :meth:`add_handler` using the :class:`DisconnectHandler`.
         """
 
diff --git a/pyrogram/client/methods/decorators/on_inline_query.py b/pyrogram/client/methods/decorators/on_inline_query.py
index 81f0f676..58837398 100644
--- a/pyrogram/client/methods/decorators/on_inline_query.py
+++ b/pyrogram/client/methods/decorators/on_inline_query.py
@@ -30,10 +30,11 @@ class OnInlineQuery(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling inline queries.
+        """Decorator for handling inline queries.
+
         This does the same thing as :meth:`add_handler` using the :class:`InlineQueryHandler`.
 
-        Args:
+        Parameters:
             filters (:obj:`Filters `):
                 Pass one or more filters to allow only a subset of inline queries to be passed
                 in your function.
diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/client/methods/decorators/on_message.py
index e6563893..f590fd12 100644
--- a/pyrogram/client/methods/decorators/on_message.py
+++ b/pyrogram/client/methods/decorators/on_message.py
@@ -30,11 +30,12 @@ class OnMessage(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling messages.
+        """Decorator for handling messages.
+
         This does the same thing as :meth:`add_handler` using the :class:`MessageHandler`.
 
-        Args:
-            filters (:obj:`Filters `):
+        Parameters:
+            filters (:obj:`Filters`):
                 Pass one or more filters to allow only a subset of messages to be passed
                 in your function.
 
diff --git a/pyrogram/client/methods/decorators/on_poll.py b/pyrogram/client/methods/decorators/on_poll.py
index 56dcd757..de1c1d3d 100644
--- a/pyrogram/client/methods/decorators/on_poll.py
+++ b/pyrogram/client/methods/decorators/on_poll.py
@@ -30,10 +30,11 @@ class OnPoll(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling poll updates.
+        """Decorator for handling poll updates.
+
         This does the same thing as :meth:`add_handler` using the :class:`PollHandler`.
 
-        Args:
+        Parameters:
             filters (:obj:`Filters `):
                 Pass one or more filters to allow only a subset of polls to be passed
                 in your function.
diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/client/methods/decorators/on_raw_update.py
index 1494a319..53a0f4cf 100644
--- a/pyrogram/client/methods/decorators/on_raw_update.py
+++ b/pyrogram/client/methods/decorators/on_raw_update.py
@@ -28,10 +28,11 @@ class OnRawUpdate(BaseClient):
         self=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling raw updates.
+        """Decorator for handling raw updates.
+
         This does the same thing as :meth:`add_handler` using the :class:`RawUpdateHandler`.
 
-        Args:
+        Parameters:
             group (``int``, *optional*):
                 The group identifier, defaults to 0.
         """
diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/client/methods/decorators/on_user_status.py
index 4d8185b1..e7db7b74 100644
--- a/pyrogram/client/methods/decorators/on_user_status.py
+++ b/pyrogram/client/methods/decorators/on_user_status.py
@@ -30,11 +30,11 @@ class OnUserStatus(BaseClient):
         filters=None,
         group: int = 0
     ) -> callable:
-        """Use this decorator to automatically register a function for handling user status updates.
+        """Decorator for handling user status updates.
         This does the same thing as :meth:`add_handler` using the :class:`UserStatusHandler`.
 
-        Args:
-            filters (:obj:`Filters `):
+        Parameters:
+            filters (:obj:`Filters`):
                 Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function.
 
             group (``int``, *optional*):
diff --git a/pyrogram/client/methods/messages/delete_messages.py b/pyrogram/client/methods/messages/delete_messages.py
index 9eb42867..e139a270 100644
--- a/pyrogram/client/methods/messages/delete_messages.py
+++ b/pyrogram/client/methods/messages/delete_messages.py
@@ -29,9 +29,9 @@ class DeleteMessages(BaseClient):
         message_ids: Iterable[int],
         revoke: bool = True
     ) -> bool:
-        """Use this method to delete messages, including service messages.
+        """Delete messages, including service messages.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -48,10 +48,10 @@ class DeleteMessages(BaseClient):
                 Defaults to True.
 
         Returns:
-            True on success, False otherwise.
+            ``bool``: True on success, False otherwise.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         peer = await self.resolve_peer(chat_id)
         message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/client/methods/messages/download_media.py
index 7ebd0fed..b91ac9a4 100644
--- a/pyrogram/client/methods/messages/download_media.py
+++ b/pyrogram/client/methods/messages/download_media.py
@@ -32,10 +32,10 @@ class DownloadMedia(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union[str, None]:
-        """Use this method to download the media from a message.
+        """Download the media from a message.
 
-        Args:
-            message (:obj:`Message ` | ``str``):
+        Parameters:
+            message (:obj:`Message` | ``str``):
                 Pass a Message containing the media, the media itself (message.audio, message.video, ...) or
                 the file id as string.
 
@@ -59,7 +59,7 @@ class DownloadMedia(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -73,11 +73,11 @@ class DownloadMedia(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the absolute path of the downloaded file as string is returned, None otherwise.
-            In case the download is deliberately stopped with :meth:`stop_transmission`, None is returned as well.
+            ``str`` | ``None``: On success, the absolute path of the downloaded file is returned, otherwise, in case
+            the download failed or was deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
             ``ValueError`` if the message doesn't contain any downloadable media
         """
         error_message = "This message doesn't contain any downloadable media"
diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/client/methods/messages/edit_message_caption.py
index 8fd89dc6..697623f3 100644
--- a/pyrogram/client/methods/messages/edit_message_caption.py
+++ b/pyrogram/client/methods/messages/edit_message_caption.py
@@ -32,9 +32,9 @@ class EditMessageCaption(BaseClient):
         parse_mode: str = "",
         reply_markup: "pyrogram.InlineKeyboardMarkup" = None
     ) -> "pyrogram.Message":
-        """Use this method to edit captions of messages.
+        """Edit captions of messages.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -47,18 +47,17 @@ class EditMessageCaption(BaseClient):
                 New caption of the message.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            :obj:`Message`: On success, the edited message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         style = self.html if parse_mode.lower() == "html" else self.markdown
 
diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/client/methods/messages/edit_message_media.py
index 13f938ae..88c41466 100644
--- a/pyrogram/client/methods/messages/edit_message_media.py
+++ b/pyrogram/client/methods/messages/edit_message_media.py
@@ -40,14 +40,14 @@ class EditMessageMedia(BaseClient):
         media: InputMedia,
         reply_markup: "pyrogram.InlineKeyboardMarkup" = None
     ) -> "pyrogram.Message":
-        """Use this method to edit audio, document, photo, or video messages.
+        """Edit audio, document, photo, or video messages.
 
         If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise,
         message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded.
         Use previously uploaded file via its file_id or specify a URL. On success, if the edited message was sent
         by the bot, the edited Message is returned, otherwise True is returned.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -63,10 +63,10 @@ class EditMessageMedia(BaseClient):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            :obj:`Message`: On success, the edited message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         style = self.html if media.parse_mode.lower() == "html" else self.markdown
         caption = media.caption
diff --git a/pyrogram/client/methods/messages/edit_message_reply_markup.py b/pyrogram/client/methods/messages/edit_message_reply_markup.py
index 18f2fbb4..b6eba080 100644
--- a/pyrogram/client/methods/messages/edit_message_reply_markup.py
+++ b/pyrogram/client/methods/messages/edit_message_reply_markup.py
@@ -30,9 +30,9 @@ class EditMessageReplyMarkup(BaseClient):
         message_id: int,
         reply_markup: "pyrogram.InlineKeyboardMarkup" = None
     ) -> "pyrogram.Message":
-        """Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
+        """Edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -45,11 +45,11 @@ class EditMessageReplyMarkup(BaseClient):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, if edited message is sent by the bot, the edited
-            :obj:`Message ` is returned, otherwise True is returned.
+            :obj:`Message` | ``bool``: In case the edited message is sent by the bot, the edited message is returned,
+            otherwise, True is returned in case the edited message is send by the user.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         r = await self.send(
diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/client/methods/messages/edit_message_text.py
index fac74f89..5d2782f9 100644
--- a/pyrogram/client/methods/messages/edit_message_text.py
+++ b/pyrogram/client/methods/messages/edit_message_text.py
@@ -33,9 +33,9 @@ class EditMessageText(BaseClient):
         disable_web_page_preview: bool = None,
         reply_markup: "pyrogram.InlineKeyboardMarkup" = None
     ) -> "pyrogram.Message":
-        """Use this method to edit text messages.
+        """Edit text messages.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -48,9 +48,8 @@ class EditMessageText(BaseClient):
                 New text of the message.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your message. Defaults to "markdown".
 
             disable_web_page_preview (``bool``, *optional*):
                 Disables link previews for links in this message.
@@ -59,10 +58,10 @@ class EditMessageText(BaseClient):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            :obj:`Message`: On success, the edited message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         style = self.html if parse_mode.lower() == "html" else self.markdown
 
diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/client/methods/messages/forward_messages.py
index 67f695cc..e8b77a23 100644
--- a/pyrogram/client/methods/messages/forward_messages.py
+++ b/pyrogram/client/methods/messages/forward_messages.py
@@ -28,14 +28,14 @@ class ForwardMessages(BaseClient):
         self,
         chat_id: Union[int, str],
         from_chat_id: Union[int, str],
-        message_ids: Iterable[int],
+        message_ids: Union[int, Iterable[int]],
         disable_notification: bool = None,
         as_copy: bool = False,
         remove_caption: bool = False
     ) -> "pyrogram.Messages":
-        """Use this method to forward messages of any kind.
+        """Forward messages of any kind.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,13 +64,12 @@ class ForwardMessages(BaseClient):
                 Defaults to False.
 
         Returns:
-            On success and in case *message_ids* was an iterable, the returned value will be a list of the forwarded
-            :obj:`Messages ` even if a list contains just one element, otherwise if
-            *message_ids* was an integer, the single forwarded :obj:`Message `
-            is returned.
+            :obj:`Message` | :obj:`Messages`: In case *message_ids* was an integer, the single forwarded message is
+            returned, otherwise, in case *message_ids* was an iterable, the returned value will be an object containing
+            a list of messages, even if such iterable contained just a single element.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         is_iterable = not isinstance(message_ids, int)
diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/client/methods/messages/get_history.py
index 3392e7fd..069c03e5 100644
--- a/pyrogram/client/methods/messages/get_history.py
+++ b/pyrogram/client/methods/messages/get_history.py
@@ -38,12 +38,12 @@ class GetHistory(BaseClient):
         offset_date: int = 0,
         reverse: bool = False
     ) -> "pyrogram.Messages":
-        """Use this method to retrieve a chunk of the history of a chat.
+        """Retrieve a chunk of the history of a chat.
 
         You can get up to 100 messages at once.
         For a more convenient way of getting a chat history see :meth:`iter_history`.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -67,10 +67,10 @@ class GetHistory(BaseClient):
                 Pass True to retrieve the messages in reversed order (from older to most recent).
 
         Returns:
-            On success, a :obj:`Messages ` object is returned.
+            :obj:`Messages` - On success, an object containing a list of the retrieved messages.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         while True:
diff --git a/pyrogram/client/methods/messages/get_history_count.py b/pyrogram/client/methods/messages/get_history_count.py
index 8883c051..1286fffb 100644
--- a/pyrogram/client/methods/messages/get_history_count.py
+++ b/pyrogram/client/methods/messages/get_history_count.py
@@ -32,7 +32,7 @@ class GetHistoryCount(BaseClient):
         self,
         chat_id: Union[int, str]
     ) -> int:
-        """Use this method to get the total count of messages in a chat.
+        """Get the total count of messages in a chat.
 
         .. note::
 
@@ -40,15 +40,15 @@ class GetHistoryCount(BaseClient):
             a **private** or a **basic group** chat has with a single method call. To overcome this limitation, Pyrogram
             has to iterate over all the messages. Channels and supergroups are not affected by this limitation.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
 
         Returns:
-            On success, an integer is returned.
+            ``int``: On success, the chat history count is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         peer = await self.resolve_peer(chat_id)
diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/client/methods/messages/get_messages.py
index 17f1ef47..ac83a7e4 100644
--- a/pyrogram/client/methods/messages/get_messages.py
+++ b/pyrogram/client/methods/messages/get_messages.py
@@ -36,10 +36,10 @@ class GetMessages(BaseClient):
         reply_to_message_ids: Union[int, Iterable[int]] = None,
         replies: int = 1
     ) -> Union["pyrogram.Message", "pyrogram.Messages"]:
-        """Use this method to get one or more messages that belong to a specific chat.
+        """Get one or more messages that belong to a specific chat.
         You can retrieve up to 200 messages at once.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -55,15 +55,17 @@ class GetMessages(BaseClient):
                 If *message_ids* is set, this argument will be ignored.
 
             replies (``int``, *optional*):
-                The number of subsequent replies to get for each message. Defaults to 1.
+                The number of subsequent replies to get for each message.
+                Pass 0 for no reply at all or -1 for unlimited replies.
+                Defaults to 1.
 
         Returns:
-            On success and in case *message_ids* or *reply_to_message_ids* was an iterable, the returned value will be a
-            :obj:`Messages ` even if a list contains just one element. Otherwise, if *message_ids* or
-            *reply_to_message_ids* was an integer, the single requested :obj:`Message ` is returned.
+            :obj:`Message` | :obj:`Messages`: In case *message_ids* was an integer, the single requested message is
+            returned, otherwise, in case *message_ids* was an iterable, the returned value will be an object containing
+            a list of messages, even if such iterable contained just a single element.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         ids, ids_type = (
             (message_ids, types.InputMessageID) if message_ids
@@ -80,6 +82,9 @@ class GetMessages(BaseClient):
         ids = list(ids) if is_iterable else [ids]
         ids = [ids_type(id=i) for i in ids]
 
+        if replies < 0:
+            replies = (1 << 31) - 1
+
         if isinstance(peer, types.InputPeerChannel):
             rpc = functions.channels.GetMessages(channel=peer, id=ids)
         else:
diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/client/methods/messages/iter_history.py
index 52f408ea..7fc81150 100644
--- a/pyrogram/client/methods/messages/iter_history.py
+++ b/pyrogram/client/methods/messages/iter_history.py
@@ -35,12 +35,12 @@ class IterHistory(BaseClient):
         offset_date: int = 0,
         reverse: bool = False
     ) -> Optional[AsyncGenerator["pyrogram.Message", None]]:
-        """Use this method to iterate through a chat history sequentially.
+        """Iterate through a chat history sequentially.
 
         This convenience method does the same as repeatedly calling :meth:`get_history` in a loop, thus saving you from
         the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a single call.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,10 +64,10 @@ class IterHistory(BaseClient):
                 Pass True to retrieve the messages in reversed order (from older to most recent).
 
         Returns:
-            A generator yielding :obj:`Message ` objects.
+            ``Generator``: A generator yielding :obj:`Message` objects.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         offset_id = offset_id or (1 if reverse else 0)
         current = 0
diff --git a/pyrogram/client/methods/messages/retract_vote.py b/pyrogram/client/methods/messages/retract_vote.py
index 7f48c8ea..490f0ad0 100644
--- a/pyrogram/client/methods/messages/retract_vote.py
+++ b/pyrogram/client/methods/messages/retract_vote.py
@@ -29,9 +29,9 @@ class RetractVote(BaseClient):
         chat_id: Union[int, str],
         message_id: int
     ) -> "pyrogram.Poll":
-        """Use this method to retract your vote in a poll.
+        """Retract your vote in a poll.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -41,10 +41,10 @@ class RetractVote(BaseClient):
                 Identifier of the original message with the poll.
 
         Returns:
-            On success, the :obj:`Poll ` with the retracted vote is returned.
+            :obj:`Poll`: On success, the poll with the retracted vote is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SendVote(
diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/client/methods/messages/send_animation.py
index 7dfd0eb9..7c6e7742 100644
--- a/pyrogram/client/methods/messages/send_animation.py
+++ b/pyrogram/client/methods/messages/send_animation.py
@@ -49,9 +49,9 @@ class SendAnimation(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send animation files (animation or H.264/MPEG-4 AVC video without sound).
+        """Send animation files (animation or H.264/MPEG-4 AVC video without sound).
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -67,9 +67,8 @@ class SendAnimation(BaseClient):
                 Animation caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of sent animation in seconds.
@@ -107,7 +106,7 @@ class SendAnimation(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -121,11 +120,11 @@ class SendAnimation(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/client/methods/messages/send_audio.py
index 81ceb3f3..ba465655 100644
--- a/pyrogram/client/methods/messages/send_audio.py
+++ b/pyrogram/client/methods/messages/send_audio.py
@@ -48,11 +48,11 @@ class SendAudio(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send audio files.
+        """Send audio files.
 
         For sending voice messages, use the :obj:`send_voice()` method instead.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -68,9 +68,8 @@ class SendAudio(BaseClient):
                 Audio caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of the audio in seconds.
@@ -108,7 +107,7 @@ class SendAudio(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -122,11 +121,11 @@ class SendAudio(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/client/methods/messages/send_cached_media.py
index b9f00495..4ba47650 100644
--- a/pyrogram/client/methods/messages/send_cached_media.py
+++ b/pyrogram/client/methods/messages/send_cached_media.py
@@ -42,13 +42,13 @@ class SendCachedMedia(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send any media stored on the Telegram servers using a file_id.
+        """Send any media stored on the Telegram servers using a file_id.
 
         This convenience method works with any valid file_id only.
         It does the same as calling the relevant method for sending media using a file_id, thus saving you from the
         hassle of using the correct method for the media the file_id is pointing to.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -62,9 +62,8 @@ class SendCachedMedia(BaseClient):
                 Media caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             disable_notification (``bool``, *optional*):
                 Sends the message silently.
@@ -78,10 +77,10 @@ class SendCachedMedia(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            :obj:`Message`: On success, the sent media message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         style = self.html if parse_mode.lower() == "html" else self.markdown
 
diff --git a/pyrogram/client/methods/messages/send_chat_action.py b/pyrogram/client/methods/messages/send_chat_action.py
index 136cccc1..c1de2014 100644
--- a/pyrogram/client/methods/messages/send_chat_action.py
+++ b/pyrogram/client/methods/messages/send_chat_action.py
@@ -18,51 +18,64 @@
 
 from typing import Union
 
-from pyrogram.api import functions
-from pyrogram.client.ext import BaseClient, ChatAction
+from pyrogram.api import functions, types
+from pyrogram.client.ext import BaseClient
+import json
+
+
+class ChatAction:
+    TYPING = types.SendMessageTypingAction
+    UPLOAD_PHOTO = types.SendMessageUploadPhotoAction
+    RECORD_VIDEO = types.SendMessageRecordVideoAction
+    UPLOAD_VIDEO = types.SendMessageUploadVideoAction
+    RECORD_AUDIO = types.SendMessageRecordAudioAction
+    UPLOAD_AUDIO = types.SendMessageUploadAudioAction
+    UPLOAD_DOCUMENT = types.SendMessageUploadDocumentAction
+    FIND_LOCATION = types.SendMessageGeoLocationAction
+    RECORD_VIDEO_NOTE = types.SendMessageRecordRoundAction
+    UPLOAD_VIDEO_NOTE = types.SendMessageUploadRoundAction
+    PLAYING = types.SendMessageGamePlayAction
+    CHOOSE_CONTACT = types.SendMessageChooseContactAction
+    CANCEL = types.SendMessageCancelAction
+
+
+POSSIBLE_VALUES = list(map(lambda x: x.lower(), filter(lambda x: not x.startswith("__"), ChatAction.__dict__.keys())))
 
 
 class SendChatAction(BaseClient):
-    async def send_chat_action(
-        self,
-        chat_id: Union[int, str],
-        action: Union[ChatAction, str],
-        progress: int = 0
-    ):
-        """Use this method when you need to tell the other party that something is happening on your side.
+    async def send_chat_action(self, chat_id: Union[int, str], action: str) -> bool:
+        """Tell the other party that something is happening on your side.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
                 For a contact that exists in your Telegram address book you can use his phone number (str).
 
-            action (:obj:`ChatAction ` | ``str``):
-                Type of action to broadcast.
-                Choose one from the :class:`ChatAction ` enumeration,
-                depending on what the user is about to receive.
-                You can also provide a string (e.g. "typing", "upload_photo", "record_audio", ...).
-
-            progress (``int``, *optional*):
-                Progress of the upload process.
-                Currently useless because official clients don't seem to be handling this.
+            action (``str``):
+                Type of action to broadcast. Choose one, depending on what the user is about to receive: *"typing"* for
+                text messages, *"upload_photo"* for photos, *"record_video"* or *"upload_video"* for videos,
+                *"record_audio"* or *"upload_audio"* for audio files, *"upload_document"* for general files,
+                *"find_location"* for location data, *"record_video_note"* or *"upload_video_note"* for video notes,
+                *"choose_contact"* for contacts, *"playing"* for games or *"cancel"* to cancel any chat action currently
+                displayed.
 
         Returns:
-            On success, True is returned.
+            ``bool``: On success, True is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if the provided string is not a valid ChatAction.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case the provided string is not a valid ChatAction.
         """
 
-        # Resolve Enum type
-        if isinstance(action, str):
-            action = ChatAction.from_string(action).value
-        elif isinstance(action, ChatAction):
-            action = action.value
+        try:
+            action = ChatAction.__dict__[action.upper()]
+        except KeyError:
+            raise ValueError("Invalid chat action '{}'. Possible values are: {}".format(
+                action, json.dumps(POSSIBLE_VALUES, indent=4))) from None
 
         if "Upload" in action.__name__:
-            action = action(progress=progress)
+            action = action(progress=0)
         else:
             action = action()
 
diff --git a/pyrogram/client/methods/messages/send_contact.py b/pyrogram/client/methods/messages/send_contact.py
index 996a801e..c8f56c5c 100644
--- a/pyrogram/client/methods/messages/send_contact.py
+++ b/pyrogram/client/methods/messages/send_contact.py
@@ -39,9 +39,9 @@ class SendContact(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send phone contacts.
+        """Send phone contacts.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -71,10 +71,10 @@ class SendContact(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            :obj:`Message`: On success, the sent contact message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SendMedia(
diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/client/methods/messages/send_document.py
index 663cc911..ab0a16b6 100644
--- a/pyrogram/client/methods/messages/send_document.py
+++ b/pyrogram/client/methods/messages/send_document.py
@@ -45,9 +45,9 @@ class SendDocument(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send general files.
+        """Send generic files.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -69,9 +69,8 @@ class SendDocument(BaseClient):
                 Document caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             disable_notification (``bool``, *optional*):
                 Sends the message silently.
@@ -94,7 +93,7 @@ class SendDocument(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -108,11 +107,11 @@ class SendDocument(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/send_location.py b/pyrogram/client/methods/messages/send_location.py
index caaf6830..0e6f0feb 100644
--- a/pyrogram/client/methods/messages/send_location.py
+++ b/pyrogram/client/methods/messages/send_location.py
@@ -38,9 +38,9 @@ class SendLocation(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send points on the map.
+        """Send points on the map.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,10 +64,10 @@ class SendLocation(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            :obj:`Message`: On success, the sent location message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SendMedia(
diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/client/methods/messages/send_media_group.py
index 1ce259df..5d37729c 100644
--- a/pyrogram/client/methods/messages/send_media_group.py
+++ b/pyrogram/client/methods/messages/send_media_group.py
@@ -41,9 +41,9 @@ class SendMediaGroup(BaseClient):
         disable_notification: bool = None,
         reply_to_message_id: int = None
     ):
-        """Use this method to send a group of photos or videos as an album.
+        """Send a group of photos or videos as an album.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -60,11 +60,10 @@ class SendMediaGroup(BaseClient):
                 If the message is a reply, ID of the original message.
 
         Returns:
-            On success, a :obj:`Messages ` object is returned containing all the
-            single messages sent.
+            :obj:`Messages`: On success, an object is returned containing all the single messages sent.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         multi_media = []
 
diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/client/methods/messages/send_message.py
index 090bd63c..65b59604 100644
--- a/pyrogram/client/methods/messages/send_message.py
+++ b/pyrogram/client/methods/messages/send_message.py
@@ -39,9 +39,9 @@ class SendMessage(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send text messages.
+        """Send text messages.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -51,9 +51,8 @@ class SendMessage(BaseClient):
                 Text of the message to be sent.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your message. Defaults to "markdown".
 
             disable_web_page_preview (``bool``, *optional*):
                 Disables link previews for links in this message.
@@ -70,10 +69,10 @@ class SendMessage(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message` is returned.
+            :obj:`Message`: On success, the sent text message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         style = self.html if parse_mode.lower() == "html" else self.markdown
         message, entities = (await style.parse(text)).values()
diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/client/methods/messages/send_photo.py
index 00302233..19dfa67e 100644
--- a/pyrogram/client/methods/messages/send_photo.py
+++ b/pyrogram/client/methods/messages/send_photo.py
@@ -46,9 +46,9 @@ class SendPhoto(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send photos.
+        """Send photos.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,9 +64,8 @@ class SendPhoto(BaseClient):
                 Photo caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             ttl_seconds (``int``, *optional*):
                 Self-Destruct Timer.
@@ -94,7 +93,7 @@ class SendPhoto(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -108,11 +107,11 @@ class SendPhoto(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent photo message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/send_poll.py b/pyrogram/client/methods/messages/send_poll.py
index 6b4e227a..4dae53b2 100644
--- a/pyrogram/client/methods/messages/send_poll.py
+++ b/pyrogram/client/methods/messages/send_poll.py
@@ -38,9 +38,9 @@ class SendPoll(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send a new poll.
+        """Send a new poll.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,10 +64,10 @@ class SendPoll(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            :obj:`Message`: On success, the sent poll message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = self.send(
             functions.messages.SendMedia(
diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/client/methods/messages/send_sticker.py
index f39bf069..1aabc746 100644
--- a/pyrogram/client/methods/messages/send_sticker.py
+++ b/pyrogram/client/methods/messages/send_sticker.py
@@ -43,9 +43,9 @@ class SendSticker(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send .webp stickers.
+        """Send .webp stickers.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -78,7 +78,7 @@ class SendSticker(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -92,11 +92,10 @@ class SendSticker(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
-
+            :obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
 
diff --git a/pyrogram/client/methods/messages/send_venue.py b/pyrogram/client/methods/messages/send_venue.py
index 9e657bbd..76594848 100644
--- a/pyrogram/client/methods/messages/send_venue.py
+++ b/pyrogram/client/methods/messages/send_venue.py
@@ -42,9 +42,9 @@ class SendVenue(BaseClient):
             "pyrogram.ForceReply"
         ] = None
     ) -> "pyrogram.Message":
-        """Use this method to send information about a venue.
+        """Send information about a venue.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -81,10 +81,10 @@ class SendVenue(BaseClient):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            :obj:`Message`: On success, the sent venue message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         r = await self.send(
             functions.messages.SendMedia(
diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/client/methods/messages/send_video.py
index 8164a2ee..52a68641 100644
--- a/pyrogram/client/methods/messages/send_video.py
+++ b/pyrogram/client/methods/messages/send_video.py
@@ -50,9 +50,9 @@ class SendVideo(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send video files.
+        """Send video files.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -68,9 +68,8 @@ class SendVideo(BaseClient):
                 Video caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of sent video in seconds.
@@ -111,7 +110,7 @@ class SendVideo(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -125,11 +124,11 @@ class SendVideo(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent video message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/client/methods/messages/send_video_note.py
index 71b0a110..bccf3bbc 100644
--- a/pyrogram/client/methods/messages/send_video_note.py
+++ b/pyrogram/client/methods/messages/send_video_note.py
@@ -46,9 +46,9 @@ class SendVideoNote(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send video messages.
+        """Send video messages.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -93,7 +93,7 @@ class SendVideoNote(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -107,11 +107,11 @@ class SendVideoNote(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the
+            pload is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
 
diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/client/methods/messages/send_voice.py
index cc91c5be..8ede5257 100644
--- a/pyrogram/client/methods/messages/send_voice.py
+++ b/pyrogram/client/methods/messages/send_voice.py
@@ -46,9 +46,9 @@ class SendVoice(BaseClient):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> Union["pyrogram.Message", None]:
-        """Use this method to send audio files.
+        """Send audio files.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -64,9 +64,8 @@ class SendVoice(BaseClient):
                 Voice message caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of the voice message in seconds.
@@ -92,7 +91,7 @@ class SendVoice(BaseClient):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -106,11 +105,11 @@ class SendVoice(BaseClient):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
-            In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
+            :obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload
+            is deliberately stopped with :meth:`stop_transmission`, None is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         file = None
         style = self.html if parse_mode.lower() == "html" else self.markdown
diff --git a/pyrogram/client/methods/messages/stop_poll.py b/pyrogram/client/methods/messages/stop_poll.py
index 383b1dcb..054229c2 100644
--- a/pyrogram/client/methods/messages/stop_poll.py
+++ b/pyrogram/client/methods/messages/stop_poll.py
@@ -30,11 +30,11 @@ class StopPoll(BaseClient):
         message_id: int,
         reply_markup: "pyrogram.InlineKeyboardMarkup" = None
     ) -> "pyrogram.Poll":
-        """Use this method to stop a poll which was sent by you.
+        """Stop a poll which was sent by you.
 
         Stopped polls can't be reopened and nobody will be able to vote in it anymore.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -47,10 +47,10 @@ class StopPoll(BaseClient):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the stopped :obj:`Poll ` with the final results is returned.
+            :obj:`Poll`: On success, the stopped poll with the final results is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         poll = (await self.get_messages(chat_id, message_id)).poll
 
diff --git a/pyrogram/client/methods/messages/vote_poll.py b/pyrogram/client/methods/messages/vote_poll.py
index b0eeb925..88bdc83f 100644
--- a/pyrogram/client/methods/messages/vote_poll.py
+++ b/pyrogram/client/methods/messages/vote_poll.py
@@ -30,9 +30,9 @@ class VotePoll(BaseClient):
         message_id: id,
         option: int
     ) -> "pyrogram.Poll":
-        """Use this method to vote a poll.
+        """Vote a poll.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -45,10 +45,10 @@ class VotePoll(BaseClient):
                 Index of the poll option you want to vote for (0 to 9).
 
         Returns:
-            On success, the :obj:`Poll ` with the chosen option is returned.
+            :obj:`Poll` - On success, the poll with the chosen option is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         poll = (await self.get_messages(chat_id, message_id)).poll
diff --git a/pyrogram/client/methods/password/change_cloud_password.py b/pyrogram/client/methods/password/change_cloud_password.py
index d9c29f57..a8f9bcfa 100644
--- a/pyrogram/client/methods/password/change_cloud_password.py
+++ b/pyrogram/client/methods/password/change_cloud_password.py
@@ -30,9 +30,9 @@ class ChangeCloudPassword(BaseClient):
         new_password: str,
         new_hint: str = ""
     ) -> bool:
-        """Use this method to change your Two-Step Verification password (Cloud Password) with a new one.
+        """Change your Two-Step Verification password (Cloud Password) with a new one.
 
-        Args:
+        Parameters:
             current_password (``str``):
                 Your current password.
 
@@ -43,11 +43,11 @@ class ChangeCloudPassword(BaseClient):
                 A new password hint.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` in case there is no cloud password to change.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case there is no cloud password to change.
         """
         r = await self.send(functions.account.GetPassword())
 
diff --git a/pyrogram/client/methods/password/enable_cloud_password.py b/pyrogram/client/methods/password/enable_cloud_password.py
index bd9fdb80..964e5559 100644
--- a/pyrogram/client/methods/password/enable_cloud_password.py
+++ b/pyrogram/client/methods/password/enable_cloud_password.py
@@ -30,11 +30,11 @@ class EnableCloudPassword(BaseClient):
         hint: str = "",
         email: str = None
     ) -> bool:
-        """Use this method to enable the Two-Step Verification security feature (Cloud Password) on your account.
+        """Enable the Two-Step Verification security feature (Cloud Password) on your account.
 
         This password will be asked when you log-in on a new device in addition to the SMS code.
 
-        Args:
+        Parameters:
             password (``str``):
                 Your password.
 
@@ -45,11 +45,11 @@ class EnableCloudPassword(BaseClient):
                 Recovery e-mail.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` in case there is already a cloud password enabled.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case there is already a cloud password enabled.
         """
         r = await self.send(functions.account.GetPassword())
 
diff --git a/pyrogram/client/methods/password/remove_cloud_password.py b/pyrogram/client/methods/password/remove_cloud_password.py
index 658f55fb..969e8c78 100644
--- a/pyrogram/client/methods/password/remove_cloud_password.py
+++ b/pyrogram/client/methods/password/remove_cloud_password.py
@@ -26,18 +26,18 @@ class RemoveCloudPassword(BaseClient):
         self,
         password: str
     ) -> bool:
-        """Use this method to turn off the Two-Step Verification security feature (Cloud Password) on your account.
+        """Turn off the Two-Step Verification security feature (Cloud Password) on your account.
 
-        Args:
+        Parameters:
             password (``str``):
                 Your current password.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` in case there is no cloud password to remove.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case there is no cloud password to remove.
         """
         r = await self.send(functions.account.GetPassword())
 
diff --git a/pyrogram/client/methods/users/delete_user_profile_photos.py b/pyrogram/client/methods/users/delete_user_profile_photos.py
index bfbc810e..7f6d433a 100644
--- a/pyrogram/client/methods/users/delete_user_profile_photos.py
+++ b/pyrogram/client/methods/users/delete_user_profile_photos.py
@@ -29,18 +29,18 @@ class DeleteUserProfilePhotos(BaseClient):
         self,
         id: Union[str, List[str]]
     ) -> bool:
-        """Use this method to delete your own profile photos.
+        """Delete your own profile photos.
 
-        Args:
+        Parameters:
             id (``str`` | ``list``):
-                A single :obj:`Photo ` id as string or multiple ids as list of strings for deleting
+                A single :obj:`Photo` id as string or multiple ids as list of strings for deleting
                 more than one photos at once.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         id = id if isinstance(id, list) else [id]
         input_photos = []
diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/client/methods/users/get_me.py
index 6281a6e7..66ab999d 100644
--- a/pyrogram/client/methods/users/get_me.py
+++ b/pyrogram/client/methods/users/get_me.py
@@ -23,13 +23,13 @@ from ...ext import BaseClient
 
 class GetMe(BaseClient):
     async def get_me(self) -> "pyrogram.User":
-        """A simple method for testing your authorization. Requires no parameters.
+        """Get your own user identity.
 
         Returns:
-            Basic information about the user or bot in form of a :obj:`User` object
+            :obj:`User`: Basic information about the user or bot.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return pyrogram.User._parse(
             self,
diff --git a/pyrogram/client/methods/users/get_user_profile_photos.py b/pyrogram/client/methods/users/get_user_profile_photos.py
index 5524c54d..3cfb8295 100644
--- a/pyrogram/client/methods/users/get_user_profile_photos.py
+++ b/pyrogram/client/methods/users/get_user_profile_photos.py
@@ -30,9 +30,9 @@ class GetUserProfilePhotos(BaseClient):
         offset: int = 0,
         limit: int = 100
     ) -> "pyrogram.UserProfilePhotos":
-        """Use this method to get a list of profile pictures for a user.
+        """Get a list of profile pictures for a user.
 
-        Args:
+        Parameters:
             user_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -47,10 +47,10 @@ class GetUserProfilePhotos(BaseClient):
                 Values between 1—100 are accepted. Defaults to 100.
 
         Returns:
-            On success, a :obj:`UserProfilePhotos` object is returned.
+            :obj:`UserProfilePhotos`: On success, an object containing a list of the profile photos is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return pyrogram.UserProfilePhotos._parse(
             self,
diff --git a/pyrogram/client/methods/users/get_user_profile_photos_count.py b/pyrogram/client/methods/users/get_user_profile_photos_count.py
index 688ad7b5..cd9d9434 100644
--- a/pyrogram/client/methods/users/get_user_profile_photos_count.py
+++ b/pyrogram/client/methods/users/get_user_profile_photos_count.py
@@ -24,19 +24,19 @@ from ...ext import BaseClient
 
 class GetUserProfilePhotosCount(BaseClient):
     async def get_user_profile_photos_count(self, user_id: Union[int, str]) -> int:
-        """Use this method to get the total count of profile pictures for a user.
+        """Get the total count of profile pictures for a user.
 
-        Args:
+        Parameters:
             user_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
                 For a contact that exists in your Telegram address book you can use his phone number (str).
 
         Returns:
-            On success, an integer is returned.
+            ``int``: On success, the user profile photos count is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         r = await self.send(
diff --git a/pyrogram/client/methods/users/get_users.py b/pyrogram/client/methods/users/get_users.py
index b9d0f12e..9136865e 100644
--- a/pyrogram/client/methods/users/get_users.py
+++ b/pyrogram/client/methods/users/get_users.py
@@ -25,26 +25,27 @@ from ...ext import BaseClient
 
 
 class GetUsers(BaseClient):
+    # TODO: Add Users type and use that
     async def get_users(
         self,
-        user_ids: Iterable[Union[int, str]]
+        user_ids: Union[Iterable[Union[int, str]], int, str]
     ) -> Union["pyrogram.User", List["pyrogram.User"]]:
-        """Use this method to get information about a user.
+        """Get information about a user.
         You can retrieve up to 200 users at once.
 
-        Args:
+        Parameters:
             user_ids (``iterable``):
                 A list of User identifiers (id or username) or a single user id/username.
                 For a contact that exists in your Telegram address book you can use his phone number (str).
                 Iterators and Generators are also accepted.
 
         Returns:
-            On success and in case *user_ids* was an iterable, the returned value will be a list of the requested
-            :obj:`Users ` even if a list contains just one element, otherwise if
-            *user_ids* was an integer or string, the single requested :obj:`User` is returned.
+            :obj:`User` | List of :obj:`User`: In case *user_ids* was an integer or string the single requested user is
+            returned, otherwise, in case *user_ids* was an iterable a list of users is returned, even if the iterable
+            contained one item only.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         is_iterable = not isinstance(user_ids, (int, str))
         user_ids = list(user_ids) if is_iterable else [user_ids]
diff --git a/pyrogram/client/methods/users/set_user_profile_photo.py b/pyrogram/client/methods/users/set_user_profile_photo.py
index 5a155b94..6f6c402e 100644
--- a/pyrogram/client/methods/users/set_user_profile_photo.py
+++ b/pyrogram/client/methods/users/set_user_profile_photo.py
@@ -25,21 +25,21 @@ class SetUserProfilePhoto(BaseClient):
         self,
         photo: str
     ) -> bool:
-        """Use this method to set a new profile photo.
+        """Set a new profile photo.
 
         This method only works for Users.
         Bots profile photos must be set using BotFather.
 
-        Args:
+        Parameters:
             photo (``str``):
                 Profile photo to set.
                 Pass a file path as string to upload a new photo that exists on your local machine.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         return bool(
diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/client/methods/users/update_username.py
index 15877992..ab8b9c59 100644
--- a/pyrogram/client/methods/users/update_username.py
+++ b/pyrogram/client/methods/users/update_username.py
@@ -27,21 +27,21 @@ class UpdateUsername(BaseClient):
         self,
         username: Union[str, None]
     ) -> bool:
-        """Use this method to update your own username.
+        """Update your own username.
         
         This method only works for users, not bots. Bot usernames must be changed via Bot Support or by recreating
         them from scratch using BotFather. To update a channel or supergroup username you can use
         :meth:`update_chat_username`.
 
-        Args:
+        Parameters:
             username (``str`` | ``None``):
-                Username to set. "" (empty string) or None to remove the username.
+                Username to set. "" (empty string) or None to remove it.
 
         Returns:
-            True on success.
+            ``bool``: True on success.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
 
         return bool(
diff --git a/pyrogram/client/types/__init__.py b/pyrogram/client/types/__init__.py
index 120c7ff5..3d430c44 100644
--- a/pyrogram/client/types/__init__.py
+++ b/pyrogram/client/types/__init__.py
@@ -16,7 +16,7 @@
 # You should have received a copy of the GNU Lesser General Public License
 # along with Pyrogram.  If not, see .
 
-from .bots import *
+from .keyboards import *
 from .inline_mode import *
 from .input_media import *
 from .input_message_content import *
diff --git a/pyrogram/client/types/inline_mode/inline_query.py b/pyrogram/client/types/inline_mode/inline_query.py
index 737960ca..605d98cc 100644
--- a/pyrogram/client/types/inline_mode/inline_query.py
+++ b/pyrogram/client/types/inline_mode/inline_query.py
@@ -28,14 +28,15 @@ from ..user_and_chats import User
 
 
 class InlineQuery(PyrogramType, Update):
-    """This object represents an incoming inline query.
+    """An incoming inline query.
+
     When the user sends an empty query, your bot could return some default or trending results.
 
-    Args:
+    Parameters:
         id (``str``):
             Unique identifier for this query.
 
-        from_user (:obj:`User `):
+        from_user (:obj:`User`):
             Sender.
 
         query (``str``):
@@ -44,7 +45,7 @@ class InlineQuery(PyrogramType, Update):
         offset (``str``):
             Offset of the results to be returned, can be controlled by the bot.
 
-        location (:obj:`Location `. *optional*):
+        location (:obj:`Location`. *optional*):
             Sender location, only for bots that request user location.
     """
     __slots__ = ["id", "from_user", "query", "offset", "location"]
@@ -52,7 +53,7 @@ class InlineQuery(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: str,
         from_user: User,
         query: str,
@@ -61,7 +62,6 @@ class InlineQuery(PyrogramType, Update):
     ):
         super().__init__(client)
 
-        self._client = client
         self.id = id
         self.from_user = from_user
         self.query = query
@@ -108,7 +108,7 @@ class InlineQuery(PyrogramType, Update):
 
                 inline_query.answer([...])
 
-        Args:
+        Parameters:
             results (List of :obj:`InlineQueryResult `):
                 A list of results for the inline query.
 
diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py
index 6fd1975d..e2074cfd 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result.py
@@ -40,7 +40,7 @@ from ..pyrogram_type import PyrogramType
 
 
 class InlineQueryResult(PyrogramType):
-    """This object represents one result of an inline query.
+    """One result of an inline query.
 
     Pyrogram currently supports results of the following 20 types:
 
@@ -50,7 +50,7 @@ class InlineQueryResult(PyrogramType):
     __slots__ = ["type", "id"]
 
     def __init__(self, type: str, id: str):
-        super().__init__(None)
+        super().__init__()
 
         self.type = type
         self.id = id
diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/client/types/inline_mode/inline_query_result_article.py
index 3f0c2997..2e6dd830 100644
--- a/pyrogram/client/types/inline_mode/inline_query_result_article.py
+++ b/pyrogram/client/types/inline_mode/inline_query_result_article.py
@@ -23,11 +23,11 @@ from .inline_query_result import InlineQueryResult
 
 
 class InlineQueryResultArticle(InlineQueryResult):
-    """Represents a link to an article or web page.
+    """Link to an article or web page.
 
     TODO: Hide url?
 
-    Args:
+    Parameters:
         id (``str``):
             Unique identifier for this result, 1-64 bytes.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py
index a67163c6..0ef30b20 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_audio.py
@@ -25,7 +25,7 @@ class InlineQueryResultAudio(PyrogramType):
     Attributes:
         ID: ``0xb0700004``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be audio.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_audio.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_audio.py
index f6ed1f15..dc51139b 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_audio.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_audio.py
@@ -31,7 +31,7 @@ class InlineQueryResultCachedAudio(PyrogramType):
     By default, this audio file will be sent by the user. Alternatively, you can use *input_message_content* to send a
     message with the specified content instead of the audio.
 
-    Args:
+    Parameters:
         id (``str``):
             Unique identifier for this result, 1-64 bytes.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py
index ab1637d2..e2873638 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_document.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedDocument(PyrogramType):
     Attributes:
         ID: ``0xb0700015``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be document.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py
index 4c457873..8b523dbd 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_gif.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedGif(PyrogramType):
     Attributes:
         ID: ``0xb0700012``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be gif.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_mpeg4_gif.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_mpeg4_gif.py
index 93ec1efb..2082150d 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_mpeg4_gif.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_mpeg4_gif.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedMpeg4Gif(PyrogramType):
     Attributes:
         ID: ``0xb0700013``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be mpeg4_gif.
 
@@ -47,7 +47,7 @@ class InlineQueryResultCachedMpeg4Gif(PyrogramType):
         reply_markup (:obj:`InlineKeyboardMarkup `, optional):
             Inline keyboard attached to the message.
 
-        input_message_content (:obj:`InputMessageContent `, optional):
+        input_message_content (:obj:`InputMessageContent`, optional):
             Content of the message to be sent instead of the video animation.
 
     """
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_photo.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_photo.py
index ee6b2654..20c1adbc 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_photo.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_photo.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedPhoto(PyrogramType):
     Attributes:
         ID: ``0xb0700011``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be photo.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py
index 6142b1fa..06944deb 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_sticker.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedSticker(PyrogramType):
     Attributes:
         ID: ``0xb0700014``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be sticker.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_video.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_video.py
index 8c00c61a..e47cae1b 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_video.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_video.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedVideo(PyrogramType):
     Attributes:
         ID: ``0xb0700016``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be video.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py
index 741df389..3f8bb6a3 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_cached_voice.py
@@ -25,7 +25,7 @@ class InlineQueryResultCachedVoice(PyrogramType):
     Attributes:
         ID: ``0xb0700017``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be voice.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_contact.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_contact.py
index e26af4ea..60512f0d 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_contact.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_contact.py
@@ -25,7 +25,7 @@ class InlineQueryResultContact(PyrogramType):
     Attributes:
         ID: ``0xb0700009``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be contact.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py
index 93b8fcae..148ec01d 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_document.py
@@ -25,7 +25,7 @@ class InlineQueryResultDocument(PyrogramType):
     Attributes:
         ID: ``0xb0700006``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be document.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py
index 3e7cfb73..faebacea 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_game.py
@@ -25,7 +25,7 @@ class InlineQueryResultGame(PyrogramType):
     Attributes:
         ID: ``0xb0700010``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be game.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_gif.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_gif.py
index 13f4fc18..d84e098b 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_gif.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_gif.py
@@ -25,7 +25,7 @@ class InlineQueryResultGif(PyrogramType):
     Attributes:
         ID: ``0xb0700001``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be gif.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_location.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_location.py
index 176591d2..cd05c832 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_location.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_location.py
@@ -25,7 +25,7 @@ class InlineQueryResultLocation(PyrogramType):
     Attributes:
         ID: ``0xb0700007``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be location.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_mpeg4_gif.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_mpeg4_gif.py
index 37aa8986..cb704eeb 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_mpeg4_gif.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_mpeg4_gif.py
@@ -25,7 +25,7 @@ class InlineQueryResultMpeg4Gif(PyrogramType):
     Attributes:
         ID: ``0xb0700002``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be mpeg4_gif.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py
index 2ba7c312..3412b3f4 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_photo.py
@@ -25,7 +25,7 @@ class InlineQueryResultPhoto(PyrogramType):
     """Represents a link to a photo. By default, this photo will be sent by the user with optional caption.
     Alternatively, you can use input_message_content to send a message with the specified content instead of the photo.
 
-    Args:
+    Parameters:
         id (``str``):
             Unique identifier for this result, 1-64 bytes.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py
index 23ddfc35..1dee9509 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_venue.py
@@ -25,7 +25,7 @@ class InlineQueryResultVenue(PyrogramType):
     Attributes:
         ID: ``0xb0700008``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be venue.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py
index 9b1723e1..22d810e1 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_video.py
@@ -25,7 +25,7 @@ class InlineQueryResultVideo(PyrogramType):
     Attributes:
         ID: ``0xb0700003``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be video.
 
diff --git a/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py b/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py
index 188063ec..73d7fb1d 100644
--- a/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py
+++ b/pyrogram/client/types/inline_mode/todo/inline_query_result_voice.py
@@ -25,7 +25,7 @@ class InlineQueryResultVoice(PyrogramType):
     Attributes:
         ID: ``0xb0700005``
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the result, must be voice.
 
diff --git a/pyrogram/client/types/input_media/input_media.py b/pyrogram/client/types/input_media/input_media.py
index 3062f136..8360862f 100644
--- a/pyrogram/client/types/input_media/input_media.py
+++ b/pyrogram/client/types/input_media/input_media.py
@@ -20,18 +20,20 @@ from ..pyrogram_type import PyrogramType
 
 
 class InputMedia(PyrogramType):
-    """This object represents the content of a media message to be sent. It should be one of:
+    """Content of a media message to be sent.
 
-    - :obj:`InputMediaAnimation `
-    - :obj:`InputMediaDocument `
-    - :obj:`InputMediaAudio `
-    - :obj:`InputMediaPhoto `
-    - :obj:`InputMediaVideo `
+    It should be one of:
+
+    - :obj:`InputMediaAnimation`
+    - :obj:`InputMediaDocument`
+    - :obj:`InputMediaAudio`
+    - :obj:`InputMediaPhoto`
+    - :obj:`InputMediaVideo`
     """
     __slots__ = ["media", "caption", "parse_mode"]
 
     def __init__(self, media: str, caption: str, parse_mode: str):
-        super().__init__(None)
+        super().__init__()
 
         self.media = media
         self.caption = caption
diff --git a/pyrogram/client/types/input_media/input_media_animation.py b/pyrogram/client/types/input_media/input_media_animation.py
index 6c06df7b..23fcb967 100644
--- a/pyrogram/client/types/input_media/input_media_animation.py
+++ b/pyrogram/client/types/input_media/input_media_animation.py
@@ -20,9 +20,9 @@ from . import InputMedia
 
 
 class InputMediaAnimation(InputMedia):
-    """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
+    """An animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent inside an album.
 
-    Args:
+    Parameters:
         media (``str``):
             Animation to send.
             Pass a file_id as string to send a file that exists on the Telegram servers or
@@ -38,9 +38,8 @@ class InputMediaAnimation(InputMedia):
             Caption of the animation to be sent, 0-1024 characters
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your caption. Defaults to "markdown".
 
         width (``int``, *optional*):
             Animation width.
diff --git a/pyrogram/client/types/input_media/input_media_audio.py b/pyrogram/client/types/input_media/input_media_audio.py
index 6b7659fe..3fb45d8f 100644
--- a/pyrogram/client/types/input_media/input_media_audio.py
+++ b/pyrogram/client/types/input_media/input_media_audio.py
@@ -20,10 +20,11 @@ from . import InputMedia
 
 
 class InputMediaAudio(InputMedia):
-    """This object represents an audio to be sent inside an album.
+    """An audio to be sent inside an album.
+
     It is intended to be used with :obj:`send_media_group() `.
 
-    Args:
+    Parameters:
         media (``str``):
             Audio to send.
             Pass a file_id as string to send an audio that exists on the Telegram servers or
@@ -39,9 +40,8 @@ class InputMediaAudio(InputMedia):
             Caption of the audio to be sent, 0-1024 characters
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your caption. Defaults to "markdown".
 
         duration (``int``, *optional*):
             Duration of the audio in seconds
diff --git a/pyrogram/client/types/input_media/input_media_document.py b/pyrogram/client/types/input_media/input_media_document.py
index a5d36261..0de8dedf 100644
--- a/pyrogram/client/types/input_media/input_media_document.py
+++ b/pyrogram/client/types/input_media/input_media_document.py
@@ -20,9 +20,9 @@ from . import InputMedia
 
 
 class InputMediaDocument(InputMedia):
-    """This object represents a general file to be sent.
+    """A generic file to be sent inside an album.
 
-    Args:
+    Parameters:
         media (``str``):
             File to send.
             Pass a file_id as string to send a file that exists on the Telegram servers or
@@ -38,9 +38,8 @@ class InputMediaDocument(InputMedia):
             Caption of the document to be sent, 0-1024 characters
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your caption. Defaults to "markdown".
     """
 
     __slots__ = ["thumb"]
diff --git a/pyrogram/client/types/input_media/input_media_photo.py b/pyrogram/client/types/input_media/input_media_photo.py
index e6bba03b..ce134af2 100644
--- a/pyrogram/client/types/input_media/input_media_photo.py
+++ b/pyrogram/client/types/input_media/input_media_photo.py
@@ -20,10 +20,10 @@ from . import InputMedia
 
 
 class InputMediaPhoto(InputMedia):
-    """This object represents a photo to be sent inside an album.
+    """A photo to be sent inside an album.
     It is intended to be used with :obj:`send_media_group() `.
 
-    Args:
+    Parameters:
         media (``str``):
             Photo to send.
             Pass a file_id as string to send a photo that exists on the Telegram servers or
@@ -34,9 +34,8 @@ class InputMediaPhoto(InputMedia):
             Caption of the photo to be sent, 0-1024 characters
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your caption. Defaults to "markdown".
     """
 
     __slots__ = []
diff --git a/pyrogram/client/types/input_media/input_media_video.py b/pyrogram/client/types/input_media/input_media_video.py
index 27d166bd..9764dd1a 100644
--- a/pyrogram/client/types/input_media/input_media_video.py
+++ b/pyrogram/client/types/input_media/input_media_video.py
@@ -20,10 +20,10 @@ from . import InputMedia
 
 
 class InputMediaVideo(InputMedia):
-    """This object represents a video to be sent inside an album.
+    """A video to be sent inside an album.
     It is intended to be used with :obj:`send_media_group() `.
 
-    Args:
+    Parameters:
         media (``str``):
             Video to send.
             Pass a file_id as string to send a video that exists on the Telegram servers or
@@ -40,9 +40,8 @@ class InputMediaVideo(InputMedia):
             Caption of the video to be sent, 0-1024 characters
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your caption. Defaults to "markdown".
 
         width (``int``, *optional*):
             Video width.
diff --git a/pyrogram/client/types/input_media/input_phone_contact.py b/pyrogram/client/types/input_media/input_phone_contact.py
index d2ac8012..0b6353b7 100644
--- a/pyrogram/client/types/input_media/input_phone_contact.py
+++ b/pyrogram/client/types/input_media/input_phone_contact.py
@@ -22,10 +22,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class InputPhoneContact(PyrogramType):
-    """This object represents a Phone Contact to be added in your Telegram address book.
+    """A Phone Contact to be added in your Telegram address book.
     It is intended to be used with :meth:`add_contacts() `
 
-    Args:
+    Parameters:
         phone (``str``):
             Contact's phone number
 
diff --git a/pyrogram/client/types/input_message_content/input_message_content.py b/pyrogram/client/types/input_message_content/input_message_content.py
index f3e238b8..50e068b7 100644
--- a/pyrogram/client/types/input_message_content/input_message_content.py
+++ b/pyrogram/client/types/input_message_content/input_message_content.py
@@ -24,7 +24,7 @@ from ..pyrogram_type import PyrogramType
 
 
 class InputMessageContent(PyrogramType):
-    """This object represents the content of a message to be sent as a result of an inline query.
+    """Content of a message to be sent as a result of an inline query.
 
     Pyrogram currently supports the following 4 types:
 
@@ -34,4 +34,4 @@ class InputMessageContent(PyrogramType):
     __slots__ = []
 
     def __init__(self):
-        super().__init__(None)
+        super().__init__()
diff --git a/pyrogram/client/types/input_message_content/input_text_message_content.py b/pyrogram/client/types/input_message_content/input_text_message_content.py
index dda1f3f3..004994de 100644
--- a/pyrogram/client/types/input_message_content/input_text_message_content.py
+++ b/pyrogram/client/types/input_message_content/input_text_message_content.py
@@ -22,16 +22,15 @@ from ...style import HTML, Markdown
 
 
 class InputTextMessageContent(InputMessageContent):
-    """This object represents the content of a text message to be sent as the result of an inline query.
+    """Content of a text message to be sent as the result of an inline query.
 
-    Args:
+    Parameters:
         message_text (``str``):
             Text of the message to be sent, 1-4096 characters.
 
         parse_mode (``str``, *optional*):
-            Use :obj:`MARKDOWN ` or :obj:`HTML `
-            if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-            Defaults to Markdown.
+            Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline URLs
+            in your message. Defaults to "markdown".
 
         disable_web_page_preview (``bool``, *optional*):
             Disables link previews for links in this message.
diff --git a/pyrogram/client/types/bots/__init__.py b/pyrogram/client/types/keyboards/__init__.py
similarity index 100%
rename from pyrogram/client/types/bots/__init__.py
rename to pyrogram/client/types/keyboards/__init__.py
diff --git a/pyrogram/client/types/bots/callback_game.py b/pyrogram/client/types/keyboards/callback_game.py
similarity index 92%
rename from pyrogram/client/types/bots/callback_game.py
rename to pyrogram/client/types/keyboards/callback_game.py
index fc2d9884..4fa43a30 100644
--- a/pyrogram/client/types/bots/callback_game.py
+++ b/pyrogram/client/types/keyboards/callback_game.py
@@ -20,7 +20,7 @@ from ..pyrogram_type import PyrogramType
 
 
 class CallbackGame(PyrogramType):
-    """A placeholder, currently holds no information.
+    """Placeholder, currently holds no information.
 
     Use BotFather to set up your game.
     """
@@ -28,4 +28,4 @@ class CallbackGame(PyrogramType):
     __slots__ = []
 
     def __init__(self):
-        super().__init__(None)
+        super().__init__()
diff --git a/pyrogram/client/types/bots/callback_query.py b/pyrogram/client/types/keyboards/callback_query.py
similarity index 85%
rename from pyrogram/client/types/bots/callback_query.py
rename to pyrogram/client/types/keyboards/callback_query.py
index c4d05b2d..52b8b013 100644
--- a/pyrogram/client/types/bots/callback_query.py
+++ b/pyrogram/client/types/keyboards/callback_query.py
@@ -18,6 +18,7 @@
 
 from base64 import b64encode
 from struct import pack
+from typing import Union
 
 import pyrogram
 from pyrogram.api import types
@@ -27,30 +28,31 @@ from ..user_and_chats import User
 
 
 class CallbackQuery(PyrogramType, Update):
-    """This object represents an incoming callback query from a callback button in an inline keyboard.
-    If the button that originated the query was attached to a message sent by the bot, the field message
-    will be present. If the button was attached to a message sent via the bot (in inline mode),
-    the field inline_message_id will be present. Exactly one of the fields data or game_short_name will be present.
+    """An incoming callback query from a callback button in an inline keyboard.
 
-    Args:
+    If the button that originated the query was attached to a message sent by the bot, the field *message*
+    will be present. If the button was attached to a message sent via the bot (in inline mode), the field
+    *inline_message_id* will be present. Exactly one of the fields *data* or *game_short_name* will be present.
+
+    Parameters:
         id (``str``):
             Unique identifier for this query.
 
-        from_user (:obj:`User `):
+        from_user (:obj:`User`):
             Sender.
 
         chat_instance (``str``, *optional*):
             Global identifier, uniquely corresponding to the chat to which the message with the callback button was
             sent. Useful for high scores in games.
 
-        message (:obj:`Message `, *optional*):
+        message (:obj:`Message`, *optional*):
             Message with the callback button that originated the query. Note that message content and message date will
             not be available if the message is too old.
 
         inline_message_id (``str``):
             Identifier of the message sent via the bot in inline mode, that originated the query.
 
-        data (``bytes``, *optional*):
+        data (``str`` | ``bytes``, *optional*):
             Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field.
 
         game_short_name (``str``, *optional*):
@@ -63,13 +65,13 @@ class CallbackQuery(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: str,
         from_user: User,
         chat_instance: str,
         message: "pyrogram.Message" = None,
         inline_message_id: str = None,
-        data: bytes = None,
+        data: Union[str, bytes] = None,
         game_short_name: str = None
     ):
         super().__init__(client)
@@ -79,7 +81,7 @@ class CallbackQuery(PyrogramType, Update):
         self.chat_instance = chat_instance
         self.message = message
         self.inline_message_id = inline_message_id
-        self.data = str(data, "utf-8")
+        self.data = data
         self.game_short_name = game_short_name
 
     @staticmethod
@@ -109,19 +111,26 @@ class CallbackQuery(PyrogramType, Update):
                 b"-_"
             ).decode().rstrip("=")
 
+        # Try to decode callback query data into string. If that fails, fallback to bytes instead of decoding by
+        # ignoring/replacing errors, this way, button clicks will still work.
+        try:
+            data = callback_query.data.decode()
+        except UnicodeDecodeError:
+            data = callback_query.data
+
         return CallbackQuery(
             id=str(callback_query.query_id),
             from_user=User._parse(client, users[callback_query.user_id]),
             message=message,
             inline_message_id=inline_message_id,
             chat_instance=str(callback_query.chat_instance),
-            data=callback_query.data,
+            data=data,
             game_short_name=callback_query.game_short_name,
             client=client
         )
 
     def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
-        """Bound method *answer* of :obj:`CallbackQuery `.
+        """Bound method *answer* of :obj:`CallbackQuery`.
 
         Use this method as a shortcut for:
 
@@ -138,7 +147,7 @@ class CallbackQuery(PyrogramType, Update):
 
                 callback_query.answer("Hello", show_alert=True)
 
-        Args:
+        Parameters:
             text (``str``):
                 Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters.
 
diff --git a/pyrogram/client/types/bots/force_reply.py b/pyrogram/client/types/keyboards/force_reply.py
similarity index 89%
rename from pyrogram/client/types/bots/force_reply.py
rename to pyrogram/client/types/keyboards/force_reply.py
index 12969742..5b263d03 100644
--- a/pyrogram/client/types/bots/force_reply.py
+++ b/pyrogram/client/types/keyboards/force_reply.py
@@ -21,13 +21,15 @@ from ..pyrogram_type import PyrogramType
 
 
 class ForceReply(PyrogramType):
-    """Upon receiving a message with this object, Telegram clients will display a reply interface to the user.
+    """Object used to force clients to show a reply interface.
+
+    Upon receiving a message with this object, Telegram clients will display a reply interface to the user.
 
     This acts as if the user has selected the bot's message and tapped "Reply".
     This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to
     sacrifice privacy mode.
 
-    Args:
+    Parameters:
         selective (``bool``, *optional*):
             Use this parameter if you want to force reply from specific users only. Targets:
             1) users that are @mentioned in the text of the Message object;
@@ -40,7 +42,7 @@ class ForceReply(PyrogramType):
         self,
         selective: bool = None
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.selective = selective
 
diff --git a/pyrogram/client/types/bots/game_high_score.py b/pyrogram/client/types/keyboards/game_high_score.py
similarity index 94%
rename from pyrogram/client/types/bots/game_high_score.py
rename to pyrogram/client/types/keyboards/game_high_score.py
index da6b2881..56389b17 100644
--- a/pyrogram/client/types/bots/game_high_score.py
+++ b/pyrogram/client/types/keyboards/game_high_score.py
@@ -24,9 +24,9 @@ from pyrogram.client.types.user_and_chats import User
 
 
 class GameHighScore(PyrogramType):
-    """This object represents one row of the high scores table for a game.
+    """One row of the high scores table for a game.
 
-    Args:
+    Parameters:
         user (:obj:`User`):
             User.
 
@@ -42,7 +42,7 @@ class GameHighScore(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         user: User,
         score: int,
         position: int = None
diff --git a/pyrogram/client/types/bots/game_high_scores.py b/pyrogram/client/types/keyboards/game_high_scores.py
similarity index 89%
rename from pyrogram/client/types/bots/game_high_scores.py
rename to pyrogram/client/types/keyboards/game_high_scores.py
index 3c197969..8183b9b0 100644
--- a/pyrogram/client/types/bots/game_high_scores.py
+++ b/pyrogram/client/types/keyboards/game_high_scores.py
@@ -25,13 +25,13 @@ from .game_high_score import GameHighScore
 
 
 class GameHighScores(PyrogramType):
-    """This object represents the high scores table for a game.
+    """The high scores table for a game.
 
-    Args:
+    Parameters:
         total_count (``int``):
             Total number of scores the target game has.
 
-        game_high_scores (List of :obj:`GameHighScore `):
+        game_high_scores (List of :obj:`GameHighScore`):
             Game scores.
     """
 
@@ -40,7 +40,7 @@ class GameHighScores(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         total_count: int,
         game_high_scores: List[GameHighScore]
     ):
diff --git a/pyrogram/client/types/bots/inline_keyboard_button.py b/pyrogram/client/types/keyboards/inline_keyboard_button.py
similarity index 84%
rename from pyrogram/client/types/bots/inline_keyboard_button.py
rename to pyrogram/client/types/keyboards/inline_keyboard_button.py
index 7e4b0690..a83e27f5 100644
--- a/pyrogram/client/types/bots/inline_keyboard_button.py
+++ b/pyrogram/client/types/keyboards/inline_keyboard_button.py
@@ -28,13 +28,15 @@ from ..pyrogram_type import PyrogramType
 
 
 class InlineKeyboardButton(PyrogramType):
-    """This object represents one button of an inline keyboard. You must use exactly one of the optional fields.
+    """One button of an inline keyboard.
 
-    Args:
+    You must use exactly one of the optional fields.
+
+    Parameters:
         text (``str``):
             Label text on the button.
 
-        callback_data (``bytes``, *optional*):
+        callback_data (``str`` | ``bytes``, *optional*):
             Data to be sent in a callback query to the bot when button is pressed, 1-64 bytes.
 
         url (``str``, *optional*):
@@ -70,11 +72,11 @@ class InlineKeyboardButton(PyrogramType):
         switch_inline_query_current_chat: str = None,
         callback_game: CallbackGame = None
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.text = str(text)
         self.url = url
-        self.callback_data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data
+        self.callback_data = callback_data
         self.switch_inline_query = switch_inline_query
         self.switch_inline_query_current_chat = switch_inline_query_current_chat
         self.callback_game = callback_game
@@ -89,9 +91,16 @@ class InlineKeyboardButton(PyrogramType):
             )
 
         if isinstance(o, KeyboardButtonCallback):
+            # Try decode data to keep it as string, but if fails, fallback to bytes so we don't lose any information,
+            # instead of decoding by ignoring/replacing errors.
+            try:
+                data = o.data.decode()
+            except UnicodeDecodeError:
+                data = o.data
+
             return InlineKeyboardButton(
                 text=o.text,
-                callback_data=o.data
+                callback_data=data
             )
 
         if isinstance(o, KeyboardButtonSwitchInline):
@@ -114,7 +123,9 @@ class InlineKeyboardButton(PyrogramType):
 
     def write(self):
         if self.callback_data is not None:
-            return KeyboardButtonCallback(text=self.text, data=self.callback_data)
+            # Telegram only wants bytes, but we are allowed to pass strings too, for convenience.
+            data = bytes(self.callback_data, "utf-8") if isinstance(self.callback_data, str) else self.callback_data
+            return KeyboardButtonCallback(text=self.text, data=data)
 
         if self.url is not None:
             return KeyboardButtonUrl(text=self.text, url=self.url)
diff --git a/pyrogram/client/types/bots/inline_keyboard_markup.py b/pyrogram/client/types/keyboards/inline_keyboard_markup.py
similarity index 91%
rename from pyrogram/client/types/bots/inline_keyboard_markup.py
rename to pyrogram/client/types/keyboards/inline_keyboard_markup.py
index 54476c5e..c7230eaf 100644
--- a/pyrogram/client/types/bots/inline_keyboard_markup.py
+++ b/pyrogram/client/types/keyboards/inline_keyboard_markup.py
@@ -24,10 +24,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class InlineKeyboardMarkup(PyrogramType):
-    """This object represents an inline keyboard that appears right next to the message it belongs to.
+    """An inline keyboard that appears right next to the message it belongs to.
 
-    Args:
-        inline_keyboard (List of List of :obj:`InlineKeyboardButton `):
+    Parameters:
+        inline_keyboard (List of List of :obj:`InlineKeyboardButton`):
             List of button rows, each represented by a List of InlineKeyboardButton objects.
     """
 
@@ -37,7 +37,7 @@ class InlineKeyboardMarkup(PyrogramType):
         self,
         inline_keyboard: List[List[InlineKeyboardButton]]
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.inline_keyboard = inline_keyboard
 
diff --git a/pyrogram/client/types/bots/keyboard_button.py b/pyrogram/client/types/keyboards/keyboard_button.py
similarity index 96%
rename from pyrogram/client/types/bots/keyboard_button.py
rename to pyrogram/client/types/keyboards/keyboard_button.py
index 477442cc..93d2e5ef 100644
--- a/pyrogram/client/types/bots/keyboard_button.py
+++ b/pyrogram/client/types/keyboards/keyboard_button.py
@@ -22,11 +22,11 @@ from ..pyrogram_type import PyrogramType
 
 
 class KeyboardButton(PyrogramType):
-    """This object represents one button of the reply keyboard.
+    """One button of the reply keyboard.
     For simple text buttons String can be used instead of this object to specify text of the button.
     Optional fields are mutually exclusive.
 
-    Args:
+    Parameters:
         text (``str``):
             Text of the button. If none of the optional fields are used, it will be sent as a message when
             the button is pressed.
@@ -48,7 +48,7 @@ class KeyboardButton(PyrogramType):
         request_contact: bool = None,
         request_location: bool = None
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.text = str(text)
         self.request_contact = request_contact
diff --git a/pyrogram/client/types/bots/reply_keyboard_markup.py b/pyrogram/client/types/keyboards/reply_keyboard_markup.py
similarity index 95%
rename from pyrogram/client/types/bots/reply_keyboard_markup.py
rename to pyrogram/client/types/keyboards/reply_keyboard_markup.py
index b0216803..c4b37b7c 100644
--- a/pyrogram/client/types/bots/reply_keyboard_markup.py
+++ b/pyrogram/client/types/keyboards/reply_keyboard_markup.py
@@ -25,10 +25,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class ReplyKeyboardMarkup(PyrogramType):
-    """This object represents a custom keyboard with reply options.
+    """A custom keyboard with reply options.
 
-    Args:
-        keyboard (List of List of :obj:`KeyboardButton `):
+    Parameters:
+        keyboard (List of List of :obj:`KeyboardButton`):
             List of button rows, each represented by a List of KeyboardButton objects.
 
         resize_keyboard (``bool``, *optional*):
@@ -58,7 +58,7 @@ class ReplyKeyboardMarkup(PyrogramType):
         one_time_keyboard: bool = None,
         selective: bool = None
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.keyboard = keyboard
         self.resize_keyboard = resize_keyboard
diff --git a/pyrogram/client/types/bots/reply_keyboard_remove.py b/pyrogram/client/types/keyboards/reply_keyboard_remove.py
similarity index 79%
rename from pyrogram/client/types/bots/reply_keyboard_remove.py
rename to pyrogram/client/types/keyboards/reply_keyboard_remove.py
index 75f2a7b5..9d6eb7d5 100644
--- a/pyrogram/client/types/bots/reply_keyboard_remove.py
+++ b/pyrogram/client/types/keyboards/reply_keyboard_remove.py
@@ -21,11 +21,14 @@ from ..pyrogram_type import PyrogramType
 
 
 class ReplyKeyboardRemove(PyrogramType):
-    """Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and display the default letter-keyboard.
-    By default, custom keyboards are displayed until a new keyboard is sent by a bot. An exception is made for one-time
-    keyboards that are hidden immediately after the user presses a button (see ReplyKeyboardMarkup).
+    """Object used to tell clients to remove a bot keyboard.
 
-    Args:
+    Upon receiving a message with this object, Telegram clients will remove the current custom keyboard and display
+    the default letter-keyboard. By default, custom keyboards are displayed until a new keyboard is sent by a bot.
+    An exception is made for one-time keyboards that are hidden immediately after the user presses a button
+    (see ReplyKeyboardMarkup).
+
+    Parameters:
         selective (``bool``, *optional*):
             Use this parameter if you want to remove the keyboard for specific users only. Targets:
             1) users that are @mentioned in the text of the Message object;
@@ -40,7 +43,7 @@ class ReplyKeyboardRemove(PyrogramType):
         self,
         selective: bool = None
     ):
-        super().__init__(None)
+        super().__init__()
 
         self.selective = selective
 
diff --git a/pyrogram/client/types/messages_and_media/animation.py b/pyrogram/client/types/messages_and_media/animation.py
index 21a01e0f..cd6e03ab 100644
--- a/pyrogram/client/types/messages_and_media/animation.py
+++ b/pyrogram/client/types/messages_and_media/animation.py
@@ -26,9 +26,9 @@ from ...ext.utils import encode
 
 
 class Animation(PyrogramType):
-    """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound).
+    """An animation file (GIF or H.264/MPEG-4 AVC video without sound).
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -62,7 +62,7 @@ class Animation(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         width: int,
         height: int,
diff --git a/pyrogram/client/types/messages_and_media/audio.py b/pyrogram/client/types/messages_and_media/audio.py
index db49f2eb..76181a22 100644
--- a/pyrogram/client/types/messages_and_media/audio.py
+++ b/pyrogram/client/types/messages_and_media/audio.py
@@ -26,16 +26,16 @@ from ...ext.utils import encode
 
 
 class Audio(PyrogramType):
-    """This object represents an audio file to be treated as music by the Telegram clients.
+    """An audio file to be treated as music by the Telegram clients.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
         duration (``int``):
             Duration of the audio in seconds as defined by sender.
 
-        thumb (:obj:`PhotoSize `, *optional*):
+        thumb (:obj:`PhotoSize`, *optional*):
             Thumbnail of the music file album cover.
 
         file_name (``str``, *optional*):
@@ -62,7 +62,7 @@ class Audio(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         duration: int,
         thumb: PhotoSize = None,
diff --git a/pyrogram/client/types/messages_and_media/contact.py b/pyrogram/client/types/messages_and_media/contact.py
index 5abe5319..9205304e 100644
--- a/pyrogram/client/types/messages_and_media/contact.py
+++ b/pyrogram/client/types/messages_and_media/contact.py
@@ -23,9 +23,9 @@ from ..pyrogram_type import PyrogramType
 
 
 class Contact(PyrogramType):
-    """This object represents a phone contact.
+    """A phone contact.
 
-    Args:
+    Parameters:
         phone_number (``str``):
             Contact's phone number.
 
@@ -47,7 +47,7 @@ class Contact(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         phone_number: str,
         first_name: str,
         last_name: str = None,
diff --git a/pyrogram/client/types/messages_and_media/document.py b/pyrogram/client/types/messages_and_media/document.py
index f3ccc4f8..394d5e14 100644
--- a/pyrogram/client/types/messages_and_media/document.py
+++ b/pyrogram/client/types/messages_and_media/document.py
@@ -26,13 +26,13 @@ from ...ext.utils import encode
 
 
 class Document(PyrogramType):
-    """This object represents a general file (as opposed to photos, voice messages, audio files, ...).
+    """A generic file (as opposed to photos, voice messages, audio files, ...).
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique file identifier.
 
-        thumb (:obj:`PhotoSize `, *optional*):
+        thumb (:obj:`PhotoSize`, *optional*):
             Document thumbnail as defined by sender.
 
         file_name (``str``, *optional*):
@@ -53,7 +53,7 @@ class Document(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         thumb: PhotoSize = None,
         file_name: str = None,
diff --git a/pyrogram/client/types/messages_and_media/game.py b/pyrogram/client/types/messages_and_media/game.py
index cf0b4fa6..1377173a 100644
--- a/pyrogram/client/types/messages_and_media/game.py
+++ b/pyrogram/client/types/messages_and_media/game.py
@@ -24,10 +24,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class Game(PyrogramType):
-    """This object represents a game.
+    """A game.
     Use BotFather to create and edit games, their short names will act as unique identifiers.
 
-    Args:
+    Parameters:
         id (``int``):
             Unique identifier of the game.
 
@@ -40,10 +40,10 @@ class Game(PyrogramType):
         description (``str``):
             Description of the game.
 
-        photo (:obj:`Photo `):
+        photo (:obj:`Photo`):
             Photo that will be displayed in the game message in chats.
 
-        animation (:obj:`Animation `, *optional*):
+        animation (:obj:`Animation`, *optional*):
             Animation that will be displayed in the game message in chats.
             Upload via BotFather.
     """
@@ -53,7 +53,7 @@ class Game(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: int,
         title: str,
         short_name: str,
diff --git a/pyrogram/client/types/messages_and_media/location.py b/pyrogram/client/types/messages_and_media/location.py
index 3a7f6d38..55def7a0 100644
--- a/pyrogram/client/types/messages_and_media/location.py
+++ b/pyrogram/client/types/messages_and_media/location.py
@@ -23,9 +23,9 @@ from ..pyrogram_type import PyrogramType
 
 
 class Location(PyrogramType):
-    """This object represents a point on the map.
+    """A point on the map.
 
-    Args:
+    Parameters:
         longitude (``float``):
             Longitude as defined by sender.
 
@@ -38,7 +38,7 @@ class Location(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         longitude: float,
         latitude: float
     ):
diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/client/types/messages_and_media/message.py
index c5678e3f..ebb5480a 100644
--- a/pyrogram/client/types/messages_and_media/message.py
+++ b/pyrogram/client/types/messages_and_media/message.py
@@ -21,9 +21,8 @@ from typing import List, Match, Union
 
 import pyrogram
 from pyrogram.api import types
-from pyrogram.errors import MessageIdsEmpty
-from pyrogram.client.ext import ChatAction, ParseMode
 from pyrogram.client.types.input_media import InputMedia
+from pyrogram.errors import MessageIdsEmpty
 from .contact import Contact
 from .location import Location
 from .message_entity import MessageEntity
@@ -61,28 +60,28 @@ class Str(str):
 
 
 class Message(PyrogramType, Update):
-    """This object represents a message.
+    """A message.
 
-    Args:
+    Parameters:
         message_id (``int``):
             Unique message identifier inside this chat.
 
         date (``int``, *optional*):
             Date the message was sent in Unix time.
 
-        chat (:obj:`Chat `, *optional*):
+        chat (:obj:`Chat`, *optional*):
             Conversation the message belongs to.
 
-        from_user (:obj:`User `, *optional*):
+        from_user (:obj:`User`, *optional*):
             Sender, empty for messages sent to channels.
 
-        forward_from (:obj:`User `, *optional*):
+        forward_from (:obj:`User`, *optional*):
             For forwarded messages, sender of the original message.
 
         forward_sender_name (``str``, *optional*):
             For messages forwarded from users who have hidden their accounts, name of the user.
 
-        forward_from_chat (:obj:`Chat `, *optional*):
+        forward_from_chat (:obj:`Chat`, *optional*):
             For messages forwarded from channels, information about the original channel.
 
         forward_from_message_id (``int``, *optional*):
@@ -94,7 +93,7 @@ class Message(PyrogramType, Update):
         forward_date (``int``, *optional*):
             For forwarded messages, date the original message was sent in Unix time.
 
-        reply_to_message (:obj:`Message `, *optional*):
+        reply_to_message (:obj:`Message`, *optional*):
             For replies, the original message. Note that the Message object in this field will not contain
             further reply_to_message fields even if it itself is a reply.
 
@@ -131,38 +130,38 @@ class Message(PyrogramType, Update):
             *text.html* to get the marked up message text. In case there is no entity, the fields
             will contain the same text as *text*.
 
-        entities (List of :obj:`MessageEntity `, *optional*):
+        entities (List of :obj:`MessageEntity`, *optional*):
             For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text.
 
-        caption_entities (List of :obj:`MessageEntity `, *optional*):
+        caption_entities (List of :obj:`MessageEntity`, *optional*):
             For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear
             in the caption.
 
-        audio (:obj:`Audio `, *optional*):
+        audio (:obj:`Audio`, *optional*):
             Message is an audio file, information about the file.
 
-        document (:obj:`Document `, *optional*):
+        document (:obj:`Document`, *optional*):
             Message is a general file, information about the file.
 
-        photo (:obj:`Photo `, *optional*):
+        photo (:obj:`Photo`, *optional*):
             Message is a photo, information about the photo.
 
-        sticker (:obj:`Sticker `, *optional*):
+        sticker (:obj:`Sticker`, *optional*):
             Message is a sticker, information about the sticker.
 
-        animation (:obj:`Animation `, *optional*):
+        animation (:obj:`Animation`, *optional*):
             Message is an animation, information about the animation.
 
-        game (:obj:`Game `, *optional*):
+        game (:obj:`Game`, *optional*):
             Message is a game, information about the game.
 
-        video (:obj:`Video `, *optional*):
+        video (:obj:`Video`, *optional*):
             Message is a video, information about the video.
 
-        voice (:obj:`Voice `, *optional*):
+        voice (:obj:`Voice`, *optional*):
             Message is a voice message, information about the file.
 
-        video_note (:obj:`VideoNote `, *optional*):
+        video_note (:obj:`VideoNote`, *optional*):
             Message is a video note, information about the video message.
 
         caption (``str``, *optional*):
@@ -171,13 +170,13 @@ class Message(PyrogramType, Update):
             *caption.html* to get the marked up caption text. In case there is no caption entity, the fields
             will contain the same text as *caption*.
 
-        contact (:obj:`Contact `, *optional*):
+        contact (:obj:`Contact`, *optional*):
             Message is a shared contact, information about the contact.
 
-        location (:obj:`Location `, *optional*):
+        location (:obj:`Location`, *optional*):
             Message is a shared location, information about the location.
 
-        venue (:obj:`Venue `, *optional*):
+        venue (:obj:`Venue`, *optional*):
             Message is a venue, information about the venue.
 
         web_page (``bool``, *optional*):
@@ -186,20 +185,20 @@ class Message(PyrogramType, Update):
             web page preview. In future versions this property could turn into a full web page object that contains
             more details.
 
-        poll (:obj:`Poll `, *optional*):
+        poll (:obj:`Poll`, *optional*):
             Message is a native poll, information about the poll.
 
-        new_chat_members (List of :obj:`User `, *optional*):
+        new_chat_members (List of :obj:`User`, *optional*):
             New members that were added to the group or supergroup and information about them
             (the bot itself may be one of these members).
 
-        left_chat_member (:obj:`User `, *optional*):
+        left_chat_member (:obj:`User`, *optional*):
             A member was removed from the group, information about them (this member may be the bot itself).
 
         new_chat_title (``str``, *optional*):
             A chat title was changed to this value.
 
-        new_chat_photo (:obj:`Photo `, *optional*):
+        new_chat_photo (:obj:`Photo`, *optional*):
             A chat photo was change to this value.
 
         delete_chat_photo (``bool``, *optional*):
@@ -232,19 +231,19 @@ class Message(PyrogramType, Update):
             in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float
             type are safe for storing this identifier.
 
-        pinned_message (:obj:`Message `, *optional*):
+        pinned_message (:obj:`Message`, *optional*):
             Specified message was pinned.
             Note that the Message object in this field will not contain further reply_to_message fields even if it
             is itself a reply.
 
-        game_high_score (:obj:`GameHighScore `, *optional*):
+        game_high_score (:obj:`GameHighScore`, *optional*):
             The game score for a user.
             The reply_to_message field will contain the game Message.
 
         views (``int``, *optional*):
             Channel post views.
 
-        via_bot (:obj:`User `):
+        via_bot (:obj:`User`):
             The information of the bot that generated the message from an inline query of a user.
 
         outgoing (``bool``, *optional*):
@@ -283,7 +282,7 @@ class Message(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         message_id: int,
         date: int = None,
         chat: Chat = None,
@@ -662,7 +661,7 @@ class Message(PyrogramType, Update):
         reply_to_message_id: int = None,
         reply_markup=None
     ) -> "Message":
-        """Bound method *reply* of :obj:`Message `.
+        """Bound method *reply* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -679,7 +678,7 @@ class Message(PyrogramType, Update):
 
                 message.reply("hello", quote=True)
 
-        Args:
+        Parameters:
             text (``str``):
                 Text of the message to be sent.
 
@@ -689,9 +688,8 @@ class Message(PyrogramType, Update):
                 Defaults to ``True`` in group chats and ``False`` in private chats.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your message. Defaults to "markdown".
 
             disable_web_page_preview (``bool``, *optional*):
                 Disables link previews for links in this message.
@@ -711,7 +709,7 @@ class Message(PyrogramType, Update):
             On success, the sent Message is returned.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -750,7 +748,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_animation* of :obj:`Message `.
+        """Bound method *reply_animation* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -766,7 +764,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_animation(animation)
 
-        Args:
+        Parameters:
             animation (``str``):
                 Animation to send.
                 Pass a file_id as string to send an animation that exists on the Telegram servers,
@@ -782,9 +780,8 @@ class Message(PyrogramType, Update):
                 Animation caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of sent animation in seconds.
@@ -822,7 +819,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -836,11 +833,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -885,7 +882,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_audio* of :obj:`Message `.
+        """Bound method *reply_audio* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -901,7 +898,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_audio(audio)
 
-        Args:
+        Parameters:
             audio (``str``):
                 Audio file to send.
                 Pass a file_id as string to send an audio file that exists on the Telegram servers,
@@ -917,9 +914,8 @@ class Message(PyrogramType, Update):
                 Audio caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of the audio in seconds.
@@ -957,7 +953,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -971,11 +967,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1014,7 +1010,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_cached_media* of :obj:`Message `.
+        """Bound method *reply_cached_media* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1030,7 +1026,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_cached_media(file_id)
 
-        Args:
+        Parameters:
             file_id (``str``):
                 Media to send.
                 Pass a file_id as string to send a media that exists on the Telegram servers.
@@ -1044,9 +1040,8 @@ class Message(PyrogramType, Update):
                 Media caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             disable_notification (``bool``, *optional*):
                 Sends the message silently.
@@ -1060,10 +1055,10 @@ class Message(PyrogramType, Update):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1081,12 +1076,8 @@ class Message(PyrogramType, Update):
             reply_markup=reply_markup
         )
 
-    async def reply_chat_action(
-        self,
-        action: Union[ChatAction, str],
-        progress: int = 0
-    ) -> "Message":
-        """Bound method *reply_chat_action* of :obj:`Message `.
+    async def reply_chat_action(self, action: str) -> bool:
+        """Bound method *reply_chat_action* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1102,28 +1093,25 @@ class Message(PyrogramType, Update):
 
                 message.reply_chat_action("typing")
 
-        Args:
-            action (:obj:`ChatAction ` | ``str``):
-                Type of action to broadcast.
-                Choose one from the :class:`ChatAction ` enumeration,
-                depending on what the user is about to receive.
-                You can also provide a string (e.g. "typing", "upload_photo", "record_audio", ...).
-
-            progress (``int``, *optional*):
-                Progress of the upload process.
-                Currently useless because official clients don't seem to be handling this.
+        Parameters:
+            action (``str``):
+                Type of action to broadcast. Choose one, depending on what the user is about to receive: *"typing"* for
+                text messages, *"upload_photo"* for photos, *"record_video"* or *"upload_video"* for videos,
+                *"record_audio"* or *"upload_audio"* for audio files, *"upload_document"* for general files,
+                *"find_location"* for location data, *"record_video_note"* or *"upload_video_note"* for video notes,
+                *"choose_contact"* for contacts, *"playing"* for games or *"cancel"* to cancel any chat action currently
+                displayed.
 
         Returns:
-            On success, True is returned.
+            ``bool``: On success, True is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
-            ``ValueError`` if the provided string is not a valid ChatAction.
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case the provided string is not a valid chat action.
         """
         return await self._client.send_chat_action(
             chat_id=self.chat.id,
-            action=action,
-            progress=progress
+            action=action
         )
 
     async def reply_contact(
@@ -1142,7 +1130,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_contact* of :obj:`Message `.
+        """Bound method *reply_contact* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1159,7 +1147,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_contact(phone_number, "Dan")
 
-        Args:
+        Parameters:
             phone_number (``str``):
                 Contact's phone number.
 
@@ -1189,10 +1177,10 @@ class Message(PyrogramType, Update):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1229,7 +1217,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_document* of :obj:`Message `.
+        """Bound method *reply_document* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1245,7 +1233,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_document(document)
 
-        Args:
+        Parameters:
             document (``str``):
                 File to send.
                 Pass a file_id as string to send a file that exists on the Telegram servers,
@@ -1267,9 +1255,8 @@ class Message(PyrogramType, Update):
                 Document caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             disable_notification (``bool``, *optional*):
                 Sends the message silently.
@@ -1292,7 +1279,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -1306,11 +1293,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1344,7 +1331,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_game* of :obj:`Message `.
+        """Bound method *reply_game* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1360,7 +1347,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_game("lumberjack")
 
-        Args:
+        Parameters:
             game_short_name (``str``):
                 Short name of the game, serves as the unique identifier for the game. Set up your games via Botfather.
 
@@ -1384,7 +1371,7 @@ class Message(PyrogramType, Update):
             On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1409,7 +1396,7 @@ class Message(PyrogramType, Update):
         reply_to_message_id: int = None,
         hide_via: bool = None
     ) -> "Message":
-        """Bound method *reply_inline_bot_result* of :obj:`Message `.
+        """Bound method *reply_inline_bot_result* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1426,7 +1413,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_inline_bot_result(query_id, result_id)
 
-        Args:
+        Parameters:
             query_id (``int``):
                 Unique identifier for the answered query.
 
@@ -1452,7 +1439,7 @@ class Message(PyrogramType, Update):
             On success, the sent Message is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1483,7 +1470,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_location* of :obj:`Message `.
+        """Bound method *reply_location* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1500,7 +1487,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_location(41.890251, 12.492373)
 
-        Args:
+        Parameters:
             latitude (``float``):
                 Latitude of the location.
 
@@ -1524,10 +1511,10 @@ class Message(PyrogramType, Update):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1551,7 +1538,7 @@ class Message(PyrogramType, Update):
         disable_notification: bool = None,
         reply_to_message_id: int = None
     ) -> "Message":
-        """Bound method *reply_media_group* of :obj:`Message `.
+        """Bound method *reply_media_group* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1567,7 +1554,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_media_group(list_of_media)
 
-        Args:
+        Parameters:
             media (``list``):
                 A list containing either :obj:`InputMediaPhoto ` or
                 :obj:`InputMediaVideo ` objects
@@ -1586,11 +1573,11 @@ class Message(PyrogramType, Update):
                 If the message is a reply, ID of the original message.
 
         Returns:
-            On success, a :obj:`Messages ` object is returned containing all the
+            On success, a :obj:`Messages` object is returned containing all the
             single messages sent.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1623,7 +1610,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_photo* of :obj:`Message `.
+        """Bound method *reply_photo* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1639,7 +1626,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_photo(photo)
 
-        Args:
+        Parameters:
             photo (``str``):
                 Photo to send.
                 Pass a file_id as string to send a photo that exists on the Telegram servers,
@@ -1655,9 +1642,8 @@ class Message(PyrogramType, Update):
                 Photo caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             ttl_seconds (``int``, *optional*):
                 Self-Destruct Timer.
@@ -1685,7 +1671,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -1699,11 +1685,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1738,7 +1724,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_poll* of :obj:`Message `.
+        """Bound method *reply_poll* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1755,7 +1741,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_poll("Is Pyrogram the best?", ["Yes", "Yes"])
 
-        Args:
+        Parameters:
             question (``str``):
                 The poll question, as string.
 
@@ -1779,10 +1765,10 @@ class Message(PyrogramType, Update):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1814,7 +1800,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_sticker* of :obj:`Message `.
+        """Bound method *reply_sticker* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1830,7 +1816,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_sticker(sticker)
 
-        Args:
+        Parameters:
             sticker (``str``):
                 Sticker to send.
                 Pass a file_id as string to send a sticker that exists on the Telegram servers,
@@ -1863,7 +1849,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -1877,11 +1863,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -1917,7 +1903,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *reply_venue* of :obj:`Message `.
+        """Bound method *reply_venue* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -1936,7 +1922,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_venue(41.890251, 12.492373, "Coliseum", "Piazza del Colosseo, 1, 00184 Roma RM")
 
-        Args:
+        Parameters:
             latitude (``float``):
                 Latitude of the venue.
 
@@ -1973,10 +1959,10 @@ class Message(PyrogramType, Update):
                 instructions to remove reply keyboard or to force a reply from the user.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -2019,7 +2005,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_video* of :obj:`Message `.
+        """Bound method *reply_video* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2035,7 +2021,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_video(video)
 
-        Args:
+        Parameters:
             video (``str``):
                 Video to send.
                 Pass a file_id as string to send a video that exists on the Telegram servers,
@@ -2051,9 +2037,8 @@ class Message(PyrogramType, Update):
                 Video caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of sent video in seconds.
@@ -2094,7 +2079,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -2108,11 +2093,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -2155,7 +2140,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_video_note* of :obj:`Message `.
+        """Bound method *reply_video_note* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2171,7 +2156,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_video_note(video_note)
 
-        Args:
+        Parameters:
             video_note (``str``):
                 Video note to send.
                 Pass a file_id as string to send a video note that exists on the Telegram servers, or
@@ -2216,7 +2201,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -2230,11 +2215,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -2273,7 +2258,7 @@ class Message(PyrogramType, Update):
         progress: callable = None,
         progress_args: tuple = ()
     ) -> "Message":
-        """Bound method *reply_voice* of :obj:`Message `.
+        """Bound method *reply_voice* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2289,7 +2274,7 @@ class Message(PyrogramType, Update):
 
                 message.reply_voice(voice)
 
-        Args:
+        Parameters:
             voice (``str``):
                 Audio file to send.
                 Pass a file_id as string to send an audio that exists on the Telegram servers,
@@ -2305,9 +2290,8 @@ class Message(PyrogramType, Update):
                 Voice message caption, 0-1024 characters.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your caption.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your caption. Defaults to "markdown".
 
             duration (``int``, *optional*):
                 Duration of the voice message in seconds.
@@ -2333,7 +2317,7 @@ class Message(PyrogramType, Update):
                 a chat_id and a message_id in order to edit a message with the updated progress.
 
         Other Parameters:
-            client (:obj:`Client `):
+            client (:obj:`Client`):
                 The Client itself, useful when you want to call other API methods inside the callback function.
 
             current (``int``):
@@ -2347,11 +2331,11 @@ class Message(PyrogramType, Update):
                 You can either keep *\*args* or add every single extra argument in your function signature.
 
         Returns:
-            On success, the sent :obj:`Message ` is returned.
+            On success, the sent :obj:`Message` is returned.
             In case the upload is deliberately stopped with :meth:`stop_transmission`, None is returned instead.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         if quote is None:
             quote = self.chat.type != "private"
@@ -2384,7 +2368,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *edit* of :obj:`Message `
+        """Bound method *edit* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2401,14 +2385,13 @@ class Message(PyrogramType, Update):
 
                 message.edit("hello")
 
-        Args:
+        Parameters:
             text (``str``):
                 New text of the message.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your message. Defaults to "markdown".
 
             disable_web_page_preview (``bool``, *optional*):
                 Disables link previews for links in this message.
@@ -2417,10 +2400,10 @@ class Message(PyrogramType, Update):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            On success, the edited :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.edit_message_text(
             chat_id=self.chat.id,
@@ -2442,7 +2425,7 @@ class Message(PyrogramType, Update):
             "pyrogram.ForceReply"
         ] = None
     ) -> "Message":
-        """Bound method *edit_caption* of :obj:`Message `
+        """Bound method *edit_caption* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2459,23 +2442,22 @@ class Message(PyrogramType, Update):
 
                 message.edit_caption("hello")
 
-        Args:
+        Parameters:
             caption (``str``):
                 New caption of the message.
 
             parse_mode (``str``, *optional*):
-                Use :obj:`MARKDOWN ` or :obj:`HTML `
-                if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
-                Defaults to Markdown.
+                Pass "markdown" or "html" if you want Telegram apps to show bold, italic, fixed-width text or inline
+                URLs in your message. Defaults to "markdown".
 
             reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            On success, the edited :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.edit_message_caption(
             chat_id=self.chat.id,
@@ -2486,7 +2468,7 @@ class Message(PyrogramType, Update):
         )
 
     async def edit_media(self, media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "Message":
-        """Bound method *edit_media* of :obj:`Message `
+        """Bound method *edit_media* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2503,7 +2485,7 @@ class Message(PyrogramType, Update):
 
                 message.edit_media(media)
 
-        Args:
+        Parameters:
             media (:obj:`InputMediaAnimation` | :obj:`InputMediaAudio` | :obj:`InputMediaDocument` | :obj:`InputMediaPhoto` | :obj:`InputMediaVideo`)
                 One of the InputMedia objects describing an animation, audio, document, photo or video.
 
@@ -2511,10 +2493,10 @@ class Message(PyrogramType, Update):
                 An InlineKeyboardMarkup object.
 
         Returns:
-            On success, the edited :obj:`Message ` is returned.
+            On success, the edited :obj:`Message` is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.edit_message_media(
             chat_id=self.chat.id,
@@ -2524,7 +2506,7 @@ class Message(PyrogramType, Update):
         )
 
     async def edit_reply_markup(self, reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "Message":
-        """Bound method *edit_reply_markup* of :obj:`Message `
+        """Bound method *edit_reply_markup* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2541,16 +2523,16 @@ class Message(PyrogramType, Update):
 
                 message.edit_reply_markup(inline_reply_markup)
 
-        Args:
+        Parameters:
             reply_markup (:obj:`InlineKeyboardMarkup`):
                 An InlineKeyboardMarkup object.
 
         Returns:
             On success, if edited message is sent by the bot, the edited
-            :obj:`Message ` is returned, otherwise True is returned.
+            :obj:`Message` is returned, otherwise True is returned.
 
         Raises:
-            :class:`RPCError ` in case of a Telegram RPC error.
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.edit_message_reply_markup(
             chat_id=self.chat.id,
@@ -2565,7 +2547,7 @@ class Message(PyrogramType, Update):
         as_copy: bool = False,
         remove_caption: bool = False
     ) -> "Message":
-        """Bound method *forward* of :obj:`Message `.
+        """Bound method *forward* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2582,7 +2564,7 @@ class Message(PyrogramType, Update):
 
                 message.forward(chat_id)
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -2605,7 +2587,7 @@ class Message(PyrogramType, Update):
             On success, the forwarded Message is returned.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         if as_copy:
             if self.service:
@@ -2696,7 +2678,7 @@ class Message(PyrogramType, Update):
                 if self.sticker or self.video_note:  # Sticker and VideoNote should have no caption
                     return await send_media(file_id=file_id)
                 else:
-                    return await send_media(file_id=file_id, caption=caption, parse_mode=ParseMode.HTML)
+                    return await send_media(file_id=file_id, caption=caption, parse_mode="html")
             else:
                 raise ValueError("Can't copy this message")
         else:
@@ -2708,7 +2690,7 @@ class Message(PyrogramType, Update):
             )
 
     async def delete(self, revoke: bool = True):
-        """Bound method *delete* of :obj:`Message `.
+        """Bound method *delete* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2724,7 +2706,7 @@ class Message(PyrogramType, Update):
 
                 message.delete()
 
-        Args:
+        Parameters:
             revoke (``bool``, *optional*):
                 Deletes messages on both parts.
                 This is only for private cloud chats and normal groups, messages on
@@ -2735,7 +2717,7 @@ class Message(PyrogramType, Update):
             True on success, False otherwise.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.delete_messages(
             chat_id=self.chat.id,
@@ -2743,10 +2725,10 @@ class Message(PyrogramType, Update):
             revoke=revoke
         )
 
-    async def click(self, x: int or str, y: int = None, quote: bool = None):
-        """Bound method *click* of :obj:`Message `.
+    async def click(self, x: int or str, y: int = 0, quote: bool = None, timeout: int = 10):
+        """Bound method *click* :obj:`Message `.
 
-        Use as a shortcut for clicking a button attached to the message instead of.
+        Use as a shortcut for clicking a button attached to the message instead of:
 
         - Clicking inline buttons:
 
@@ -2779,9 +2761,10 @@ class Message(PyrogramType, Update):
             3.  Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
                 Only the first matching button will be pressed.
 
-        Args:
+        Parameters:
             x (``int`` | ``str``):
                 Used as integer index, integer abscissa (in pair with y) or as string label.
+                Defaults to 0 (first button).
 
             y (``int``, *optional*):
                 Used as ordinate only (in pair with x).
@@ -2791,58 +2774,67 @@ class Message(PyrogramType, Update):
                 If ``True``, the message will be sent as a reply to this message.
                 Defaults to ``True`` in group chats and ``False`` in private chats.
 
+            timeout (``int``, *optional*):
+                Timeout in seconds.
+
         Returns:
-            -   The result of *request_callback_answer()* in case of inline callback button clicks.
-            -   The result of *reply()* in case of normal button clicks.
-            -   A string in case the inline button is an URL, switch_inline_query or switch_inline_query_current_chat
-                button.
+            -   The result of :meth:`request_callback_answer() ` in case of
+                inline callback button clicks.
+            -   The result of :meth:`reply() ` in case of normal button clicks.
+            -   A string in case the inline button is a URL, a *switch_inline_query* or a
+                *switch_inline_query_current_chat* button.
 
         Raises:
-            :class:`RPCError `
-            ``ValueError``: If the provided index or position is out of range or the button label was not found
-            ``TimeoutError``: If, after clicking an inline button, the bot fails to answer within 10 seconds
+            RPCError: In case of a Telegram RPC error.
+            ValueError: In case the provided index or position is out of range or the button label was not found.
+            TimeoutError: In case, after clicking an inline button, the bot fails to answer within the timeout.
         """
+
         if isinstance(self.reply_markup, pyrogram.ReplyKeyboardMarkup):
-            return await self.reply(x, quote=quote)
+            keyboard = self.reply_markup.keyboard
+            is_inline = False
         elif isinstance(self.reply_markup, pyrogram.InlineKeyboardMarkup):
-            if isinstance(x, int) and y is None:
-                try:
-                    button = [
-                        button
-                        for row in self.reply_markup.inline_keyboard
-                        for button in row
-                    ][x]
-                except IndexError:
-                    raise ValueError("The button at index {} doesn't exist".format(x)) from None
-            elif isinstance(x, int) and isinstance(y, int):
-                try:
-                    button = self.reply_markup.inline_keyboard[y][x]
-                except IndexError:
-                    raise ValueError("The button at position ({}, {}) doesn't exist".format(x, y)) from None
-            elif isinstance(x, str):
-                x = x.encode("utf-16", "surrogatepass").decode("utf-16")
+            keyboard = self.reply_markup.inline_keyboard
+            is_inline = True
+        else:
+            raise ValueError("The message doesn't contain any keyboard")
 
-                try:
-                    button = [
-                        button
-                        for row in self.reply_markup.inline_keyboard
-                        for button in row
-                        if x == button.text
-                    ][0]
-                except IndexError:
-                    raise ValueError(
-                        "The button with label '{}' doesn't exists".format(
-                            x.encode("unicode_escape").decode()
-                        )
-                    ) from None
-            else:
-                raise ValueError("Invalid arguments")
+        if isinstance(x, int) and y is None:
+            try:
+                button = [
+                    button
+                    for row in keyboard
+                    for button in row
+                ][x]
+            except IndexError:
+                raise ValueError("The button at index {} doesn't exist".format(x))
+        elif isinstance(x, int) and isinstance(y, int):
+            try:
+                button = keyboard[y][x]
+            except IndexError:
+                raise ValueError("The button at position ({}, {}) doesn't exist".format(x, y))
+        elif isinstance(x, str) and y is None:
+            label = x.encode("utf-16", "surrogatepass").decode("utf-16")
 
+            try:
+                button = [
+                    button
+                    for row in keyboard
+                    for button in row
+                    if label == button.text
+                ][0]
+            except IndexError:
+                raise ValueError("The button with label '{}' doesn't exists".format(x))
+        else:
+            raise ValueError("Invalid arguments")
+
+        if is_inline:
             if button.callback_data:
                 return await self._client.request_callback_answer(
                     chat_id=self.chat.id,
                     message_id=self.message_id,
-                    callback_data=button.callback_data
+                    callback_data=button.callback_data,
+                    timeout=timeout
                 )
             elif button.url:
                 return button.url
@@ -2853,7 +2845,7 @@ class Message(PyrogramType, Update):
             else:
                 raise ValueError("This button is not supported yet")
         else:
-            raise ValueError("The message doesn't contain any keyboard")
+            await self.reply(button, quote=quote)
 
     async def download(
         self,
@@ -2861,8 +2853,8 @@ class Message(PyrogramType, Update):
         block: bool = True,
         progress: callable = None,
         progress_args: tuple = ()
-    ) -> "Message":
-        """Bound method *download* of :obj:`Message `.
+    ) -> str:
+        """Bound method *download* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2875,7 +2867,7 @@ class Message(PyrogramType, Update):
 
                 message.download()
 
-        Args:
+        Parameters:
             file_name (``str``, *optional*):
                 A custom *file_name* to be used instead of the one provided by Telegram.
                 By default, all files are downloaded in the *downloads* folder in your working directory.
@@ -2899,7 +2891,7 @@ class Message(PyrogramType, Update):
             On success, the absolute path of the downloaded file as string is returned, None otherwise.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
             ``ValueError``: If the message doesn't contain any downloadable media
         """
         return await self._client.download_media(
@@ -2911,7 +2903,7 @@ class Message(PyrogramType, Update):
         )
 
     async def pin(self, disable_notification: bool = None) -> "Message":
-        """Bound method *pin* of :obj:`Message `.
+        """Bound method *pin* :obj:`Message `.
 
         Use as a shortcut for:
 
@@ -2927,7 +2919,7 @@ class Message(PyrogramType, Update):
 
                 message.pin()
 
-        Args:
+        Parameters:
             disable_notification (``bool``):
                 Pass True, if it is not necessary to send a notification to all chat members about the new pinned
                 message. Notifications are always disabled in channels.
@@ -2936,7 +2928,7 @@ class Message(PyrogramType, Update):
             True on success.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         return await self._client.pin_chat_message(
             chat_id=self.chat.id,
diff --git a/pyrogram/client/types/messages_and_media/message_entity.py b/pyrogram/client/types/messages_and_media/message_entity.py
index 160d0d1e..e369e74e 100644
--- a/pyrogram/client/types/messages_and_media/message_entity.py
+++ b/pyrogram/client/types/messages_and_media/message_entity.py
@@ -24,10 +24,10 @@ from ..user_and_chats.user import User
 
 
 class MessageEntity(PyrogramType):
-    """This object represents one special entity in a text message.
+    """One special entity in a text message.
     For example, hashtags, usernames, URLs, etc.
 
-    Args:
+    Parameters:
         type (``str``):
             Type of the entity.
             Can be "mention" (@username), "hashtag", "cashtag", "bot_command", "url", "email", "phone_number", "bold"
@@ -43,7 +43,7 @@ class MessageEntity(PyrogramType):
         url (``str``, *optional*):
             For "text_link" only, url that will be opened after user taps on the text.
 
-        user (:obj:`User `, *optional*):
+        user (:obj:`User`, *optional*):
             For "text_mention" only, the mentioned user.
     """
 
@@ -68,7 +68,7 @@ class MessageEntity(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         type: str,
         offset: int,
         length: int,
diff --git a/pyrogram/client/types/messages_and_media/messages.py b/pyrogram/client/types/messages_and_media/messages.py
index 5ac7a30a..95fad2fa 100644
--- a/pyrogram/client/types/messages_and_media/messages.py
+++ b/pyrogram/client/types/messages_and_media/messages.py
@@ -27,13 +27,13 @@ from ..user_and_chats import Chat
 
 
 class Messages(PyrogramType, Update):
-    """This object represents a chat's messages.
+    """Contains a chat's messages.
 
-    Args:
+    Parameters:
         total_count (``int``):
             Total number of messages the target chat has.
 
-        messages (List of :obj:`Message `):
+        messages (List of :obj:`Message`):
             Requested messages.
     """
 
@@ -42,7 +42,7 @@ class Messages(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         total_count: int,
         messages: List[Message]
     ):
@@ -79,7 +79,7 @@ class Messages(PyrogramType, Update):
                 reply_messages = (await client.get_messages(
                     parsed_messages[0].chat.id,
                     reply_to_message_ids=reply_message_ids,
-                    replies=0
+                    replies=replies - 1
                 )).messages
 
                 for message in parsed_messages:
@@ -128,9 +128,9 @@ class Messages(PyrogramType, Update):
         as_copy: bool = False,
         remove_caption: bool = False
     ):
-        """Bound method *forward* of :obj:`Message `.
+        """Bound method *forward* of :obj:`Message`.
 
-        Args:
+        Parameters:
             chat_id (``int`` | ``str``):
                 Unique identifier (int) or username (str) of the target chat.
                 For your personal cloud (Saved Messages) you can simply use "me" or "self".
@@ -150,10 +150,10 @@ class Messages(PyrogramType, Update):
                 Defaults to False.
 
         Returns:
-            On success, a :class:`Messages ` containing forwarded messages is returned.
+            On success, a :class:`Messages` containing forwarded messages is returned.
 
         Raises:
-            :class:`RPCError `
+            RPCError: In case of a Telegram RPC error.
         """
         forwarded_messages = []
 
diff --git a/pyrogram/client/types/messages_and_media/photo.py b/pyrogram/client/types/messages_and_media/photo.py
index 6f1852fb..8d60d59a 100644
--- a/pyrogram/client/types/messages_and_media/photo.py
+++ b/pyrogram/client/types/messages_and_media/photo.py
@@ -28,16 +28,16 @@ from ...ext.utils import encode
 
 
 class Photo(PyrogramType):
-    """This object represents a Photo.
+    """A Photo.
 
-    Args:
+    Parameters:
         id (``str``):
             Unique identifier for this photo.
 
         date (``int``):
             Date the photo was sent in Unix time.
 
-        sizes (List of :obj:`PhotoSize `):
+        sizes (List of :obj:`PhotoSize`):
             Available sizes of this photo.
     """
 
@@ -46,7 +46,7 @@ class Photo(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: str,
         date: int,
         sizes: List[PhotoSize]
diff --git a/pyrogram/client/types/messages_and_media/photo_size.py b/pyrogram/client/types/messages_and_media/photo_size.py
index 10d00a86..9f64ae6a 100644
--- a/pyrogram/client/types/messages_and_media/photo_size.py
+++ b/pyrogram/client/types/messages_and_media/photo_size.py
@@ -26,9 +26,9 @@ from ..pyrogram_type import PyrogramType
 
 
 class PhotoSize(PyrogramType):
-    """This object represents one size of a photo or a file/sticker thumbnail.
+    """One size of a photo or a file/sticker thumbnail.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -47,7 +47,7 @@ class PhotoSize(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         width: int,
         height: int,
diff --git a/pyrogram/client/types/messages_and_media/poll.py b/pyrogram/client/types/messages_and_media/poll.py
index fa68f669..e6c97bfb 100644
--- a/pyrogram/client/types/messages_and_media/poll.py
+++ b/pyrogram/client/types/messages_and_media/poll.py
@@ -26,9 +26,9 @@ from ..update import Update
 
 
 class Poll(PyrogramType, Update):
-    """This object represents a Poll.
+    """A Poll.
 
-    Args:
+    Parameters:
         id (``str``):
             Unique poll identifier.
 
@@ -53,7 +53,7 @@ class Poll(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: str,
         question: str,
         options: List[PollOption],
diff --git a/pyrogram/client/types/messages_and_media/poll_option.py b/pyrogram/client/types/messages_and_media/poll_option.py
index 4b32623a..e7eb1f5f 100644
--- a/pyrogram/client/types/messages_and_media/poll_option.py
+++ b/pyrogram/client/types/messages_and_media/poll_option.py
@@ -21,23 +21,26 @@ from ..pyrogram_type import PyrogramType
 
 
 class PollOption(PyrogramType):
-    """This object contains information about one answer option in a poll.
+    """Contains information about one answer option in a poll.
 
-    Args:
+    Parameters:
         text (``str``):
             Option text, 1-100 characters.
 
         voter_count (``int``):
             Number of users that voted for this option.
             Equals to 0 until you vote.
+
+        data (``bytes``):
+            The data this poll option is holding.
     """
 
-    __slots__ = ["text", "voter_count", "_data"]
+    __slots__ = ["text", "voter_count", "data"]
 
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         text: str,
         voter_count: int,
         data: bytes
@@ -46,4 +49,4 @@ class PollOption(PyrogramType):
 
         self.text = text
         self.voter_count = voter_count
-        self._data = data  # Hidden
+        self.data = data
diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/client/types/messages_and_media/sticker.py
index 47800657..08d56f6e 100644
--- a/pyrogram/client/types/messages_and_media/sticker.py
+++ b/pyrogram/client/types/messages_and_media/sticker.py
@@ -29,9 +29,9 @@ from ...ext.utils import encode
 
 
 class Sticker(PyrogramType):
-    """This object represents a sticker.
+    """A sticker.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -41,7 +41,7 @@ class Sticker(PyrogramType):
         height (``int``):
             Sticker height.
 
-        thumb (:obj:`PhotoSize `, *optional*):
+        thumb (:obj:`PhotoSize`, *optional*):
             Sticker thumbnail in the .webp or .jpg format.
 
         file_name (``str``, *optional*):
@@ -72,7 +72,7 @@ class Sticker(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         width: int,
         height: int,
diff --git a/pyrogram/client/types/messages_and_media/user_profile_photos.py b/pyrogram/client/types/messages_and_media/user_profile_photos.py
index f162b077..628831d5 100644
--- a/pyrogram/client/types/messages_and_media/user_profile_photos.py
+++ b/pyrogram/client/types/messages_and_media/user_profile_photos.py
@@ -24,13 +24,13 @@ from ..pyrogram_type import PyrogramType
 
 
 class UserProfilePhotos(PyrogramType):
-    """This object represents a user's profile pictures.
+    """Contains a user's profile pictures.
 
-    Args:
+    Parameters:
         total_count (``int``):
             Total number of profile pictures the target user has.
 
-        photos (List of :obj:`Photo `):
+        photos (List of :obj:`Photo`):
             Requested profile pictures.
     """
 
@@ -39,7 +39,7 @@ class UserProfilePhotos(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         total_count: int,
         photos: List[Photo]
     ):
diff --git a/pyrogram/client/types/messages_and_media/venue.py b/pyrogram/client/types/messages_and_media/venue.py
index 97829142..e54a812e 100644
--- a/pyrogram/client/types/messages_and_media/venue.py
+++ b/pyrogram/client/types/messages_and_media/venue.py
@@ -23,10 +23,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class Venue(PyrogramType):
-    """This object represents a venue.
+    """A venue.
 
-    Args:
-        location (:obj:`Location `):
+    Parameters:
+        location (:obj:`Location`):
             Venue location.
 
         title (``str``):
@@ -49,7 +49,7 @@ class Venue(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         location: Location,
         title: str,
         address: str,
diff --git a/pyrogram/client/types/messages_and_media/video.py b/pyrogram/client/types/messages_and_media/video.py
index a45a8f8d..529fc5ef 100644
--- a/pyrogram/client/types/messages_and_media/video.py
+++ b/pyrogram/client/types/messages_and_media/video.py
@@ -26,9 +26,9 @@ from ...ext.utils import encode
 
 
 class Video(PyrogramType):
-    """This object represents a video file.
+    """A video file.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -41,7 +41,7 @@ class Video(PyrogramType):
         duration (``int``):
             Duration of the video in seconds as defined by sender.
 
-        thumb (:obj:`PhotoSize `, *optional*):
+        thumb (:obj:`PhotoSize`, *optional*):
             Video thumbnail.
 
         file_name (``str``, *optional*):
@@ -68,7 +68,7 @@ class Video(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         width: int,
         height: int,
diff --git a/pyrogram/client/types/messages_and_media/video_note.py b/pyrogram/client/types/messages_and_media/video_note.py
index e6c2ab31..133ccae0 100644
--- a/pyrogram/client/types/messages_and_media/video_note.py
+++ b/pyrogram/client/types/messages_and_media/video_note.py
@@ -26,9 +26,9 @@ from ...ext.utils import encode
 
 
 class VideoNote(PyrogramType):
-    """This object represents a video note.
+    """A video note.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -38,7 +38,7 @@ class VideoNote(PyrogramType):
         duration (``int``):
             Duration of the video in seconds as defined by sender.
 
-        thumb (:obj:`PhotoSize `, *optional*):
+        thumb (:obj:`PhotoSize`, *optional*):
             Video thumbnail.
 
         mime_type (``str``, *optional*):
@@ -56,7 +56,7 @@ class VideoNote(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         length: int,
         duration: int,
diff --git a/pyrogram/client/types/messages_and_media/voice.py b/pyrogram/client/types/messages_and_media/voice.py
index b4063088..3e08d57a 100644
--- a/pyrogram/client/types/messages_and_media/voice.py
+++ b/pyrogram/client/types/messages_and_media/voice.py
@@ -25,9 +25,9 @@ from ...ext.utils import encode
 
 
 class Voice(PyrogramType):
-    """This object represents a voice note.
+    """A voice note.
 
-    Args:
+    Parameters:
         file_id (``str``):
             Unique identifier for this file.
 
@@ -52,7 +52,7 @@ class Voice(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         file_id: str,
         duration: int,
         waveform: bytes = None,
diff --git a/pyrogram/client/types/pyrogram_type.py b/pyrogram/client/types/pyrogram_type.py
index 5f757d43..ed50efbc 100644
--- a/pyrogram/client/types/pyrogram_type.py
+++ b/pyrogram/client/types/pyrogram_type.py
@@ -25,34 +25,45 @@ import pyrogram
 class PyrogramType:
     __slots__ = ["_client"]
 
-    def __init__(self, client: "pyrogram.client.ext.BaseClient"):
+    def __init__(self, client: "pyrogram.BaseClient" = None):
         self._client = client
 
-    def __str__(self):
+        if self._client is None:
+            del self._client
+
+    def __eq__(self, other: "PyrogramType") -> bool:
+        for attr in self.__slots__:
+            try:
+                if getattr(self, attr) != getattr(other, attr):
+                    return False
+            except AttributeError:
+                return False
+
+        return True
+
+    def __str__(self) -> str:
+        def default(obj: PyrogramType):
+            try:
+                return OrderedDict(
+                    [("_", "pyrogram." + obj.__class__.__name__)]
+                    + [(attr, getattr(obj, attr))
+                       for attr in obj.__slots__
+                       if getattr(obj, attr) is not None]
+                )
+            except AttributeError:
+                return repr(obj)
+
         return dumps(self, indent=4, default=default, ensure_ascii=False)
 
+    def __repr__(self) -> str:
+        return "pyrogram.{}({})".format(
+            self.__class__.__name__,
+            ", ".join(
+                "{}={}".format(attr, repr(getattr(self, attr)))
+                for attr in self.__slots__
+                if getattr(self, attr) is not None
+            )
+        )
+
     def __getitem__(self, item):
         return getattr(self, item)
-
-
-def remove_none(obj):
-    if isinstance(obj, (list, tuple, set)):
-        return type(obj)(remove_none(x) for x in obj if x is not None)
-    elif isinstance(obj, dict):
-        return type(obj)((remove_none(k), remove_none(v)) for k, v in obj.items() if k is not None and v is not None)
-    else:
-        return obj
-
-
-def default(o: PyrogramType):
-    try:
-        content = {i: getattr(o, i) for i in o.__slots__}
-
-        return remove_none(
-            OrderedDict(
-                [("_", "pyrogram." + o.__class__.__name__)]
-                + [i for i in content.items() if not i[0].startswith("_")]
-            )
-        )
-    except AttributeError:
-        return repr(o)
diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/client/types/user_and_chats/chat.py
index 6b4b9f38..85b29ac6 100644
--- a/pyrogram/client/types/user_and_chats/chat.py
+++ b/pyrogram/client/types/user_and_chats/chat.py
@@ -26,40 +26,40 @@ from ..pyrogram_type import PyrogramType
 
 
 class Chat(PyrogramType):
-    """This object represents a chat.
+    """A chat.
 
-    Args:
+    Parameters:
         id (``int``):
             Unique identifier for this chat.
 
         type (``str``):
-            Type of chat, can be either "private", "group", "supergroup" or "channel".
+            Type of chat, can be either "private", "bot", "group", "supergroup" or "channel".
 
         title (``str``, *optional*):
             Title, for supergroups, channels and basic group chats.
 
         username (``str``, *optional*):
-            Username, for private chats, supergroups and channels if available.
+            Username, for private chats, bots, supergroups and channels if available.
 
         first_name (``str``, *optional*):
-            First name of the other party in a private chat.
+            First name of the other party in a private chat, for private chats and bots.
 
         last_name (``str``, *optional*):
-            Last name of the other party in a private chat.
+            Last name of the other party in a private chat, for private chats.
 
         photo (:obj:`ChatPhoto `, *optional*):
             Chat photo. Suitable for downloads only.
 
         description (``str``, *optional*):
-            Description, for supergroups and channel chats.
+            Bio, for private chats and bots or description for groups, supergroups and channels.
             Returned only in :meth:`get_chat() `.
 
         invite_link (``str``, *optional*):
-            Chat invite link, for supergroups and channel chats.
+            Chat invite link, for groups, supergroups and channels.
             Returned only in :meth:`get_chat() `.
 
-        pinned_message (:obj:`Message `, *optional*):
-            Pinned message, for supergroups and channel chats.
+        pinned_message (:obj:`Message`, *optional*):
+            Pinned message, for groups, supergroups channels and own chat.
             Returned only in :meth:`get_chat() `.
 
         sticker_set_name (``str``, *optional*):
@@ -71,13 +71,13 @@ class Chat(PyrogramType):
             Returned only in :meth:`get_chat() `.
 
         members_count (``int``, *optional*):
-            Chat members count, for groups and channels only.
+            Chat members count, for groups, supergroups and channels only.
 
         restriction_reason (``str``, *optional*):
             The reason why this chat might be unavailable to some users.
 
         permissions (:obj:`ChatPermissions ` *optional*):
-            Information about the chat default permissions.
+            Information about the chat default permissions, for groups and supergroups.
     """
 
     __slots__ = [
@@ -89,7 +89,7 @@ class Chat(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: int,
         type: str,
         title: str = None,
@@ -128,7 +128,7 @@ class Chat(PyrogramType):
     def _parse_user_chat(client, user: types.User) -> "Chat":
         return Chat(
             id=user.id,
-            type="private",
+            type="bot" if user.bot else "private",
             username=user.username,
             first_name=user.first_name,
             last_name=user.last_name,
diff --git a/pyrogram/client/types/user_and_chats/chat_member.py b/pyrogram/client/types/user_and_chats/chat_member.py
index 046d2ebc..536f9526 100644
--- a/pyrogram/client/types/user_and_chats/chat_member.py
+++ b/pyrogram/client/types/user_and_chats/chat_member.py
@@ -23,10 +23,10 @@ from ..pyrogram_type import PyrogramType
 
 
 class ChatMember(PyrogramType):
-    """This object contains information about one member of a chat.
+    """Contains information about one member of a chat.
 
-    Args:
-        user (:obj:`User `):
+    Parameters:
+        user (:obj:`User`):
             Information about the user.
 
         status (``str``):
@@ -39,17 +39,17 @@ class ChatMember(PyrogramType):
         is_member (``bool``, *optional*):
             Restricted only. True, if the user is a member of the chat at the moment of the request.
 
-        invited_by (:obj:`User `, *optional*):
+        invited_by (:obj:`User`, *optional*):
             Administrators and self member only. Information about the user who invited this member.
             In case the user joined by himself this will be the same as "user".
 
-        promoted_by (:obj:`User `, *optional*):
+        promoted_by (:obj:`User`, *optional*):
             Administrators only. Information about the user who promoted this member as administrator.
 
-        restricted_by (:obj:`User `, *optional*):
+        restricted_by (:obj:`User`, *optional*):
             Restricted and kicked only. Information about the user who restricted or kicked this member.
 
-        permissions (:obj:`ChatPermissions ` *optional*):
+        permissions (:obj:`ChatPermissions` *optional*):
             Administrators, restricted and kicked members only.
             Information about the member permissions.
     """
@@ -59,7 +59,7 @@ class ChatMember(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         user: "pyrogram.User",
         status: str,
         date: int = None,
diff --git a/pyrogram/client/types/user_and_chats/chat_members.py b/pyrogram/client/types/user_and_chats/chat_members.py
index 3c89b124..f57b8b46 100644
--- a/pyrogram/client/types/user_and_chats/chat_members.py
+++ b/pyrogram/client/types/user_and_chats/chat_members.py
@@ -25,9 +25,9 @@ from ..pyrogram_type import PyrogramType
 
 
 class ChatMembers(PyrogramType):
-    """This object contains information about the members list of a chat.
+    """Contains information about the members list of a chat.
 
-    Args:
+    Parameters:
         total_count (``int``):
             Total number of members the chat has.
 
@@ -40,7 +40,7 @@ class ChatMembers(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         total_count: int,
         chat_members: List[ChatMember]
     ):
diff --git a/pyrogram/client/types/user_and_chats/chat_permissions.py b/pyrogram/client/types/user_and_chats/chat_permissions.py
index 7b35b1d0..6fa1a2a8 100644
--- a/pyrogram/client/types/user_and_chats/chat_permissions.py
+++ b/pyrogram/client/types/user_and_chats/chat_permissions.py
@@ -23,12 +23,12 @@ from ..pyrogram_type import PyrogramType
 
 
 class ChatPermissions(PyrogramType):
-    """This object represents both a chat default permissions and a single member permissions within a chat.
+    """A chat default permissions and a single member permissions within a chat.
 
     Some permissions make sense depending on the context: default chat permissions, restricted/kicked member or
     administrators in groups or channels.
 
-    Args:
+    Parameters:
         until_date (``int``, *optional*):
             Applicable to restricted and kicked members only.
             Date when user restrictions will be lifted, unix time.
diff --git a/pyrogram/client/types/user_and_chats/chat_photo.py b/pyrogram/client/types/user_and_chats/chat_photo.py
index 6fbc779d..08e43138 100644
--- a/pyrogram/client/types/user_and_chats/chat_photo.py
+++ b/pyrogram/client/types/user_and_chats/chat_photo.py
@@ -25,9 +25,9 @@ from ...ext.utils import encode
 
 
 class ChatPhoto(PyrogramType):
-    """This object represents a chat photo.
+    """A chat photo.
 
-    Args:
+    Parameters:
         small_file_id (``str``):
             Unique file identifier of small (160x160) chat photo. This file_id can be used only for photo download.
 
@@ -40,7 +40,7 @@ class ChatPhoto(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         small_file_id: str,
         big_file_id: str
     ):
diff --git a/pyrogram/client/types/user_and_chats/chat_preview.py b/pyrogram/client/types/user_and_chats/chat_preview.py
index ddd84b09..38dda6b6 100644
--- a/pyrogram/client/types/user_and_chats/chat_preview.py
+++ b/pyrogram/client/types/user_and_chats/chat_preview.py
@@ -26,13 +26,13 @@ from ..user_and_chats.user import User
 
 
 class ChatPreview(PyrogramType):
-    """This object represents a chat preview.
+    """A chat preview.
 
-    Args:
+    Parameters:
         title (``str``):
             Title of the chat.
 
-        photo (:obj:`ChatPhoto`):
+        photo (:obj:`ChatPhoto`, *optional*):
             Chat photo. Suitable for downloads only.
 
         type (``str``):
@@ -50,9 +50,9 @@ class ChatPreview(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         title: str,
-        photo: ChatPhoto,
+        photo: ChatPhoto = None,
         type: str,
         members_count: int,
         members: List[User] = None
diff --git a/pyrogram/client/types/user_and_chats/dialog.py b/pyrogram/client/types/user_and_chats/dialog.py
index d406d783..fc691ab6 100644
--- a/pyrogram/client/types/user_and_chats/dialog.py
+++ b/pyrogram/client/types/user_and_chats/dialog.py
@@ -24,13 +24,13 @@ from ..user_and_chats import Chat
 
 
 class Dialog(PyrogramType):
-    """This object represents a dialog.
+    """A user's dialog.
 
-    Args:
+    Parameters:
         chat (:obj:`Chat `):
             Conversation the dialog belongs to.
 
-        top_message (:obj:`Message `):
+        top_message (:obj:`Message`):
             The last message sent in the dialog at this time.
 
         unread_messages_count (``int``):
@@ -51,7 +51,7 @@ class Dialog(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         chat: Chat,
         top_message: "pyrogram.Message",
         unread_messages_count: int,
diff --git a/pyrogram/client/types/user_and_chats/dialogs.py b/pyrogram/client/types/user_and_chats/dialogs.py
index 3f831b45..915166bf 100644
--- a/pyrogram/client/types/user_and_chats/dialogs.py
+++ b/pyrogram/client/types/user_and_chats/dialogs.py
@@ -26,13 +26,13 @@ from ..pyrogram_type import PyrogramType
 
 
 class Dialogs(PyrogramType):
-    """This object represents a user's dialogs chunk.
+    """Contains a user's dialogs chunk.
 
-    Args:
+    Parameters:
         total_count (``int``):
             Total number of dialogs the user has.
 
-        dialogs (List of :obj:`Dialog `):
+        dialogs (List of :obj:`Dialog`):
             Requested dialogs.
     """
 
@@ -41,7 +41,7 @@ class Dialogs(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         total_count: int,
         dialogs: List[Dialog]
     ):
diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/client/types/user_and_chats/user.py
index 5718b917..455b4a4d 100644
--- a/pyrogram/client/types/user_and_chats/user.py
+++ b/pyrogram/client/types/user_and_chats/user.py
@@ -24,9 +24,9 @@ from ..pyrogram_type import PyrogramType
 
 
 class User(PyrogramType):
-    """This object represents a Telegram user or bot.
+    """A Telegram user or bot.
 
-    Args:
+    Parameters:
         id (``int``):
             Unique identifier for this user or bot.
 
@@ -78,7 +78,7 @@ class User(PyrogramType):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         id: int,
         is_self: bool,
         is_contact: bool,
diff --git a/pyrogram/client/types/user_and_chats/user_status.py b/pyrogram/client/types/user_and_chats/user_status.py
index 170ce373..e6f5b134 100644
--- a/pyrogram/client/types/user_and_chats/user_status.py
+++ b/pyrogram/client/types/user_and_chats/user_status.py
@@ -24,14 +24,14 @@ from ..update import Update
 
 
 class UserStatus(PyrogramType, Update):
-    """This object represents a User status (Last Seen privacy).
+    """A User status (Last Seen privacy).
 
     .. note::
 
         You won't see exact last seen timestamps for people with whom you don't share your own. Instead, you get
         "recently", "within_week", "within_month" or "long_time_ago" fields set.
 
-    Args:
+    Parameters:
         user_id (``int``):
             User's id.
 
@@ -70,7 +70,7 @@ class UserStatus(PyrogramType, Update):
     def __init__(
         self,
         *,
-        client: "pyrogram.client.ext.BaseClient",
+        client: "pyrogram.BaseClient" = None,
         user_id: int,
         online: bool = None,
         offline: bool = None,
diff --git a/pyrogram/crypto/aes.py b/pyrogram/crypto/aes.py
index de275bd0..d603caa0 100644
--- a/pyrogram/crypto/aes.py
+++ b/pyrogram/crypto/aes.py
@@ -56,7 +56,7 @@ except ImportError:
     log.warning(
         "TgCrypto is missing! "
         "Pyrogram will work the same, but at a much slower speed. "
-        "More info: https://docs.pyrogram.ml/resources/TgCrypto"
+        "More info: https://docs.pyrogram.org/topics/tgcrypto"
     )
 
 
diff --git a/requirements.txt b/requirements.txt
index 860eb531..f73d2a8b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
 pyaes==1.6.1
-pysocks==1.6.8
+pysocks==1.7.0
 async_lru==1.0.1
 async_generator==1.10
\ No newline at end of file
diff --git a/setup.py b/setup.py
index ef02c428..146dae9e 100644
--- a/setup.py
+++ b/setup.py
@@ -27,28 +27,20 @@ from compiler.api import compiler as api_compiler
 from compiler.docs import compiler as docs_compiler
 from compiler.error import compiler as error_compiler
 
+with open("requirements.txt", encoding="utf-8") as r:
+    requires = [i.strip() for i in r]
 
-def read(file: str) -> list:
-    with open(file, encoding="utf-8") as r:
-        return [i.strip() for i in r]
+with open("pyrogram/__init__.py", encoding="utf-8") as f:
+    version = re.findall(r"__version__ = \"(.+)\"", f.read())[0]
 
-
-def get_version():
-    with open("pyrogram/__init__.py", encoding="utf-8") as f:
-        return re.findall(r"__version__ = \"(.+)\"", f.read())[0]
-
-
-def get_readme():
-    # PyPI doesn't like raw html
-    with open("README.rst", encoding="utf-8") as f:
-        readme = re.sub(r"\.\. \|.+\| raw:: html(?:\s{4}.+)+\n\n", "", f.read())
-        return re.sub(r"\|header\|", "|logo|\n\n|description|\n\n|schema| |tgcrypto|", readme)
+with open("README.md", encoding="utf-8") as f:
+    readme = f.read()
 
 
 class Clean(Command):
     DIST = ["./build", "./dist", "./Pyrogram.egg-info"]
     API = ["pyrogram/api/errors/exceptions", "pyrogram/api/functions", "pyrogram/api/types", "pyrogram/api/all.py"]
-    DOCS = ["docs/source/functions", "docs/source/types", "docs/build"]
+    DOCS = ["docs/source/telegram", "docs/build"]
     ALL = DIST + API + DOCS
 
     description = "Clean generated files"
@@ -128,23 +120,25 @@ class Generate(Command):
 
 
 if len(argv) > 1 and argv[1] in ["bdist_wheel", "install", "develop"]:
-    error_compiler.start()
     api_compiler.start()
+    error_compiler.start()
     docs_compiler.start()
 
 setup(
     name="Pyrogram",
-    version=get_version(),
-    description="Telegram MTProto API Client Library for Python",
-    long_description=get_readme(),
+    version=version,
+    description="Telegram MTProto API Client Library and Framework for Python",
+    long_description=readme,
+    long_description_content_type="text/markdown",
     url="https://github.com/pyrogram",
     download_url="https://github.com/pyrogram/pyrogram/releases/latest",
-    author="Dan Tès",
-    author_email="admin@pyrogram.ml",
+    author="Dan",
+    author_email="dan@pyrogram.org",
     license="LGPLv3+",
     classifiers=[
-        "Development Status :: 3 - Alpha",
+        "Development Status :: 4 - Beta",
         "Intended Audience :: Developers",
+        "Natural Language :: English",
         "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)",
         "Operating System :: OS Independent",
         "Programming Language :: Python",
@@ -152,6 +146,8 @@ setup(
         "Programming Language :: Python :: 3.4",
         "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
+        "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
         "Programming Language :: Python :: Implementation",
         "Programming Language :: Python :: Implementation :: CPython",
         "Programming Language :: Python :: Implementation :: PyPy",
@@ -165,9 +161,9 @@ setup(
     keywords="telegram chat messenger mtproto api client library python",
     project_urls={
         "Tracker": "https://github.com/pyrogram/pyrogram/issues",
-        "Community": "https://t.me/PyrogramChat",
+        "Community": "https://t.me/Pyrogram",
         "Source": "https://github.com/pyrogram/pyrogram",
-        "Documentation": "https://docs.pyrogram.ml",
+        "Documentation": "https://docs.pyrogram.org",
     },
     python_requires="~=3.4",
     packages=find_packages(exclude=["compiler*"]),
@@ -175,10 +171,9 @@ setup(
         "pyrogram.client.ext": ["mime.types"]
     },
     zip_safe=False,
-    install_requires=read("requirements.txt"),
+    install_requires=requires,
     extras_require={
-        "tgcrypto": ["tgcrypto==1.1.1"],  # TODO: Remove soon
-        "fast": ["tgcrypto==1.1.1"],
+        "fast": ["tgcrypto==1.1.1"]
     },
     cmdclass={
         "clean": Clean,