Compare commits

..

No commits in common. "master" and "4.6.1" have entirely different histories.

61 changed files with 1266 additions and 42833 deletions

View File

@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
python-version: [ '3.6','3.7','3.8','3.9', '3.10', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9']
name: ${{ matrix.python-version }} and tests
steps:
- uses: actions/checkout@v2

View File

@ -1,22 +0,0 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.9"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt

View File

@ -4,7 +4,6 @@ python:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "pypy3"
install: "pip install -r requirements.txt"
script:

View File

@ -2,6 +2,7 @@
[![PyPi Package Version](https://img.shields.io/pypi/v/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/pyTelegramBotAPI.svg)](https://pypi.python.org/pypi/pyTelegramBotAPI)
[![Documentation Status](https://readthedocs.org/projects/pytba/badge/?version=latest)](https://pytba.readthedocs.io/en/latest/?badge=latest)
[![Build Status](https://travis-ci.org/eternnoir/pyTelegramBotAPI.svg?branch=master)](https://travis-ci.org/eternnoir/pyTelegramBotAPI)
[![PyPi downloads](https://img.shields.io/pypi/dm/pyTelegramBotAPI.svg)](https://pypi.org/project/pyTelegramBotAPI/)
[![PyPi status](https://img.shields.io/pypi/status/pytelegrambotapi.svg?style=flat-square)](https://pypi.python.org/pypi/pytelegrambotapi)
@ -10,10 +11,9 @@
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Both synchronous and asynchronous.</p>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#april-21-2023">6.7</a>!
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#june-20-2022">6.1</a>!
<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
## Contents
@ -56,7 +56,7 @@
* [Logging](#logging)
* [Proxy](#proxy)
* [Testing](#testing)
* [API conformance limitations](#api-conformance-limitations)
* [API conformance](#api-conformance)
* [AsyncTeleBot](#asynctelebot)
* [F.A.Q.](#faq)
* [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)
@ -69,7 +69,7 @@
## Getting started
This API is tested with Python 3.7-3.11 and Pypy 3.
This API is tested with Python 3.6-3.10 and Pypy 3.
There are two ways to install the library:
* Installation using pip (a Python package manager):
@ -165,7 +165,7 @@ To start the bot, simply open up a terminal and enter `python echo_bot.py` to ru
All types are defined in types.py. They are all completely in line with the [Telegram API's definition of the types](https://core.telegram.org/bots/api#available-types), except for the Message's `from` field, which is renamed to `from_user` (because `from` is a Python reserved token). Thus, attributes such as `message_id` can be accessed directly with `message.message_id`. Note that `message.chat` can be either an instance of `User` or `GroupChat` (see [How can I distinguish a User and a GroupChat in message.chat?](#how-can-i-distinguish-a-user-and-a-groupchat-in-messagechat)).
The Message object also has a `content_type`attribute, which defines the type of the Message. `content_type` can be one of the following strings:
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_members`, `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`, `web_app_data`.
`text`, `audio`, `document`, `photo`, `sticker`, `video`, `video_note`, `voice`, `location`, `contact`, `new_chat_members`, `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`.
You can use some types in one function. Example:
@ -265,7 +265,7 @@ def test_callback(call): # <- passes a CallbackQuery type object to your functio
#### Shipping Query Handler
Handle shipping queries
`@bot.shipping_query_handler() # <- passes a ShippingQuery type object to your function`
`@bot.shipping_query_handeler() # <- passes a ShippingQuery type object to your function`
#### Pre Checkout Query Handler
Handle pre checkoupt queries
@ -726,10 +726,27 @@ Result will be:
## API conformance limitations
## API conformance
* ✔ [Bot API 6.1](https://core.telegram.org/bots/api#june-20-2022)
* ✔ [Bot API 6.0](https://core.telegram.org/bots/api#april-16-2022)
* ✔ [Bot API 5.7](https://core.telegram.org/bots/api#january-31-2022)
* ✔ [Bot API 5.6](https://core.telegram.org/bots/api#december-30-2021)
* ✔ [Bot API 5.5](https://core.telegram.org/bots/api#december-7-2021)
* ✔ [Bot API 5.4](https://core.telegram.org/bots/api#november-5-2021)
* [Bot API 5.3](https://core.telegram.org/bots/api#june-25-2021) - ChatMember* classes are full copies of ChatMember
* ✔ [Bot API 5.2](https://core.telegram.org/bots/api#april-26-2021)
* ✔ [Bot API 5.1](https://core.telegram.org/bots/api#march-9-2021)
* ✔ [Bot API 5.0](https://core.telegram.org/bots/api-changelog#november-4-2020)
* ✔ [Bot API 4.9](https://core.telegram.org/bots/api-changelog#june-4-2020)
* ✔ [Bot API 4.8](https://core.telegram.org/bots/api-changelog#april-24-2020)
* ✔ [Bot API 4.7](https://core.telegram.org/bots/api-changelog#march-30-2020)
* ✔ [Bot API 4.6](https://core.telegram.org/bots/api-changelog#january-23-2020)
* [Bot API 4.5](https://core.telegram.org/bots/api-changelog#december-31-2019) - No nested MessageEntities and Markdown2 support
* [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
* [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
* ✔ [Bot API 4.4](https://core.telegram.org/bots/api-changelog#july-29-2019)
* ✔ [Bot API 4.3](https://core.telegram.org/bots/api-changelog#may-31-2019)
* ✔ [Bot API 4.2](https://core.telegram.org/bots/api-changelog#april-14-2019)
* [Bot API 4.1](https://core.telegram.org/bots/api-changelog#august-27-2018) - No Passport support
* [Bot API 4.0](https://core.telegram.org/bots/api-changelog#july-26-2018) - No Passport support
## AsyncTeleBot
@ -877,7 +894,6 @@ Here are some examples of template:
* [GrandQuiz Bot](https://github.com/Carlosma7/TFM-GrandQuiz) by [Carlosma7](https://github.com/Carlosma7). This bot is a trivia game that allows you to play with people from different ages. This project addresses the use of a system through chatbots to carry out a social and intergenerational game as an alternative to traditional game development.
* [Diccionario de la RAE](https://t.me/dleraebot) ([source](https://github.com/studentenherz/dleraebot)) This bot lets you find difinitions of words in Spanish using [RAE's dictionary](https://dle.rae.es/). It features direct message and inline search.
* [remoteTelegramShell](https://github.com/EnriqueMoran/remoteTelegramShell) by [EnriqueMoran](https://github.com/EnriqueMoran). Control your LinuxOS computer through Telegram.
* [Commerce Telegram Bot](https://github.com/ayitinya/commerce-telegram-bot/). Make purchases of items in a store with an Admin panel for data control and notifications.
* [Pyfram-telegram-bot](https://github.com/skelly37/pyfram-telegram-bot) Query wolframalpha.com and make use of its API through Telegram.
* [TranslateThisVideoBot](https://gitlab.com/WuerfelDev/translatethisvideo) This Bot can understand spoken text in videos and translate it to English
* [Zyprexa](https://t.me/mathemathicsBot) ([source](https://github.com/atif5/zyprexa)) Zyprexa can solve, help you solve any mathematical problem you encounter and convert your regular mathematical expressions into beautiful imagery using LaTeX.
@ -885,12 +901,5 @@ Here are some examples of template:
* [hydrolib_bot](https://github.com/Mayson90/hydrolib_bot) Toolset for Hydrophilia tabletop game (game cards, rules, structure...).
* [Gugumoe-bot](http://t.me/gugumoe_bot) ([source](https://github.com/GooGuJiang/Gugumoe-bot)) by [咕谷酱](https://gmoe.cc) GuXiaoJiang is a multi-functional robot, such as OSU game information query, IP test, animation screenshot search and other functions.
* [Feedback-bot](https://github.com/coder2020official/feedbackbot) A feedback bot for user-admin communication. Made on AsyncTeleBot, using [template](https://github.com/coder2020official/asynctelebot_template).
* [TeleServ](https://github.com/ablakely/TeleServ) by [ablakely](https://github.com/ablakely) This is a Telegram to IRC bridge which links as an IRC server and makes Telegram users appear as native IRC users.
* [Simple Store Bot](https://github.com/AntonGlyzin/myshopbot) by [Anton Glyzin](https://github.com/AntonGlyzin) This is a simple telegram-store with an admin panel. Designed according to a template.
* [Media Rating Bot](https://t.me/mediaratingbot) ([source](https://github.com/CommanderCRM/MediaRatingBot))by [CommanderCRM](https://github.com/CommanderCRM). This bot aggregates media (movies, TV series, etc.) ratings from IMDb, Rotten Tomatoes, Metacritic, TheMovieDB, FilmAffinity and also provides number of votes of said media on IMDb.
* [Spot Seek Bot](https://t.me/SpotSeekBot) ([source](https://github.com/arashnm80/spot-seek-bot)) by [Arashnm80](https://github.com/arashnm80). This is a free & open source telegram bot for downloading tracks, albums or playlists from spotify.
* [CalendarIT Bot](https://t.me/calendarit_bot) ([source](https://github.com/codebyzen/CalendarIT_Telegram_Bot))by [CodeByZen](https://github.com/codebyzen). A simple, but extensible Python Telegram bot, can post acquainted with what is happening today, tomorrow or what happened 20 years ago to channel.
* [DownloadMusicBOT](https://github.com/fcoagz/DownloadMusicBOT) by *Francisco Griman* - It is a simple bot that downloads audio from YouTube videos on Telegram.
* [AwesomeChatGPTBot](https://github.com/Kourva/AwesomeChatGPTBot) - Simple ChatGTP-3.5 bot. It is FREE and can remember chat history for a while With pre-defined roles!
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

View File

@ -26,6 +26,15 @@ Asyncio filters
:undoc-members:
:show-inheritance:
Asynchronous storage for states
-------------------------------
.. automodule:: telebot.asyncio_storage
:members:
:undoc-members:
:show-inheritance:
Asyncio handler backends
------------------------

View File

@ -18,11 +18,11 @@
# -- Project information -----------------------------------------------------
project = 'pyTelegramBotAPI Documentation'
copyright = '2022-2023, coder2020official'
copyright = '2022, coder2020official'
author = 'coder2020official'
# The full version, including alpha/beta/rc tags
release = '4.12.0'
release = '4.6.1'
# -- General configuration ---------------------------------------------------
@ -68,5 +68,3 @@ html_theme_options = {
"light_logo": "logo.png",
"dark_logo": "logo2.png",
}
locale_dirs = ["locales/"]

File diff suppressed because it is too large Load Diff

View File

@ -1,127 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../calldata.rst:4
msgid "Callback data factory"
msgstr ""
#: ../../calldata.rst:6
msgid "Callback data factory in pyTelegramBotAPI"
msgstr ""
#: ../../calldata.rst:6
msgid ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
"factory"
msgstr ""
#: ../../calldata.rst:12
msgid "callback\\_data file"
msgstr ""
#: of telebot.callback_data:1
msgid "Callback data factory's file."
msgstr ""
#: of telebot.callback_data.CallbackData:1
#: telebot.callback_data.CallbackDataFilter:1
msgid "Bases: :py:class:`object`"
msgstr ""
#: of telebot.callback_data.CallbackData:1
msgid "Callback data factory This class will help you to work with CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:1
msgid "Generate filter"
msgstr ""
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:3
msgid "specified named parameters will be checked with CallbackQuery.data"
msgstr ""
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Returns"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:4
msgid "CallbackDataFilter class"
msgstr ""
#: of telebot.callback_data.CallbackData.new:1
msgid "Generate callback data"
msgstr ""
#: of telebot.callback_data.CallbackData.new:3
msgid "positional parameters of CallbackData instance parts"
msgstr ""
#: of telebot.callback_data.CallbackData.new:4
msgid "named parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.new:5
msgid "str"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:1
msgid "Parse data from the callback data"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:3
msgid ""
"string, use to telebot.types.CallbackQuery to parse it from string to a "
"dict"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:4
msgid "dict parsed from callback data"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter:1
msgid "Filter for CallbackData."
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:1
msgid "Checks if query.data appropriates to specified config"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:3
msgid "telebot.types.CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:6
msgid "True if query.data appropriates to specified config"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check
msgid "Return type"
msgstr ""

View File

@ -1,251 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../formatting.rst:3
msgid "Formatting options"
msgstr ""
#: ../../formatting.rst:5
msgid "Formatting options in pyTelegramBotAPI"
msgstr ""
#: ../../formatting.rst:5
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
msgstr ""
#: of telebot.formatting:1
msgid "Markdown & HTML formatting functions."
msgstr ""
#: of telebot.formatting.escape_html:1
msgid "Escapes HTML characters in a string of HTML."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Parameters"
msgstr ""
#: of telebot.formatting.escape_html:3
msgid "The string of HTML to escape."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Returns"
msgstr ""
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
msgid "The escaped string."
msgstr ""
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Return type"
msgstr ""
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
#: telebot.formatting.munderline:10
msgid ":obj:`str`"
msgstr ""
#: of telebot.formatting.escape_markdown:1
msgid "Escapes Markdown characters in a string of Markdown."
msgstr ""
#: of telebot.formatting.escape_markdown:3
msgid "Credits to: simonsmh"
msgstr ""
#: of telebot.formatting.escape_markdown:5
msgid "The string of Markdown to escape."
msgstr ""
#: of telebot.formatting.format_text:1
msgid "Formats a list of strings into a single string."
msgstr ""
#: of telebot.formatting.format_text:10
msgid "Strings to format."
msgstr ""
#: of telebot.formatting.format_text:13
msgid "The separator to use between each string."
msgstr ""
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
msgid "The formatted string."
msgstr ""
#: of telebot.formatting.hbold:1
msgid "Returns an HTML-formatted bold string."
msgstr ""
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
msgid "The string to bold."
msgstr ""
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
#: telebot.formatting.munderline:6
msgid "True if you need to escape special characters. Defaults to True."
msgstr ""
#: of telebot.formatting.hcode:1
msgid "Returns an HTML-formatted code string."
msgstr ""
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
msgid "The string to code."
msgstr ""
#: of telebot.formatting.hide_link:1
msgid "Hide url of an image."
msgstr ""
#: of telebot.formatting.hide_link:3
msgid "The url of the image."
msgstr ""
#: of telebot.formatting.hide_link:6
msgid "The hidden url."
msgstr ""
#: of telebot.formatting.hitalic:1
msgid "Returns an HTML-formatted italic string."
msgstr ""
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
msgid "The string to italicize."
msgstr ""
#: of telebot.formatting.hlink:1
msgid "Returns an HTML-formatted link string."
msgstr ""
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
msgid "The string to link."
msgstr ""
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
msgid "The URL to link to."
msgstr ""
#: of telebot.formatting.hpre:1
msgid "Returns an HTML-formatted preformatted string."
msgstr ""
#: of telebot.formatting.hpre:3
msgid "The string to preformatted."
msgstr ""
#: of telebot.formatting.hspoiler:1
msgid "Returns an HTML-formatted spoiler string."
msgstr ""
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
msgid "The string to spoiler."
msgstr ""
#: of telebot.formatting.hstrikethrough:1
msgid "Returns an HTML-formatted strikethrough string."
msgstr ""
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
msgid "The string to strikethrough."
msgstr ""
#: of telebot.formatting.hunderline:1
msgid "Returns an HTML-formatted underline string."
msgstr ""
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
msgid "The string to underline."
msgstr ""
#: of telebot.formatting.mbold:1
msgid "Returns a Markdown-formatted bold string."
msgstr ""
#: of telebot.formatting.mcode:1
msgid "Returns a Markdown-formatted code string."
msgstr ""
#: of telebot.formatting.mitalic:1
msgid "Returns a Markdown-formatted italic string."
msgstr ""
#: of telebot.formatting.mlink:1
msgid "Returns a Markdown-formatted link string."
msgstr ""
#: of telebot.formatting.mspoiler:1
msgid "Returns a Markdown-formatted spoiler string."
msgstr ""
#: of telebot.formatting.mstrikethrough:1
msgid "Returns a Markdown-formatted strikethrough string."
msgstr ""
#: of telebot.formatting.munderline:1
msgid "Returns a Markdown-formatted underline string."
msgstr ""

View File

@ -1,120 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../index.rst:8
msgid "Welcome to pyTelegramBotAPI's documentation!"
msgstr ""
#: ../../index.rst:10
msgid "Official documentation of pyTelegramBotAPI"
msgstr ""
#: ../../index.rst:10
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
msgstr ""
#: ../../index.rst:17
msgid "TeleBot"
msgstr ""
#: ../../index.rst:18
msgid ""
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
msgstr ""
#: ../../index.rst:21
msgid "Chats"
msgstr ""
#: ../../index.rst:22
msgid ""
"English chat: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
msgstr ""
#: ../../index.rst:24
msgid ""
"Russian chat: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
msgstr ""
#: ../../index.rst:26
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
msgstr ""
#: ../../index.rst:28
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
msgstr ""
#: ../../index.rst:30
msgid ""
"Source: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
msgstr ""
#: ../../index.rst:33
msgid "Some features:"
msgstr ""
#: ../../index.rst:34
msgid "Easy to learn and use."
msgstr ""
#: ../../index.rst:36
msgid "Easy to understand."
msgstr ""
#: ../../index.rst:38
msgid "Both sync and async."
msgstr ""
#: ../../index.rst:40
msgid "Examples on features."
msgstr ""
#: ../../index.rst:42
msgid "States"
msgstr ""
#: ../../index.rst:44
msgid "And more..."
msgstr ""
#: ../../index.rst:47
msgid "Content"
msgstr ""
#: ../../index.rst:63
msgid "Indices and tables"
msgstr ""
#: ../../index.rst:65
msgid ":ref:`genindex`"
msgstr ""
#: ../../index.rst:66
msgid ":ref:`modindex`"
msgstr ""
#: ../../index.rst:67
msgid ":ref:`search`"
msgstr ""

View File

@ -1,58 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../install.rst:3
msgid "Installation Guide"
msgstr ""
#: ../../install.rst:5
msgid "Installation of pyTelegramBotAPI"
msgstr ""
#: ../../install.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
msgstr ""
#: ../../install.rst:11
msgid "Using PIP"
msgstr ""
#: ../../install.rst:17
msgid "Using pipenv"
msgstr ""
#: ../../install.rst:23
msgid "By cloning repository"
msgstr ""
#: ../../install.rst:31
msgid "Directly using pip"
msgstr ""
#: ../../install.rst:37
msgid "It is generally recommended to use the first option."
msgstr ""
#: ../../install.rst:39
msgid ""
"While the API is production-ready, it is still under development and it "
"has regular updates, do not forget to update it regularly by calling:"
msgstr ""

View File

@ -1,40 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../quick_start.rst:4
msgid "Quick start"
msgstr ""
#: ../../quick_start.rst:6
msgid "Quickstart guide"
msgstr ""
#: ../../quick_start.rst:6
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
msgstr ""
#: ../../quick_start.rst:11
msgid "Synchronous TeleBot"
msgstr ""
#: ../../quick_start.rst:16
msgid "Asynchronous TeleBot"
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,355 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../source/util.rst:3
msgid "Utils"
msgstr ""
#: ../../source/util.rst:5
msgid "Utils in pyTelegramBotAPI"
msgstr ""
#: ../../source/util.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
msgstr ""
#: ../../source/util.rst:11
msgid "util file"
msgstr ""
#: of telebot.util.antiflood:1
msgid ""
"Use this function inside loops in order to avoid getting TooManyRequests "
"error. Example:"
msgstr ""
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Parameters"
msgstr ""
#: of telebot.util.antiflood:10
msgid "The function to call"
msgstr ""
#: of telebot.util.antiflood:13
msgid "Number of retries to send"
msgstr ""
#: of telebot.util.antiflood:16
msgid "The arguments to pass to the function"
msgstr ""
#: of telebot.util.antiflood:19
msgid "The keyword arguments to pass to the function"
msgstr ""
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Returns"
msgstr ""
#: of telebot.util.antiflood:22
msgid "None"
msgstr ""
#: of telebot.service_utils.chunks:1
msgid "Yield successive n-sized chunks from lst."
msgstr ""
#: ../../docstring of telebot.util.content_type_media:1
msgid "Contains all media content types."
msgstr ""
#: ../../docstring of telebot.util.content_type_service:1
msgid "Contains all service content types such as `User joined the group`."
msgstr ""
#: of telebot.util.escape:1
msgid ""
"Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;'"
" and '>' with '&gt;')."
msgstr ""
#: of telebot.util.escape:3
msgid "the text to escape"
msgstr ""
#: of telebot.util.escape:4
msgid "the escaped text"
msgstr ""
#: of telebot.util.extract_arguments:1
msgid "Returns the argument after the command."
msgstr ""
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
msgid "Examples:"
msgstr ""
#: of telebot.util.extract_arguments:10
msgid "String to extract the arguments from a command"
msgstr ""
#: of telebot.util.extract_arguments:13
msgid "the arguments if `text` is a command (according to is_command), else None."
msgstr ""
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
#: telebot.util.user_link
msgid "Return type"
msgstr ""
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
msgid ":obj:`str` or :obj:`None`"
msgstr ""
#: of telebot.util.extract_command:1
msgid ""
"Extracts the command from `text` (minus the '/') if `text` is a command "
"(see is_command). If `text` is not a command, this function returns None."
msgstr ""
#: of telebot.util.extract_command:12
msgid "String to extract the command from"
msgstr ""
#: of telebot.util.extract_command:15
msgid "the command if `text` is a command (according to is_command), else None."
msgstr ""
#: of telebot.service_utils.generate_random_token:1
msgid ""
"Generates a random token consisting of letters and digits, 16 characters "
"long."
msgstr ""
#: of telebot.service_utils.generate_random_token:3
msgid "a random token"
msgstr ""
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
msgid ":obj:`str`"
msgstr ""
#: of telebot.service_utils.is_bytes:1
msgid "Returns True if the given object is a bytes object."
msgstr ""
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
#: telebot.service_utils.is_pil_image:3
msgid "object to be checked"
msgstr ""
#: of telebot.service_utils.is_bytes:6
msgid "True if the given object is a bytes object."
msgstr ""
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
msgid ":obj:`bool`"
msgstr ""
#: of telebot.util.is_command:1
msgid ""
"Checks if `text` is a command. Telegram chat commands start with the '/' "
"character."
msgstr ""
#: of telebot.util.is_command:3
msgid "Text to check."
msgstr ""
#: of telebot.util.is_command:6
msgid "True if `text` is a command, else False."
msgstr ""
#: of telebot.service_utils.is_dict:1
msgid "Returns True if the given object is a dictionary."
msgstr ""
#: of telebot.service_utils.is_dict:6
msgid "True if the given object is a dictionary."
msgstr ""
#: of telebot.service_utils.is_pil_image:1
msgid "Returns True if the given object is a PIL.Image.Image object."
msgstr ""
#: of telebot.service_utils.is_pil_image:6
msgid "True if the given object is a PIL.Image.Image object."
msgstr ""
#: of telebot.service_utils.is_string:1
msgid "Returns True if the given object is a string."
msgstr ""
#: of telebot.util.parse_web_app_data:1
msgid "Parses web app data."
msgstr ""
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
msgid "The bot token"
msgstr ""
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
msgid "The raw init data"
msgstr ""
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
msgid "The parsed init data"
msgstr ""
#: of telebot.util.quick_markup:1
msgid ""
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
" = InlineKeyboardButton(...)'"
msgstr ""
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
msgid "Example:"
msgstr ""
#: of telebot.util.quick_markup:6
msgid "Using quick_markup:"
msgstr ""
#: of telebot.util.quick_markup:31
msgid ""
"a dict containing all buttons to create in this format: {text: kwargs} "
"{str:}"
msgstr ""
#: of telebot.util.quick_markup:34
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
msgstr ""
#: of telebot.util.quick_markup:37
msgid "InlineKeyboardMarkup"
msgstr ""
#: of telebot.util.quick_markup:38
msgid ":obj:`types.InlineKeyboardMarkup`"
msgstr ""
#: of telebot.util.smart_split:1
msgid ""
"Splits one string into multiple strings, with a maximum amount of "
"`chars_per_string` characters per string. This is very useful for "
"splitting one giant message into multiples. If `chars_per_string` > 4096:"
" `chars_per_string` = 4096. Splits by '\\n', '. ' or ' ' in exactly this "
"priority."
msgstr ""
#: of telebot.util.smart_split:6 telebot.util.split_string:4
msgid "The text to split"
msgstr ""
#: of telebot.util.smart_split:9
msgid "The number of maximum characters per part the text is split to."
msgstr ""
#: of telebot.util.smart_split:12 telebot.util.split_string:10
msgid "The splitted text as a list of strings."
msgstr ""
#: of telebot.util.smart_split:13 telebot.util.split_string:11
msgid ":obj:`list` of :obj:`str`"
msgstr ""
#: of telebot.util.split_string:1
msgid ""
"Splits one string into multiple strings, with a maximum amount of "
"`chars_per_string` characters per string. This is very useful for "
"splitting one giant message into multiples."
msgstr ""
#: of telebot.util.split_string:7
msgid "The number of characters per line the text is split into."
msgstr ""
#: ../../docstring of telebot.util.update_types:1
msgid "All update types, should be used for allowed_updates parameter in polling."
msgstr ""
#: of telebot.util.user_link:1
msgid ""
"Returns an HTML user link. This is useful for reports. Attention: Don't "
"forget to set parse_mode to 'HTML'!"
msgstr ""
#: of telebot.util.user_link:11
msgid ""
"You can use formatting.* for all other formatting options(bold, italic, "
"links, and etc.) This method is kept for backward compatibility, and it "
"is recommended to use formatting.* for more options."
msgstr ""
#: of telebot.util.user_link:15
msgid "the user (not the user_id)"
msgstr ""
#: of telebot.util.user_link:18
msgid "include the user_id"
msgstr ""
#: of telebot.util.user_link:21
msgid "HTML user link"
msgstr ""
#: of telebot.util.validate_web_app_data:1
msgid "Validates web app data."
msgstr ""
#: of telebot.util.webhook_google_functions:1
msgid "A webhook endpoint for Google Cloud Functions FaaS."
msgstr ""
#: of telebot.util.webhook_google_functions:3
msgid "The bot instance"
msgstr ""
#: of telebot.util.webhook_google_functions:6
msgid "The request object"
msgstr ""
#: of telebot.util.webhook_google_functions:9
msgid "The response object"
msgstr ""
#~ msgid "int row width"
#~ msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../calldata.rst:4
msgid "Callback data factory"
msgstr "Фабрика callback data"
#: ../../calldata.rst:6
msgid "Callback data factory in pyTelegramBotAPI"
msgstr "Фабрика callback data в pyTelegramBotAPI"
#: ../../calldata.rst:6
msgid ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, guide, callbackdata, "
"factory"
msgstr ""
"ptba, pytba, pyTelegramBotAPI, callbackdatafactory, гайд, callbackdata, "
"фабрика"
#: ../../calldata.rst:12
msgid "callback\\_data file"
msgstr "Файл callback\\_data"
#: of telebot.callback_data:1
msgid "Callback data factory's file."
msgstr "Файл фабрики callback data."
#: of telebot.callback_data.CallbackData:1
#: telebot.callback_data.CallbackDataFilter:1
msgid "Bases: :py:class:`object`"
msgstr "Базовые классы: :py:class:`object`"
#: of telebot.callback_data.CallbackData:1
msgid "Callback data factory This class will help you to work with CallbackQuery"
msgstr "Фабрика Callback data. Этот класс поможет вам в работе с CallbackQuery"
#: of telebot.callback_data.CallbackData.filter:1
msgid "Generate filter"
msgstr "Сгенерировать фильтр"
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Parameters"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:3
msgid "specified named parameters will be checked with CallbackQuery.data"
msgstr "заданные именованные параметры будут проверены в CallbackQuery.data"
#: of telebot.callback_data.CallbackData.filter
#: telebot.callback_data.CallbackData.new
#: telebot.callback_data.CallbackData.parse
#: telebot.callback_data.CallbackDataFilter.check
msgid "Returns"
msgstr ""
#: of telebot.callback_data.CallbackData.filter:4
msgid "CallbackDataFilter class"
msgstr "Класс CallbackDataFilter"
#: of telebot.callback_data.CallbackData.new:1
msgid "Generate callback data"
msgstr "Сгенерировать callback data"
#: of telebot.callback_data.CallbackData.new:3
msgid "positional parameters of CallbackData instance parts"
msgstr "позиционные параметры экземпляра CallbackData"
#: of telebot.callback_data.CallbackData.new:4
msgid "named parameters"
msgstr "именованные параметры"
#: of telebot.callback_data.CallbackData.new:5
msgid "str"
msgstr ""
#: of telebot.callback_data.CallbackData.parse:1
msgid "Parse data from the callback data"
msgstr "Получить данные из callback data"
#: of telebot.callback_data.CallbackData.parse:3
msgid ""
"string, use to telebot.types.CallbackQuery to parse it from string to a "
"dict"
msgstr ""
"string, примените к telebot.types.CallbackQuery, чтобы преобразовать "
"callback_data из строки (str) в словарь (dict)"
#: of telebot.callback_data.CallbackData.parse:4
msgid "dict parsed from callback data"
msgstr "словарь (dict), полученный из callback data"
#: of telebot.callback_data.CallbackDataFilter:1
msgid "Filter for CallbackData."
msgstr "Фильтр для CallbackData."
#: of telebot.callback_data.CallbackDataFilter.check:1
msgid "Checks if query.data appropriates to specified config"
msgstr "Проверяет, соответствует ли query.data заданной конфигурации"
#: of telebot.callback_data.CallbackDataFilter.check:3
msgid "telebot.types.CallbackQuery"
msgstr ""
#: of telebot.callback_data.CallbackDataFilter.check:6
msgid "True if query.data appropriates to specified config"
msgstr "True, если query.data соответствует заданной конфигурации"
#: of telebot.callback_data.CallbackDataFilter.check
msgid "Return type"
msgstr ""

View File

@ -1,251 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../formatting.rst:3
msgid "Formatting options"
msgstr "Параметры форматирования"
#: ../../formatting.rst:5
msgid "Formatting options in pyTelegramBotAPI"
msgstr "Параметры форматирования в pyTelegramBotAPI"
#: ../../formatting.rst:5
msgid "html, markdown, parse_mode, formatting, ptba, pytba, pyTelegramBotAPI"
msgstr "html, markdown, parse_mode, форматирование, ptba, pytba, pyTelegramBotAPI"
#: of telebot.formatting:1
msgid "Markdown & HTML formatting functions."
msgstr "Функции форматирования Markdown & HTML."
#: of telebot.formatting.escape_html:1
msgid "Escapes HTML characters in a string of HTML."
msgstr "Пропускает HTML символы в HTML строке."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Parameters"
msgstr ""
#: of telebot.formatting.escape_html:3
msgid "The string of HTML to escape."
msgstr "HTML строка, которую нужно пропустить."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Returns"
msgstr ""
#: of telebot.formatting.escape_html:6 telebot.formatting.escape_markdown:8
msgid "The escaped string."
msgstr "Пропускаемая строка."
#: of telebot.formatting.escape_html telebot.formatting.escape_markdown
#: telebot.formatting.format_text telebot.formatting.hbold
#: telebot.formatting.hcode telebot.formatting.hide_link
#: telebot.formatting.hitalic telebot.formatting.hlink telebot.formatting.hpre
#: telebot.formatting.hspoiler telebot.formatting.hstrikethrough
#: telebot.formatting.hunderline telebot.formatting.mbold
#: telebot.formatting.mcode telebot.formatting.mitalic telebot.formatting.mlink
#: telebot.formatting.mspoiler telebot.formatting.mstrikethrough
#: telebot.formatting.munderline
msgid "Return type"
msgstr ""
#: of telebot.formatting.escape_html:7 telebot.formatting.escape_markdown:9
#: telebot.formatting.format_text:17 telebot.formatting.hbold:10
#: telebot.formatting.hcode:10 telebot.formatting.hide_link:7
#: telebot.formatting.hitalic:10 telebot.formatting.hlink:13
#: telebot.formatting.hpre:10 telebot.formatting.hspoiler:10
#: telebot.formatting.hstrikethrough:10 telebot.formatting.hunderline:10
#: telebot.formatting.mbold:10 telebot.formatting.mcode:10
#: telebot.formatting.mitalic:10 telebot.formatting.mlink:13
#: telebot.formatting.mspoiler:10 telebot.formatting.mstrikethrough:10
#: telebot.formatting.munderline:10
msgid ":obj:`str`"
msgstr ""
#: of telebot.formatting.escape_markdown:1
msgid "Escapes Markdown characters in a string of Markdown."
msgstr "Пропускает Markdown символы в Markdown строке."
#: of telebot.formatting.escape_markdown:3
msgid "Credits to: simonsmh"
msgstr ""
#: of telebot.formatting.escape_markdown:5
msgid "The string of Markdown to escape."
msgstr "Markdown строка, которую нужно пропустить."
#: of telebot.formatting.format_text:1
msgid "Formats a list of strings into a single string."
msgstr "Преобразовывает набор строк в одну."
#: of telebot.formatting.format_text:10
msgid "Strings to format."
msgstr "Строки для преобразования."
#: of telebot.formatting.format_text:13
msgid "The separator to use between each string."
msgstr "Символ для разделения строк."
#: of telebot.formatting.format_text:16 telebot.formatting.hbold:9
#: telebot.formatting.hcode:9 telebot.formatting.hitalic:9
#: telebot.formatting.hlink:12 telebot.formatting.hpre:9
#: telebot.formatting.hspoiler:9 telebot.formatting.hstrikethrough:9
#: telebot.formatting.hunderline:9 telebot.formatting.mbold:9
#: telebot.formatting.mcode:9 telebot.formatting.mitalic:9
#: telebot.formatting.mlink:12 telebot.formatting.mspoiler:9
#: telebot.formatting.mstrikethrough:9 telebot.formatting.munderline:9
msgid "The formatted string."
msgstr "Преобразованная строка."
#: of telebot.formatting.hbold:1
msgid "Returns an HTML-formatted bold string."
msgstr "Возвращает выделенную жирным шрифтом HTML строку."
#: of telebot.formatting.hbold:3 telebot.formatting.mbold:3
msgid "The string to bold."
msgstr "Строка для выделения жирным шрифтом."
#: of telebot.formatting.hbold:6 telebot.formatting.hcode:6
#: telebot.formatting.hitalic:6 telebot.formatting.hlink:9
#: telebot.formatting.hpre:6 telebot.formatting.hspoiler:6
#: telebot.formatting.hstrikethrough:6 telebot.formatting.hunderline:6
#: telebot.formatting.mbold:6 telebot.formatting.mcode:6
#: telebot.formatting.mitalic:6 telebot.formatting.mlink:9
#: telebot.formatting.mspoiler:6 telebot.formatting.mstrikethrough:6
#: telebot.formatting.munderline:6
msgid "True if you need to escape special characters. Defaults to True."
msgstr "True если вам нужно пропустить спец. символы. По умолчанию True."
#: of telebot.formatting.hcode:1
msgid "Returns an HTML-formatted code string."
msgstr "Возвращает выделенную как код HTML строку."
#: of telebot.formatting.hcode:3 telebot.formatting.mcode:3
msgid "The string to code."
msgstr "Строка для выделения как код."
#: of telebot.formatting.hide_link:1
msgid "Hide url of an image."
msgstr "Делает невидимым URL изображения."
#: of telebot.formatting.hide_link:3
msgid "The url of the image."
msgstr "URL изображения."
#: of telebot.formatting.hide_link:6
msgid "The hidden url."
msgstr "Невидимый URL."
#: of telebot.formatting.hitalic:1
msgid "Returns an HTML-formatted italic string."
msgstr "Возвращает выделенную курсивом HTML строку."
#: of telebot.formatting.hitalic:3 telebot.formatting.mitalic:3
msgid "The string to italicize."
msgstr "Строка для выделения курсивом."
#: of telebot.formatting.hlink:1
msgid "Returns an HTML-formatted link string."
msgstr "Возвращает HTML строку с гиперссылкой."
#: of telebot.formatting.hlink:3 telebot.formatting.mlink:3
msgid "The string to link."
msgstr "Строка для добавления гиперссылки."
#: of telebot.formatting.hlink:6 telebot.formatting.mlink:6
msgid "The URL to link to."
msgstr "URL для создания гиперссылки."
#: of telebot.formatting.hpre:1
msgid "Returns an HTML-formatted preformatted string."
msgstr "Возвращает предварительно отформатированную HTML строку."
#: of telebot.formatting.hpre:3
msgid "The string to preformatted."
msgstr "Строка для предварительного форматирования."
#: of telebot.formatting.hspoiler:1
msgid "Returns an HTML-formatted spoiler string."
msgstr "Возвращает выделенную как спойлер HTML строку."
#: of telebot.formatting.hspoiler:3 telebot.formatting.mspoiler:3
msgid "The string to spoiler."
msgstr "Строка для выделения как спойлер."
#: of telebot.formatting.hstrikethrough:1
msgid "Returns an HTML-formatted strikethrough string."
msgstr "Возвращает зачеркнутую HTML строку."
#: of telebot.formatting.hstrikethrough:3 telebot.formatting.mstrikethrough:3
msgid "The string to strikethrough."
msgstr "Строка для зачеркивания."
#: of telebot.formatting.hunderline:1
msgid "Returns an HTML-formatted underline string."
msgstr "Возвращает подчеркнутую HTML строку."
#: of telebot.formatting.hunderline:3 telebot.formatting.munderline:3
msgid "The string to underline."
msgstr "Строка для подчёркивания."
#: of telebot.formatting.mbold:1
msgid "Returns a Markdown-formatted bold string."
msgstr "Возвращает выделенную жирным шрифтом Markdown строку."
#: of telebot.formatting.mcode:1
msgid "Returns a Markdown-formatted code string."
msgstr "Возвращает выделенную как код Markdown строку."
#: of telebot.formatting.mitalic:1
msgid "Returns a Markdown-formatted italic string."
msgstr "Возвращает выделенную курсивом Markdown строку."
#: of telebot.formatting.mlink:1
msgid "Returns a Markdown-formatted link string."
msgstr "Возвращает Markdown строку с гиперссылкой."
#: of telebot.formatting.mspoiler:1
msgid "Returns a Markdown-formatted spoiler string."
msgstr "Возвращает выделенную как спойлер Markdown строку."
#: of telebot.formatting.mstrikethrough:1
msgid "Returns a Markdown-formatted strikethrough string."
msgstr "Возвращает зачеркнутую Markdown строку."
#: of telebot.formatting.munderline:1
msgid "Returns a Markdown-formatted underline string."
msgstr "Возвращает подчеркнутую Markdown строку."

View File

@ -1,128 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../index.rst:8
msgid "Welcome to pyTelegramBotAPI's documentation!"
msgstr "Добро пожаловать в документацию pyTelegramBotAPI!"
#: ../../index.rst:10
msgid "Official documentation of pyTelegramBotAPI"
msgstr "Официальная документация pyTelegramBotAPI"
#: ../../index.rst:10
msgid "ptba, pytba, pyTelegramBotAPI, documentation, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, документация, гайд"
#: ../../index.rst:17
msgid "TeleBot"
msgstr ""
#: ../../index.rst:18
msgid ""
"TeleBot is synchronous and asynchronous implementation of `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
msgstr ""
"TeleBot это синхронная и асинхронная реализация `Telegram Bot "
"API <https://core.telegram.org/bots/api>`_."
#: ../../index.rst:21
msgid "Chats"
msgstr "Чаты"
#: ../../index.rst:22
msgid ""
"English chat: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
msgstr ""
"Англоязычный чат: `Private chat "
"<https://telegram.me/joinchat/Bn4ixj84FIZVkwhk2jag6A>`__"
#: ../../index.rst:24
msgid ""
"Russian chat: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
msgstr ""
"Русскоязычный чат: `@pytelegrambotapi_talks_ru "
"<https://t.me/pytelegrambotapi_talks_ru>`__"
#: ../../index.rst:26
msgid "News: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
msgstr "Новости: `@pyTelegramBotAPI <https://t.me/pytelegrambotapi>`__"
#: ../../index.rst:28
msgid "Pypi: `Pypi <https://pypi.org/project/pyTelegramBotAPI/>`__"
msgstr ""
#: ../../index.rst:30
msgid ""
"Source: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
msgstr ""
"Исходники: `Github repository "
"<https://github.com/eternnoir/pyTelegramBotAPI>`__"
#: ../../index.rst:33
msgid "Some features:"
msgstr "Некоторые особенности:"
#: ../../index.rst:34
msgid "Easy to learn and use."
msgstr "Простой в изучении и использовании."
#: ../../index.rst:36
msgid "Easy to understand."
msgstr "Простой в понимании."
#: ../../index.rst:38
msgid "Both sync and async."
msgstr "И синхронный, и асинхронный."
#: ../../index.rst:40
msgid "Examples on features."
msgstr "Примеры возможностей."
#: ../../index.rst:42
msgid "States"
msgstr "Состояния (стейты, FSM)"
#: ../../index.rst:44
msgid "And more..."
msgstr "И другое..."
#: ../../index.rst:47
msgid "Content"
msgstr "Содержимое"
#: ../../index.rst:63
msgid "Indices and tables"
msgstr "Ссылки"
#: ../../index.rst:65
msgid ":ref:`genindex`"
msgstr ""
#: ../../index.rst:66
msgid ":ref:`modindex`"
msgstr ""
#: ../../index.rst:67
msgid ":ref:`search`"
msgstr ""

View File

@ -1,59 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../install.rst:3
msgid "Installation Guide"
msgstr "Гайд по установке"
#: ../../install.rst:5
msgid "Installation of pyTelegramBotAPI"
msgstr "Установка pyTelegramBotAPI"
#: ../../install.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, installation, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, установка, гайд"
#: ../../install.rst:11
msgid "Using PIP"
msgstr "Используя PIP"
#: ../../install.rst:17
msgid "Using pipenv"
msgstr "Используя pipenv"
#: ../../install.rst:23
msgid "By cloning repository"
msgstr "Клонируя репозиторий"
#: ../../install.rst:31
msgid "Directly using pip"
msgstr "Напрямую используя pip"
#: ../../install.rst:37
msgid "It is generally recommended to use the first option."
msgstr "Рекомендуется использовать первый вариант."
#: ../../install.rst:39
msgid ""
"While the API is production-ready, it is still under development and it "
"has regular updates, do not forget to update it regularly by calling:"
msgstr "Новые версии библиотеки имеют больше фич, улучшений и баг фиксов. Не забывайте"
" обновляться вызывая:"

View File

@ -1,40 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-29 14:44+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../quick_start.rst:4
msgid "Quick start"
msgstr "Быстрый старт"
#: ../../quick_start.rst:6
msgid "Quickstart guide"
msgstr "Быстрый старт - гайд"
#: ../../quick_start.rst:6
msgid "ptba, pytba, pyTelegramBotAPI, quickstart, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, быстрый старт, гайд"
#: ../../quick_start.rst:11
msgid "Synchronous TeleBot"
msgstr "Синхронный телебот"
#: ../../quick_start.rst:16
msgid "Asynchronous TeleBot"
msgstr "Асинхронный телебот"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,393 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2022, coder2020official
# This file is distributed under the same license as the pyTelegramBotAPI
# Documentation package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2022.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pyTelegramBotAPI Documentation \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-07-08 23:07+0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.1\n"
#: ../../source/util.rst:3
msgid "Utils"
msgstr "Утилиты"
#: ../../source/util.rst:5
msgid "Utils in pyTelegramBotAPI"
msgstr "Утилиты в pyTelegramBotAPI"
#: ../../source/util.rst:5
msgid "ptba, pytba, pyTelegramBotAPI, utils, guide"
msgstr "ptba, pytba, pyTelegramBotAPI, утилиты, гайд"
#: ../../source/util.rst:11
msgid "util file"
msgstr "Файл util"
#: of telebot.util.antiflood:1
msgid ""
"Use this function inside loops in order to avoid getting TooManyRequests "
"error. Example:"
msgstr ""
"Используйте эту функцию в циклах, чтобы избежать ошибки TooManyRequests. "
"Пример:"
#: of telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Parameters"
msgstr ""
#: of telebot.util.antiflood:10
msgid "The function to call"
msgstr "Вызываемая функция"
#: of telebot.util.antiflood:13
msgid "Number of retries to send"
msgstr ""
#: of telebot.util.antiflood:16
msgid "The arguments to pass to the function"
msgstr "Аргументы, для передачи в функцию"
#: of telebot.util.antiflood:19
msgid "The keyword arguments to pass to the function"
msgstr "Именованные аргументы для передачи в функцию"
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.antiflood
#: telebot.util.escape telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.parse_web_app_data telebot.util.quick_markup
#: telebot.util.smart_split telebot.util.split_string telebot.util.user_link
#: telebot.util.validate_web_app_data telebot.util.webhook_google_functions
msgid "Returns"
msgstr ""
#: of telebot.util.antiflood:22
msgid "None"
msgstr ""
#: of telebot.service_utils.chunks:1
msgid "Yield successive n-sized chunks from lst."
msgstr "Генерирует последовательные части списка, состоящие из n элементов."
#: ../../docstring of telebot.util.content_type_media:1
msgid "Contains all media content types."
msgstr "Содержит все виды медиа."
#: ../../docstring of telebot.util.content_type_service:1
msgid "Contains all service content types such as `User joined the group`."
msgstr "Содержит все виды сервисных сообщений, такие как `User joined the group`."
#: of telebot.util.escape:1
msgid ""
"Replaces the following chars in `text` ('&' with '&amp;', '<' with '&lt;'"
" and '>' with '&gt;')."
msgstr ""
"Заменяет следующие символы в `text` ('&' на '&amp;', '<' на '&lt;' и '>' "
"на '&gt;')."
#: of telebot.util.escape:3
msgid "the text to escape"
msgstr "Текст для замены символов"
#: of telebot.util.escape:4
msgid "the escaped text"
msgstr "Отформатированный текст"
#: of telebot.util.extract_arguments:1
msgid "Returns the argument after the command."
msgstr "Возвращает аргументы команды."
#: of telebot.util.extract_arguments:3 telebot.util.extract_command:4
msgid "Examples:"
msgstr "Примеры:"
#: of telebot.util.extract_arguments:10
msgid "String to extract the arguments from a command"
msgstr "Строка для извлечения аргументов команды"
#: of telebot.util.extract_arguments:13
msgid "the arguments if `text` is a command (according to is_command), else None."
msgstr ""
"Аргументы, если `text` является командой (согласно is_command), в "
"остальных случаях None."
#: of telebot.service_utils.generate_random_token
#: telebot.service_utils.is_bytes telebot.service_utils.is_dict
#: telebot.service_utils.is_pil_image telebot.util.extract_arguments
#: telebot.util.extract_command telebot.util.is_command
#: telebot.util.quick_markup telebot.util.smart_split telebot.util.split_string
#: telebot.util.user_link
msgid "Return type"
msgstr ""
#: of telebot.util.extract_arguments:14 telebot.util.extract_command:16
msgid ":obj:`str` or :obj:`None`"
msgstr ":obj:`str` или :obj:`None`"
#: of telebot.util.extract_command:1
msgid ""
"Extracts the command from `text` (minus the '/') if `text` is a command "
"(see is_command). If `text` is not a command, this function returns None."
msgstr ""
"Извлекает команду из `text` (исключает '/') если `text` является командой"
" (см. is_command). Если `text` не является командой, эта функция "
"возвращает None."
#: of telebot.util.extract_command:12
msgid "String to extract the command from"
msgstr "Строка, из которой нужно извлечь команду"
#: of telebot.util.extract_command:15
msgid "the command if `text` is a command (according to is_command), else None."
msgstr ""
"Команда, если `text` является командой (согласно is_command), в остальных"
" случаях None."
#: of telebot.service_utils.generate_random_token:1
msgid ""
"Generates a random token consisting of letters and digits, 16 characters "
"long."
msgstr ""
"Генерирует рандомный токен, состоящий из латинских букв и цифр длиной 16 "
"символов."
#: of telebot.service_utils.generate_random_token:3
msgid "a random token"
msgstr "Сгенерированный токен"
#: of telebot.service_utils.generate_random_token:4 telebot.util.user_link:22
msgid ":obj:`str`"
msgstr ""
#: of telebot.service_utils.is_bytes:1
msgid "Returns True if the given object is a bytes object."
msgstr "Возвращает True если полученный объект является bytes."
#: of telebot.service_utils.is_bytes:3 telebot.service_utils.is_dict:3
#: telebot.service_utils.is_pil_image:3
msgid "object to be checked"
msgstr "Объект для проверки"
#: of telebot.service_utils.is_bytes:6
msgid "True if the given object is a bytes object."
msgstr "True, если полученный объект является bytes."
#: of telebot.service_utils.is_bytes:7 telebot.service_utils.is_dict:7
#: telebot.service_utils.is_pil_image:7 telebot.util.is_command:7
msgid ":obj:`bool`"
msgstr ""
#: of telebot.util.is_command:1
msgid ""
"Checks if `text` is a command. Telegram chat commands start with the '/' "
"character."
msgstr ""
"Проверяет, является ли `text` командой. Команды в Telegram начинаются с "
"символа '/'."
#: of telebot.util.is_command:3
msgid "Text to check."
msgstr "Текст для проверки."
#: of telebot.util.is_command:6
msgid "True if `text` is a command, else False."
msgstr "True, если `text` является командой, иначе False."
#: of telebot.service_utils.is_dict:1
msgid "Returns True if the given object is a dictionary."
msgstr "Возвращает True, если полученный объект является словарём (dict)."
#: of telebot.service_utils.is_dict:6
msgid "True if the given object is a dictionary."
msgstr "True, если полученный объект является словарём (dict)."
#: of telebot.service_utils.is_pil_image:1
msgid "Returns True if the given object is a PIL.Image.Image object."
msgstr "Возвращает True, если полученный объект является PIL.Image.Image."
#: of telebot.service_utils.is_pil_image:6
msgid "True if the given object is a PIL.Image.Image object."
msgstr "True, если полученный объект является PIL.Image.Image."
#: of telebot.service_utils.is_string:1
msgid "Returns True if the given object is a string."
msgstr "Возвращает True, если полученный объект является строкой (str)."
#: of telebot.util.parse_web_app_data:1
msgid "Parses web app data."
msgstr "Обрабатывает данные, полученные от web app."
#: of telebot.util.parse_web_app_data:3 telebot.util.validate_web_app_data:3
msgid "The bot token"
msgstr "Токен бота"
#: of telebot.util.parse_web_app_data:6 telebot.util.validate_web_app_data:6
msgid "The raw init data"
msgstr "Необработанные данные"
#: of telebot.util.parse_web_app_data:9 telebot.util.validate_web_app_data:9
msgid "The parsed init data"
msgstr "Обработанные данные"
#: of telebot.util.quick_markup:1
msgid ""
"Returns a reply markup from a dict in this format: {'text': kwargs} This "
"is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2"
" = InlineKeyboardButton(...)'"
msgstr ""
"Возвращает reply markup из словаря следующего формата: {'text': kwargs}. "
"Удобно использовать вместо постоянного использования 'btn1 = "
"InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'"
#: of telebot.util.quick_markup:4 telebot.util.user_link:5
msgid "Example:"
msgstr "Пример:"
#: of telebot.util.quick_markup:6
msgid "Using quick_markup:"
msgstr "Используя quick_markup:"
#: of telebot.util.quick_markup:31
msgid ""
"a dict containing all buttons to create in this format: {text: kwargs} "
"{str:}"
msgstr ""
"Словарь, содержащий все кнопки для создания reply markup в следующем "
"формате: {text: kwargs} {str:}"
#: of telebot.util.quick_markup:34
msgid "number of :class:`telebot.types.InlineKeyboardButton` objects on each row"
msgstr ""
#: of telebot.util.quick_markup:37
msgid "InlineKeyboardMarkup"
msgstr ""
#: of telebot.util.quick_markup:38
msgid ":obj:`types.InlineKeyboardMarkup`"
msgstr ""
#: of telebot.util.smart_split:1
msgid ""
"Splits one string into multiple strings, with a maximum amount of "
"`chars_per_string` characters per string. This is very useful for "
"splitting one giant message into multiples. If `chars_per_string` > 4096:"
" `chars_per_string` = 4096. Splits by '\\n', '. ' or ' ' in exactly this "
"priority."
msgstr ""
"Разбивает строку на несколько, каждая из которых будет не длиннее "
"`characters_per_string`. Удобно использовать для разбиения одного "
"гигантского сообщения на несколько. Если `chars_per_string` > 4096: "
"`chars_per_string` = 4096. Разбивает строку по '\\n', '. ' или ' ' именно"
" в таком порядке."
#: of telebot.util.smart_split:6 telebot.util.split_string:4
msgid "The text to split"
msgstr "Текст для разбиения"
#: of telebot.util.smart_split:9
msgid "The number of maximum characters per part the text is split to."
msgstr ""
"Максимальное количество символов в части текста, на которые он будет "
"разбит."
#: of telebot.util.smart_split:12 telebot.util.split_string:10
msgid "The splitted text as a list of strings."
msgstr "Список частей разбитого текста."
#: of telebot.util.smart_split:13 telebot.util.split_string:11
msgid ":obj:`list` of :obj:`str`"
msgstr ""
#: of telebot.util.split_string:1
msgid ""
"Splits one string into multiple strings, with a maximum amount of "
"`chars_per_string` characters per string. This is very useful for "
"splitting one giant message into multiples."
msgstr ""
"Разбивает одну строку на несколько, каждая из которых будет не длиннее "
"`characters_per_string`. Удобно использовать для разбиения одного "
"гигантского сообщения на несколько."
#: of telebot.util.split_string:7
msgid "The number of characters per line the text is split into."
msgstr "Количество символов в одной строке, на которые будет разбит текст."
#: ../../docstring of telebot.util.update_types:1
msgid "All update types, should be used for allowed_updates parameter in polling."
msgstr ""
"Все виды апдейтов, рекомендуется использовать в качестве параметра "
"allowed_updates функции polling."
#: of telebot.util.user_link:1
msgid ""
"Returns an HTML user link. This is useful for reports. Attention: Don't "
"forget to set parse_mode to 'HTML'!"
msgstr ""
"Возвращает HTML ссылку на пользователя. Удобно использовать для отчетов. "
"Важно: Не забудьте установить значение 'HTML' в parse_mode!"
#: of telebot.util.user_link:11
msgid ""
"You can use formatting.* for all other formatting options(bold, italic, "
"links, and etc.) This method is kept for backward compatibility, and it "
"is recommended to use formatting.* for more options."
msgstr ""
"Вы можете использовать formatting.* во всех остальных вариантах "
"форматирования(bold, italic, links, и прочее). Этот метод сохранён для "
"обратной совместимости, рекомендуется использовать formatting.* для "
"большего количества вариантов."
#: of telebot.util.user_link:15
msgid "the user (not the user_id)"
msgstr "Пользователь (не id пользователя)"
#: of telebot.util.user_link:18
msgid "include the user_id"
msgstr "Добавить id пользователя"
#: of telebot.util.user_link:21
msgid "HTML user link"
msgstr "Ссылка на пользователя в формате HTML"
#: of telebot.util.validate_web_app_data:1
msgid "Validates web app data."
msgstr "Проверяет данные, полученные от web app."
#: of telebot.util.webhook_google_functions:1
msgid "A webhook endpoint for Google Cloud Functions FaaS."
msgstr "Endpoint вебхука для Google Cloud Functions FaaS."
#: of telebot.util.webhook_google_functions:3
msgid "The bot instance"
msgstr "Инстанс бота"
#: of telebot.util.webhook_google_functions:6
msgid "The request object"
msgstr "HTTP-запрос"
#: of telebot.util.webhook_google_functions:9
msgid "The response object"
msgstr "Объект, полученный в качестве ответа"
#~ msgid "int row width"
#~ msgstr "Количество кнопок в одной строке, int"

View File

@ -21,6 +21,14 @@ custom_filters file
:undoc-members:
:show-inheritance:
Synchronous storage for states
-------------------------------
.. automodule:: telebot.storage
:members:
:undoc-members:
:show-inheritance:
handler_backends file
--------------------------------
@ -35,7 +43,7 @@ Extensions
.. automodule:: telebot.ext.sync.webhooks
.. automodule:: telebot.ext.aio.webhooks
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,27 +0,0 @@
from telebot.async_telebot import AsyncTeleBot
from telebot.asyncio_handler_backends import ContinueHandling
bot = AsyncTeleBot('TOKEN')
@bot.message_handler(commands=['start'])
async def start(message):
await bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
async def start2(message):
"""
This handler comes after the first one, but it will never be called.
But you can call it by returning ContinueHandling() in the first handler.
If you return ContinueHandling() in the first handler, the next
registered handler with appropriate filters will be called.
"""
await bot.send_message(message.chat.id, 'Hello World2!')
import asyncio
asyncio.run(bot.polling()) # just a reminder that infinity polling
# wraps polling into try/except block just as sync version,
# but you can use any of them because neither of them stops if you
# pass non_stop=True

View File

@ -1,28 +0,0 @@
#!/usr/bin/python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
from telebot.async_telebot import AsyncTeleBot
bot = AsyncTeleBot('TOKEN')
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
async def send_welcome(message):
await bot.reply_to(message, """\
Hi there, I am EchoBot.
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
""")
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
@bot.message_handler(func=lambda message: True)
async def echo_message(message):
await bot.reply_to(message, message.text)
import asyncio
# only for versions 4.7.0+
asyncio.run(bot.polling(restart_on_change=True))

View File

@ -1,93 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This is an async echo bot using decorators and webhook with aiohttp
# It echoes any incoming text messages and does not use the polling method.
import logging
import ssl
import asyncio
from aiohttp import web
import telebot
from telebot.async_telebot import AsyncTeleBot
API_TOKEN = '<api_token>'
WEBHOOK_HOST = '<ip/host where the bot is running>'
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = '0.0.0.0' # In some VPS you may need to put here the IP addr
WEBHOOK_SSL_CERT = './webhook_cert.pem' # Path to the ssl certificate
WEBHOOK_SSL_PRIV = './webhook_pkey.pem' # Path to the ssl private key
WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT)
WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN)
# Quick'n'dirty SSL certificate generation:
#
# openssl genrsa -out webhook_pkey.pem 2048
# openssl req -new -x509 -days 3650 -key webhook_pkey.pem -out webhook_cert.pem
#
# When asked for "Common Name (e.g. server FQDN or YOUR name)" you should reply
# with the same value in you put in WEBHOOK_HOST
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = AsyncTeleBot(API_TOKEN)
# Process webhook calls
async def handle(request):
if request.match_info.get('token') == bot.token:
request_body_dict = await request.json()
update = telebot.types.Update.de_json(request_body_dict)
asyncio.ensure_future(bot.process_new_updates([update]))
return web.Response()
else:
return web.Response(status=403)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
async def send_welcome(message):
await bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
async def echo_message(message):
await bot.reply_to(message, message.text)
# Remove webhook and closing session before exiting
async def shutdown(app):
logger.info('Shutting down: removing webhook')
await bot.remove_webhook()
logger.info('Shutting down: closing session')
await bot.close_session()
async def setup():
# Remove webhook, it fails sometimes the set if there is a previous webhook
logger.info('Starting up: removing old webhook')
await bot.remove_webhook()
# Set webhook
logger.info('Starting up: setting webhook')
await bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
app = web.Application()
app.router.add_post('/{token}/', handle)
app.on_cleanup.append(shutdown)
return app
if __name__ == '__main__':
# Build ssl context
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain(WEBHOOK_SSL_CERT, WEBHOOK_SSL_PRIV)
# Start aiohttp server
web.run_app(
setup(),
host=WEBHOOK_LISTEN,
port=WEBHOOK_PORT,
ssl_context=context,
)

View File

@ -1,89 +0,0 @@
#!/usr/bin/env python
"""
Asynchronous Telegram Echo Bot example.
This is a simple bot that echoes each message that is received onto the chat.
It uses the Starlette ASGI framework to receive updates via webhook requests.
"""
import uvicorn
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import PlainTextResponse, Response
from starlette.routing import Route
from telebot.async_telebot import AsyncTeleBot
from telebot.types import Message, Update
API_TOKEN = "TOKEN"
WEBHOOK_HOST = "<ip/domain>"
WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open')
WEBHOOK_LISTEN = "0.0.0.0"
WEBHOOK_SSL_CERT = "./webhook_cert.pem" # Path to the ssl certificate
WEBHOOK_SSL_PRIV = "./webhook_pkey.pem" # Path to the ssl private key
WEBHOOK_URL = f"https://{WEBHOOK_HOST}:{WEBHOOK_PORT}/telegram"
WEBHOOK_SECRET_TOKEN = "SECRET_TOKEN"
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = AsyncTeleBot(token=API_TOKEN)
# BOT HANDLERS
@bot.message_handler(commands=["help", "start"])
async def send_welcome(message: Message):
"""
Handle '/start' and '/help'
"""
await bot.reply_to(
message,
("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you."),
)
@bot.message_handler(func=lambda _: True, content_types=["text"])
async def echo_message(message: Message):
"""
Handle all other messages
"""
await bot.reply_to(message, message.text)
# WEBSERVER HANDLERS
async def telegram(request: Request) -> Response:
"""Handle incoming Telegram updates."""
token_header_name = "X-Telegram-Bot-Api-Secret-Token"
if request.headers.get(token_header_name) != WEBHOOK_SECRET_TOKEN:
return PlainTextResponse("Forbidden", status_code=403)
await bot.process_new_updates([Update.de_json(await request.json())])
return Response()
async def startup() -> None:
"""Register webhook for telegram updates."""
webhook_info = await bot.get_webhook_info(30)
if WEBHOOK_URL != webhook_info.url:
logger.debug(
f"updating webhook url, old: {webhook_info.url}, new: {WEBHOOK_URL}"
)
if not await bot.set_webhook(
url=WEBHOOK_URL, secret_token=WEBHOOK_SECRET_TOKEN
):
raise RuntimeError("unable to set webhook")
app = Starlette(
routes=[
Route("/telegram", telegram, methods=["POST"]),
],
on_startup=[startup],
)
uvicorn.run(
app,
host=WEBHOOK_HOST,
port=WEBHOOK_LISTEN,
ssl_certfile=WEBHOOK_SSL_CERT,
ssl_keyfile=WEBHOOK_SSL_PRIV,
)

View File

@ -1,23 +0,0 @@
from telebot import TeleBot
from telebot.handler_backends import ContinueHandling
bot = TeleBot('TOKEN')
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
def start2(message):
"""
This handler comes after the first one, but it will never be called.
But you can call it by returning ContinueHandling() in the first handler.
If you return ContinueHandling() in the first handler, the next
registered handler with appropriate filters will be called.
"""
bot.send_message(message.chat.id, 'Hello World2!')
bot.infinity_polling()

View File

@ -1,28 +0,0 @@
#!/usr/bin/python
# This is a simple echo bot using the decorator mechanism.
# It echoes any incoming text messages.
import telebot
API_TOKEN = '<api_token>'
bot = telebot.TeleBot(API_TOKEN)
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message, """\
Hi there, I am EchoBot.
I am here to echo your kind words back to you. Just say anything nice and I'll say the exact same thing to you!\
""")
# Handle all other messages with content_type 'text' (content_types defaults to ['text'])
@bot.message_handler(func=lambda message: True)
def echo_message(message):
bot.reply_to(message, message.text)
# only for versions 4.7.0+
bot.infinity_polling(restart_on_change=True)

View File

@ -42,7 +42,7 @@ def query_video(inline_query):
try:
r = types.InlineQueryResultVideo('1',
'https://github.com/eternnoir/pyTelegramBotAPI/blob/master/tests/test_data/test_video.mp4?raw=true',
'video/mp4',
'video/mp4', 'Video',
'https://raw.githubusercontent.com/eternnoir/pyTelegramBotAPI/master/examples/detailed_example/rooster.jpg',
'Title'
)

View File

@ -1,32 +0,0 @@
#!/usr/bin/python
# This is an example file to create quiz polls
import telebot
API_TOKEN = "<api_token>"
bot = telebot.TeleBot(API_TOKEN)
@bot.message_handler(commands=["poll"])
def create_poll(message):
bot.send_message(message.chat.id, "English Article Test")
answer_options = ["a", "an", "the", "-"]
bot.send_poll(
chat_id=message.chat.id,
question="We are going to '' park.",
options=answer_options,
type="quiz",
correct_option_id=2,
is_anonymous=False,
)
@bot.poll_answer_handler()
def handle_poll(poll):
# This handler can be used to log User answers and to send next poll
pass
bot.infinity_polling()

View File

@ -1,50 +0,0 @@
"""
Example of running PyTelegramBotAPI serverless in Amazon AWS Lambdaю
You have to set your lambda's url as telegram webhook manually https://core.telegram.org/bots/api#setwebhook
"""
import logging
import telebot
import json
import os
API_TOKEN = os.environ['TELEGRAM_TOKEN']
logger = telebot.logger
telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN, threaded=False)
def process_event(event):
# Get telegram webhook json from event
request_body_dict = json.loads(event['body'])
# Parse updates from json
update = telebot.types.Update.de_json(request_body_dict)
# Run handlers and etc for updates
bot.process_new_updates([update])
def lambda_handler(event, context):
# Process event from aws and respond
process_event(event)
return {
'statusCode': 200
}
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)

View File

@ -6,7 +6,6 @@
import logging
import fastapi
import uvicorn
import telebot
API_TOKEN = 'TOKEN'
@ -34,14 +33,12 @@ telebot.logger.setLevel(logging.INFO)
bot = telebot.TeleBot(API_TOKEN)
app = fastapi.FastAPI(docs=None, redoc_url=None)
app = fastapi.FastAPI()
# Process webhook calls
@app.post(f'/{API_TOKEN}/')
def process_webhook(update: dict):
"""
Process webhook calls
"""
if update:
update = telebot.types.Update.de_json(update)
bot.process_new_updates([update])
@ -49,21 +46,18 @@ def process_webhook(update: dict):
return
# Handle '/start' and '/help'
@bot.message_handler(commands=['help', 'start'])
def send_welcome(message):
"""
Handle '/start' and '/help'
"""
bot.reply_to(message,
("Hi there, I am EchoBot.\n"
"I am here to echo your kind words back to you."))
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
"""
Handle all other messages
"""
bot.reply_to(message, message.text)
@ -71,12 +65,11 @@ def echo_message(message):
bot.remove_webhook()
# Set webhook
bot.set_webhook(
url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r')
)
bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH,
certificate=open(WEBHOOK_SSL_CERT, 'r'))
import uvicorn
uvicorn.run(
app,
host=WEBHOOK_LISTEN,

View File

@ -1,4 +1,4 @@
pytest
requests==2.31.0
wheel==0.38.1
requests==2.20.0
wheel==0.24.0
aiohttp>=3.8.0,<3.9.0

View File

@ -31,9 +31,6 @@ setup(name='pyTelegramBotAPI',
'aiohttp': 'aiohttp',
'fastapi': 'fastapi',
'uvicorn': 'uvicorn',
'psutil': 'psutil',
'coloredlogs': 'coloredlogs',
'watchdog': 'watchdog'
},
classifiers=[
'Development Status :: 5 - Production/Stable',

File diff suppressed because it is too large Load Diff

View File

@ -87,15 +87,6 @@ def _make_request(token, method_name, method='get', params=None, files=None):
logger.debug("Request: method={0} url={1} params={2} files={3}".format(method, request_url, params, files).replace(token, token.split(':')[0] + ":{TOKEN}"))
read_timeout = READ_TIMEOUT
connect_timeout = CONNECT_TIMEOUT
if files:
files_copy = dict(files)
# process types.InputFile
for key, value in files_copy.items():
if isinstance(value, types.InputFile):
files[key] = value.file
if files and format_header_param:
fields.format_header_param = _no_encode(format_header_param)
if params:
@ -111,13 +102,7 @@ def _make_request(token, method_name, method='get', params=None, files=None):
params = params or None # Set params to None if empty
result = None
if CUSTOM_REQUEST_SENDER:
# noinspection PyCallingNonCallable
result = CUSTOM_REQUEST_SENDER(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
elif RETRY_ON_ERROR and RETRY_ENGINE == 1:
if RETRY_ON_ERROR and RETRY_ENGINE == 1:
got_result = False
current_try = 0
while not got_result and current_try<MAX_RETRIES-1:
@ -152,6 +137,11 @@ def _make_request(token, method_name, method='get', params=None, files=None):
result = http.request(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
elif CUSTOM_REQUEST_SENDER:
# noinspection PyCallingNonCallable
result = CUSTOM_REQUEST_SENDER(
method, request_url, params=params, files=files,
timeout=(connect_timeout, read_timeout), proxies=proxy)
else:
result = _get_req_session().request(
method, request_url, params=params, files=files,
@ -237,8 +227,23 @@ def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
:param chat_id:
:param text:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification:
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
method_url = r'sendMessage'
payload = {'chat_id': str(chat_id), 'text': text}
if disable_web_page_preview is not None:
@ -259,8 +264,6 @@ def send_message(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, method='post')
@ -355,15 +358,15 @@ def get_chat_member_count(token, chat_id):
return _make_request(token, method_url, params=payload)
def set_sticker_set_thumbnail(token, name, user_id, thumbnail):
method_url = r'setStickerSetThumbnail'
def set_sticker_set_thumb(token, name, user_id, thumb):
method_url = r'setStickerSetThumb'
payload = {'name': name, 'user_id': user_id}
files = {}
if thumbnail:
if not isinstance(thumbnail, str):
files['thumbnail'] = thumbnail
if thumb:
if not isinstance(thumb, str):
files['thumb'] = thumb
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
return _make_request(token, method_url, params=payload, files=files or None)
@ -387,7 +390,7 @@ def get_chat_member(token, chat_id, user_id):
def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None, protect_content=None, message_thread_id=None):
disable_notification=None, timeout=None, protect_content=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
@ -396,14 +399,12 @@ def forward_message(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None):
reply_markup=None, timeout=None, protect_content=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@ -424,15 +425,13 @@ def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_m
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -449,8 +448,6 @@ def send_dice(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -458,8 +455,7 @@ def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -487,17 +483,13 @@ def send_photo(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendMediaGroup'
media_json, files = convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -511,8 +503,6 @@ def send_media_group(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -524,8 +514,7 @@ def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -548,8 +537,6 @@ def send_location(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -601,7 +588,7 @@ def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None, protect_content=None, message_thread_id=None):
google_place_type=None, protect_content=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -624,15 +611,13 @@ def send_venue(
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -651,26 +636,21 @@ def send_contact(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None):
def send_chat_action(token, chat_id, action, timeout=None):
method_url = r'sendChatAction'
payload = {'chat_id': chat_id, 'action': action}
if timeout:
payload['timeout'] = timeout
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -694,14 +674,14 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if width:
payload['width'] = width
if height:
@ -712,18 +692,13 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, width=None, height=None, message_thread_id=None,
has_spoiler=None):
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, width=None, height=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -745,14 +720,14 @@ def send_animation(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -763,16 +738,12 @@ def send_animation(
payload['width'] = width
if height:
payload['height'] = height
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -800,14 +771,11 @@ def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_mess
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumbnail=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -829,26 +797,24 @@ def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_m
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -874,29 +840,27 @@ def send_audio(token, chat_id, audio, caption=None, duration=None, performer=Non
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, files=files, method='post')
def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None,
protect_content = None, message_thread_id=None, emoji=None):
protect_content = None):
method_url = get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -919,14 +883,14 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
payload['timeout'] = timeout
if caption:
payload['caption'] = caption
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -935,10 +899,6 @@ def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_m
payload['protect_content'] = protect_content
if method_url == 'sendDocument' and disable_content_type_detection is not None:
payload['disable_content_type_detection'] = disable_content_type_detection
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if emoji:
payload['emoji'] = emoji
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -970,19 +930,36 @@ def unban_chat_member(token, chat_id, user_id, only_if_banned):
def restrict_chat_member(
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
method_url = 'restrictChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
else:
payload['until_date'] = until_date
return _make_request(token, method_url, params=payload, method='post')
@ -990,8 +967,7 @@ def promote_chat_member(
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None,
can_manage_topics=None):
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
@ -1016,8 +992,6 @@ def promote_chat_member(
payload['can_manage_chat'] = can_manage_chat
if can_manage_video_chats is not None:
payload['can_manage_video_chats'] = can_manage_video_chats
if can_manage_topics is not None:
payload['can_manage_topics'] = can_manage_topics
return _make_request(token, method_url, params=payload, method='post')
@ -1041,14 +1015,12 @@ def unban_chat_sender_chat(token, chat_id, sender_chat_id):
return _make_request(token, method_url, params=payload, method='post')
def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
def set_chat_permissions(token, chat_id, permissions):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return _make_request(token, method_url, params=payload, method='post')
@ -1154,39 +1126,6 @@ def set_chat_title(token, chat_id, title):
return _make_request(token, method_url, params=payload, method='post')
def set_my_description(token, description=None, language_code=None):
method_url = r'setMyDescription'
payload = {}
if description is not None:
payload['description'] = description
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_description(token, language_code=None):
method_url = r'getMyDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_my_short_description(token, short_description=None, language_code=None):
method_url = r'setMyShortDescription'
payload = {}
if short_description is not None:
payload['short_description'] = short_description
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_short_description(token, language_code=None):
method_url = r'getMyShortDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def get_my_commands(token, scope=None, language_code=None):
method_url = r'getMyCommands'
payload = {}
@ -1196,22 +1135,6 @@ def get_my_commands(token, scope=None, language_code=None):
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_my_name(token, name=None, language_code=None):
method_url = r'setMyName'
payload = {}
if name is not None:
payload['name'] = name
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload, method='post')
def get_my_name(token, language_code=None):
method_url = r'getMyName'
payload = {}
if language_code is not None:
payload['language_code'] = language_code
return _make_request(token, method_url, params=payload)
def set_chat_menu_button(token, chat_id=None, menu_button=None):
method_url = r'setChatMenuButton'
payload = {}
@ -1381,7 +1304,7 @@ def delete_message(token, chat_id, message_id, timeout=None):
def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1396,8 +1319,6 @@ def send_game(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -1463,7 +1384,7 @@ def send_invoice(
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
protect_content=None, message_thread_id=None):
protect_content=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@ -1495,8 +1416,7 @@ def send_invoice(
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
:param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:param protect_content:
:return:
"""
method_url = r'sendInvoice'
@ -1545,8 +1465,6 @@ def send_invoice(
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
@ -1614,7 +1532,7 @@ def answer_callback_query(token, callback_query_id, text=None, show_alert=None,
def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
button=None):
switch_pm_text=None, switch_pm_parameter=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': _convert_list_json_serializable(results)}
if cache_time is not None:
@ -1623,8 +1541,10 @@ def answer_inline_query(token, inline_query_id, results, cache_time=None, is_per
payload['is_personal'] = is_personal
if next_offset is not None:
payload['next_offset'] = next_offset
if button is not None:
payload["button"] = button.to_json()
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
return _make_request(token, method_url, params=payload, method='post')
@ -1632,88 +1552,57 @@ def get_sticker_set(token, name):
method_url = 'getStickerSet'
return _make_request(token, method_url, params={'name': name})
def get_custom_emoji_stickers(token, custom_emoji_ids):
method_url = r'getCustomEmojiStickers'
return _make_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)})
def set_sticker_keywords(token, sticker, keywords=None):
method_url = 'setStickerKeywords'
payload = {'sticker': sticker}
if keywords:
payload['keywords'] = json.dumps(keywords)
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_mask_position(token, sticker, mask_position=None):
method_url = 'setStickerMaskPosition'
payload = {'sticker': sticker}
if mask_position:
payload['mask_position'] = mask_position.to_json()
return _make_request(token, method_url, params=payload, method='post')
def upload_sticker_file(token, user_id, sticker, sticker_format):
def upload_sticker_file(token, user_id, png_sticker):
method_url = 'uploadStickerFile'
payload = {'user_id': user_id, 'sticker_format': sticker_format}
files = {'sticker': sticker}
payload = {'user_id': user_id}
files = {'png_sticker': png_sticker}
return _make_request(token, method_url, params=payload, files=files, method='post')
def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None):
method_url = 'setCustomEmojiStickerSetThumbnail'
payload = {'name': name}
if custom_emoji_id is not None:
payload['custom_emoji_id'] = custom_emoji_id
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_set_title(token, name, title):
method_url = 'setStickerSetTitle'
payload = {'name': name, 'title': title}
return _make_request(token, method_url, params=payload, method='post')
def delete_sticker_set(token, name):
method_url = 'deleteStickerSet'
payload = {'name': name}
return _make_request(token, method_url, params=payload, method='post')
def set_sticker_emoji_list(token, sticker, emoji_list):
method_url = 'setStickerEmojiList'
payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)}
return _make_request(token, method_url, params=payload, method='post')
def create_new_sticker_set(
token, user_id, name, title, stickers, sticker_format, sticker_type=None, needs_repainting=None):
token, user_id, name, title, emojis, png_sticker, tgs_sticker,
contains_masks=None, mask_position=None, webm_sticker=None):
method_url = 'createNewStickerSet'
payload = {'user_id': user_id, 'name': name, 'title': title, 'sticker_format': sticker_format}
if sticker_type:
payload['sticker_type'] = sticker_type
if needs_repainting:
payload['needs_repainting'] = needs_repainting
files = {}
lst = []
for sticker in stickers:
json_dict, file = sticker.convert_input_sticker()
json_dict = sticker.to_dict()
if file:
list_keys = list(file.keys())
files[list_keys[0]] = file[list_keys[0]]
lst.append(json_dict)
payload['stickers'] = json.dumps(lst)
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if contains_masks is not None:
payload['contains_masks'] = contains_masks
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
return _make_request(token, method_url, params=payload, files=files, method='post')
def add_sticker_to_set(token, user_id, name, sticker):
def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker):
method_url = 'addStickerToSet'
json_dict, files = sticker.convert_input_sticker()
payload = {'user_id': user_id, 'name': name, 'sticker': json_dict}
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
return _make_request(token, method_url, params=payload, files=files, method='post')
@ -1781,7 +1670,7 @@ def send_poll(
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1825,51 +1714,8 @@ def send_poll(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload)
def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
method_url = r'createForumTopic'
payload = {'chat_id': chat_id, 'name': name}
if icon_color:
payload['icon_color'] = icon_color
if icon_custom_emoji_id:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return _make_request(token, method_url, params=payload)
def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None):
method_url = r'editForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
if name is not None:
payload['name'] = name
if icon_custom_emoji_id is not None:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return _make_request(token, method_url, params=payload)
def close_forum_topic(token, chat_id, message_thread_id):
method_url = r'closeForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def reopen_forum_topic(token, chat_id, message_thread_id):
method_url = r'reopenForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def delete_forum_topic(token, chat_id, message_thread_id):
method_url = r'deleteForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def unpin_all_forum_topic_messages(token, chat_id, message_thread_id):
method_url = r'unpinAllForumTopicMessages'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return _make_request(token, method_url, params=payload)
def get_forum_topic_icon_stickers(token):
method_url = r'getForumTopicIconStickers'
return _make_request(token, method_url)
def stop_poll(token, chat_id, message_id, reply_markup=None):
method_url = r'stopPoll'
@ -1878,31 +1724,6 @@ def stop_poll(token, chat_id, message_id, reply_markup=None):
payload['reply_markup'] = _convert_markup(reply_markup)
return _make_request(token, method_url, params=payload)
def edit_general_forum_topic(token, chat_id, name):
method_url = r'editGeneralForumTopic'
payload = {'chat_id': chat_id, 'name': name}
return _make_request(token, method_url, params=payload)
def close_general_forum_topic(token, chat_id):
method_url = r'closeGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def reopen_general_forum_topic(token, chat_id):
method_url = r'reopenGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def hide_general_forum_topic(token, chat_id):
method_url = r'hideGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def unhide_general_forum_topic(token, chat_id):
method_url = r'unhideGeneralForumTopic'
payload = {'chat_id': chat_id}
return _make_request(token, method_url, params=payload)
def _convert_list_json_serializable(results):
ret = ''

File diff suppressed because it is too large Load Diff

View File

@ -420,7 +420,7 @@ class StateFilter(AdvancedCustomFilter):
text = text.name
if message.chat.type in ['group', 'supergroup']:
group_state = await self.bot.current_states.get_state(chat_id, user_id)
group_state = await self.bot.current_states.get_state(user_id, chat_id)
if group_state == text:
return True
elif type(text) is list and group_state in text:
@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
else:
user_state = await self.bot.current_states.get_state(chat_id, user_id)
user_state = await self.bot.current_states.get_state(user_id, chat_id)
if user_state == text:
return True
elif type(text) is list and user_state in text:

View File

@ -3,6 +3,8 @@ File with all middleware classes, states.
"""
class BaseMiddleware:
"""
Base class for middleware.
@ -74,18 +76,12 @@ class StatesGroup:
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None:
state_list = []
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))
value.group = cls
state_list.append(value)
cls._state_list = state_list
@property
def state_list(self):
return self._state_list
class SkipHandler:
@ -100,7 +96,6 @@ class SkipHandler:
def __init__(self) -> None:
pass
class CancelUpdate:
"""
Class for canceling updates.
@ -111,27 +106,4 @@ class CancelUpdate:
"""
def __init__(self) -> None:
pass
class ContinueHandling:
"""
Class for continue updates in handlers.
Just return instance of this class
in handlers to continue process.
.. code-block:: python3
:caption: Example of using ContinueHandling
@bot.message_handler(commands=['start'])
async def start(message):
await bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
async def start2(message):
await bot.send_message(message.chat.id, 'Hello World2!')
"""
def __init__(self) -> None:
pass
pass

View File

@ -13,17 +13,15 @@ API_URL = 'https://api.telegram.org/bot{0}/{1}'
from datetime import datetime
from telebot import util
import logging
from telebot import util, logger
logger = logging.getLogger('TeleBot')
proxy = None
session = None
FILE_URL = None
REQUEST_TIMEOUT = 300
REQUEST_TIMEOUT = None
MAX_RETRIES = 3
REQUEST_LIMIT = 50
@ -58,29 +56,10 @@ class SessionManager:
session_manager = SessionManager()
async def _process_request(token, url, method='get', params=None, files=None, **kwargs):
# Let's resolve all timeout parameters.
# getUpdates parameter may contain 2 parameters: request_timeout & timeout.
# other methods may contain timeout parameter that should be applied to
# ClientTimeout only.
# timeout should be added to params for getUpdates. All other timeout's should be used
# for request timeout.
# here we got request_timeout, so this is getUpdates method.
if 'request_timeout' in kwargs:
request_timeout = kwargs.pop('request_timeout')
else:
# let's check for timeout in params
request_timeout = params.pop('timeout', None) if params else None
# we will apply default request_timeout if there is no timeout in params
# otherwise, we will use timeout parameter applied for payload.
request_timeout = REQUEST_TIMEOUT if request_timeout is None else request_timeout
# Preparing data by adding all parameters and files to FormData
params = _prepare_data(params, files)
async def _process_request(token, url, method='get', params=None, files=None, request_timeout=None):
params = prepare_data(params, files)
if request_timeout is None:
request_timeout = REQUEST_TIMEOUT
timeout = aiohttp.ClientTimeout(total=request_timeout)
got_result = False
current_try=0
@ -104,17 +83,24 @@ async def _process_request(token, url, method='get', params=None, files=None, **
if not got_result:
raise RequestTimeout("Request timeout. Request: method={0} url={1} params={2} files={3} request_timeout={4}".format(method, url, params, files, request_timeout, current_try))
def _prepare_file(obj):
def prepare_file(obj):
"""
Prepares file for upload.
returns os.path.basename for a given file
:param obj:
:return:
"""
name = getattr(obj, 'name', None)
if name and isinstance(name, str) and name[0] != '<' and name[-1] != '>':
return os.path.basename(name)
def _prepare_data(params=None, files=None):
def prepare_data(params=None, files=None):
"""
Adds the parameters and files to the request.
prepare data for request.
:param params:
:param files:
@ -125,20 +111,18 @@ def _prepare_data(params=None, files=None):
if params:
for key, value in params.items():
data.add_field(key, str(value))
if files:
for key, f in files.items():
if isinstance(f, tuple):
if len(f) == 2:
file_name, file = f
filename, fileobj = f
else:
raise ValueError('Tuple must have exactly 2 elements: filename, fileobj')
elif isinstance(f, types.InputFile):
file_name = f.file_name
file = f.file
else:
file_name, file = _prepare_file(f) or key, f
filename, fileobj = prepare_file(f) or key, f
data.add_field(key, file, filename=file_name)
data.add_field(key, fileobj, filename=filename)
return data
@ -171,10 +155,10 @@ async def get_file(token, file_id):
async def get_file_url(token, file_id):
if FILE_URL is None:
return "https://api.telegram.org/file/bot{0}/{1}".format(token, (await get_file(token, file_id))['file_path'])
return "https://api.telegram.org/file/bot{0}/{1}".format(token, await get_file(token, file_id)['file_path'])
else:
# noinspection PyUnresolvedReferences
return FILE_URL.format(token, (await get_file(token, file_id))['file_path'])
return FILE_URL.format(token, await get_file(token, file_id)['file_path'])
async def download_file(token, file_path):
@ -183,12 +167,12 @@ async def download_file(token, file_path):
else:
# noinspection PyUnresolvedReferences
url = FILE_URL.format(token, file_path)
session = await session_manager.get_session()
async with session.get(url, proxy=proxy) as response:
if response.status != 200:
raise ApiHTTPException('Download file', response)
result = await response.read()
async with await session_manager.get_session() as session:
async with session.get(url, proxy=proxy) as response:
result = await response.read()
if response.status != 200:
raise ApiHTTPException('Download file', result)
return result
@ -245,11 +229,11 @@ async def get_updates(token, offset=None, limit=None,
params['limit'] = limit
if timeout:
params['timeout'] = timeout
if allowed_updates is not None: # Empty lists should pass
params['allowed_updates'] = json.dumps(allowed_updates)
if allowed_updates:
params['allowed_updates'] = allowed_updates
return await _process_request(token, method_name, params=params, request_timeout=request_timeout)
async def _check_result(method_name, result: aiohttp.ClientResponse):
async def _check_result(method_name, result):
"""
Checks whether `result` is a valid API response.
A result is considered invalid if:
@ -265,7 +249,7 @@ async def _check_result(method_name, result: aiohttp.ClientResponse):
try:
result_json = await result.json(encoding="utf-8")
except:
if result.status != 200:
if result.status_code != 200:
raise ApiHTTPException(method_name, result)
else:
raise ApiInvalidJSONException(method_name, result)
@ -280,8 +264,23 @@ async def send_message(
token, chat_id, text,
disable_web_page_preview=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
entities=None, allow_sending_without_reply=None, protect_content=None):
"""
Use this method to send text messages. On success, the sent Message is returned.
:param token:
:param chat_id:
:param text:
:param disable_web_page_preview:
:param reply_to_message_id:
:param reply_markup:
:param parse_mode:
:param disable_notification:
:param timeout:
:param entities:
:param allow_sending_without_reply:
:param protect_content:
:return:
"""
method_name = 'sendMessage'
params = {'chat_id': str(chat_id), 'text': text}
if disable_web_page_preview is not None:
@ -302,8 +301,6 @@ async def send_message(
params['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
params['protect_content'] = protect_content
if message_thread_id:
params['message_thread_id'] = message_thread_id
return await _process_request(token, method_name, params=params)
@ -343,15 +340,15 @@ async def get_chat_member_count(token, chat_id):
return await _process_request(token, method_url, params=payload)
async def set_sticker_set_thumbnail(token, name, user_id, thumbnail):
method_url = r'setStickerSetThumbnail'
async def set_sticker_set_thumb(token, name, user_id, thumb):
method_url = r'setStickerSetThumb'
payload = {'name': name, 'user_id': user_id}
files = {}
if thumbnail:
if not isinstance(thumbnail, str):
files['thumbnail'] = thumbnail
if thumb:
if not isinstance(thumb, str):
files['thumb'] = thumb
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
return await _process_request(token, method_url, params=payload, files=files or None)
@ -381,8 +378,7 @@ async def get_chat_member(token, chat_id, user_id):
async def forward_message(
token, chat_id, from_chat_id, message_id,
disable_notification=None, timeout=None, protect_content=None,
message_thread_id=None):
disable_notification=None, timeout=None, protect_content=None):
method_url = r'forwardMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if disable_notification is not None:
@ -391,14 +387,12 @@ async def forward_message(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, parse_mode=None, caption_entities=None,
disable_notification=None, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, protect_content=None, message_thread_id=None):
reply_markup=None, timeout=None, protect_content=None):
method_url = r'copyMessage'
payload = {'chat_id': chat_id, 'from_chat_id': from_chat_id, 'message_id': message_id}
if caption is not None:
@ -419,16 +413,13 @@ async def copy_message(token, chat_id, from_chat_id, message_id, caption=None, p
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_dice(
token, chat_id,
emoji=None, disable_notification=None, reply_to_message_id=None,
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
reply_markup=None, timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendDice'
payload = {'chat_id': chat_id}
if emoji:
@ -445,8 +436,6 @@ async def send_dice(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -454,8 +443,7 @@ async def send_photo(
token, chat_id, photo,
caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None, has_spoiler=None):
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendPhoto'
payload = {'chat_id': chat_id}
files = None
@ -483,17 +471,13 @@ async def send_photo(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_media_group(
token, chat_id, media,
disable_notification=None, reply_to_message_id=None,
timeout=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
timeout=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendMediaGroup'
media_json, files = await convert_input_media_array(media)
payload = {'chat_id': chat_id, 'media': media_json}
@ -507,8 +491,6 @@ async def send_media_group(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(
token, method_url, params=payload,
method='post' if files else 'get',
@ -520,7 +502,7 @@ async def send_location(
live_period=None, reply_to_message_id=None,
reply_markup=None, disable_notification=None,
timeout=None, horizontal_accuracy=None, heading=None,
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
proximity_alert_radius=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendLocation'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
if live_period:
@ -543,8 +525,6 @@ async def send_location(
payload['timeout'] = timeout
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -596,7 +576,7 @@ async def send_venue(
foursquare_id=None, foursquare_type=None, disable_notification=None,
reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, google_place_id=None,
google_place_type=None, protect_content=None, message_thread_id=None):
google_place_type=None, protect_content=None):
method_url = r'sendVenue'
payload = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude, 'title': title, 'address': address}
if foursquare_id:
@ -619,15 +599,13 @@ async def send_venue(
payload['google_place_type'] = google_place_type
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_contact(
token, chat_id, phone_number, first_name, last_name=None, vcard=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendContact'
payload = {'chat_id': chat_id, 'phone_number': phone_number, 'first_name': first_name}
if last_name:
@ -646,25 +624,21 @@ async def send_contact(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None):
async def send_chat_action(token, chat_id, action, timeout=None):
method_url = r'sendChatAction'
payload = {'chat_id': chat_id, 'action': action}
if timeout:
payload['timeout'] = timeout
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumbnail=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None,
protect_content=None, message_thread_id=None, has_spoiler=None):
parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None,
thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None,
protect_content=None):
method_url = r'sendVideo'
payload = {'chat_id': chat_id}
files = None
@ -688,14 +662,14 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if width:
payload['width'] = width
if height:
@ -706,18 +680,13 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_animation(
token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, width=None, height=None, protect_content=None, message_thread_id=None,
has_spoiler=None):
parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, width=None, height=None, protect_content=None):
method_url = r'sendAnimation'
payload = {'chat_id': chat_id}
files = None
@ -739,14 +708,14 @@ async def send_animation(
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -757,16 +726,12 @@ async def send_animation(
payload['height'] = height
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if has_spoiler is not None:
payload['has_spoiler'] = has_spoiler
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_to_message_id=None, reply_markup=None,
parse_mode=None, disable_notification=None, timeout=None, caption_entities=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVoice'
payload = {'chat_id': chat_id}
files = None
@ -794,14 +759,11 @@ async def send_voice(token, chat_id, voice, caption=None, duration=None, reply_t
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_video_note(token, chat_id, data, duration=None, length=None, reply_to_message_id=None, reply_markup=None,
disable_notification=None, timeout=None, thumbnail=None, allow_sending_without_reply=None, protect_content=None,
message_thread_id=None):
disable_notification=None, timeout=None, thumb=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendVideoNote'
payload = {'chat_id': chat_id}
files = None
@ -823,26 +785,24 @@ async def send_video_note(token, chat_id, data, duration=None, length=None, repl
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_audio(token, chat_id, audio, caption=None, duration=None, performer=None, title=None, reply_to_message_id=None,
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumbnail=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None,
caption_entities=None, allow_sending_without_reply=None, protect_content=None):
method_url = r'sendAudio'
payload = {'chat_id': chat_id}
files = None
@ -868,29 +828,26 @@ async def send_audio(token, chat_id, audio, caption=None, duration=None, perform
payload['disable_notification'] = disable_notification
if timeout:
payload['timeout'] = timeout
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, reply_markup=None, parse_mode=None,
disable_notification=None, timeout=None, caption=None, thumbnail=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None,
message_thread_id=None, emoji=None):
disable_notification=None, timeout=None, caption=None, thumb=None, caption_entities=None,
allow_sending_without_reply=None, disable_content_type_detection=None, visible_file_name=None, protect_content=None):
method_url = await get_method_by_type(data_type)
payload = {'chat_id': chat_id}
files = None
@ -913,14 +870,14 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r
payload['timeout'] = timeout
if caption:
payload['caption'] = caption
if thumbnail:
if not util.is_string(thumbnail):
if thumb:
if not util.is_string(thumb):
if files:
files['thumbnail'] = thumbnail
files['thumb'] = thumb
else:
files = {'thumbnail': thumbnail}
files = {'thumb': thumb}
else:
payload['thumbnail'] = thumbnail
payload['thumb'] = thumb
if caption_entities:
payload['caption_entities'] = json.dumps(types.MessageEntity.to_list_of_dicts(caption_entities))
if allow_sending_without_reply is not None:
@ -929,10 +886,6 @@ async def send_data(token, chat_id, data, data_type, reply_to_message_id=None, r
payload['protect_content'] = protect_content
if method_url == 'sendDocument' and disable_content_type_detection is not None:
payload['disable_content_type_detection'] = disable_content_type_detection
if message_thread_id:
payload['message_thread_id'] = message_thread_id
if emoji:
payload['emoji'] = emoji
return await _process_request(token, method_url, params=payload, files=files, method='post')
@ -964,13 +917,31 @@ async def unban_chat_member(token, chat_id, user_id, only_if_banned):
async def restrict_chat_member(
token, chat_id, user_id, permissions, until_date=None,
use_independent_chat_permissions=None):
token, chat_id, user_id, until_date=None,
can_send_messages=None, can_send_media_messages=None,
can_send_polls=None, can_send_other_messages=None,
can_add_web_page_previews=None, can_change_info=None,
can_invite_users=None, can_pin_messages=None):
method_url = 'restrictChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions.to_json()}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
permissions = {}
if can_send_messages is not None:
permissions['can_send_messages'] = can_send_messages
if can_send_media_messages is not None:
permissions['can_send_media_messages'] = can_send_media_messages
if can_send_polls is not None:
permissions['can_send_polls'] = can_send_polls
if can_send_other_messages is not None:
permissions['can_send_other_messages'] = can_send_other_messages
if can_add_web_page_previews is not None:
permissions['can_add_web_page_previews'] = can_add_web_page_previews
if can_change_info is not None:
permissions['can_change_info'] = can_change_info
if can_invite_users is not None:
permissions['can_invite_users'] = can_invite_users
if can_pin_messages is not None:
permissions['can_pin_messages'] = can_pin_messages
permissions_json = json.dumps(permissions)
payload = {'chat_id': chat_id, 'user_id': user_id, 'permissions': permissions_json}
if until_date is not None:
if isinstance(until_date, datetime):
payload['until_date'] = until_date.timestamp()
@ -983,7 +954,7 @@ async def promote_chat_member(
token, chat_id, user_id, can_change_info=None, can_post_messages=None,
can_edit_messages=None, can_delete_messages=None, can_invite_users=None,
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None):
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
@ -1008,8 +979,6 @@ async def promote_chat_member(
payload['can_manage_chat'] = can_manage_chat
if can_manage_video_chats is not None:
payload['can_manage_video_chats'] = can_manage_video_chats
if can_manage_topics is not None:
payload['can_manage_topics'] = can_manage_topics
return await _process_request(token, method_url, params=payload, method='post')
@ -1032,14 +1001,12 @@ async def unban_chat_sender_chat(token, chat_id, sender_chat_id):
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
return await _process_request(token, method_url, params=payload, method='post')
async def set_chat_permissions(token, chat_id, permissions, use_independent_chat_permissions=None):
async def set_chat_permissions(token, chat_id, permissions):
method_url = 'setChatPermissions'
payload = {
'chat_id': chat_id,
'permissions': permissions.to_json()
}
if use_independent_chat_permissions is not None:
payload['use_independent_chat_permissions'] = use_independent_chat_permissions
return await _process_request(token, method_url, params=payload, method='post')
@ -1142,37 +1109,6 @@ async def set_chat_title(token, chat_id, title):
payload = {'chat_id': chat_id, 'title': title}
return await _process_request(token, method_url, params=payload, method='post')
async def set_my_description(token, description=None, language_code=None):
method_url = r'setMyDescription'
payload = {}
if description is not None:
payload['description'] = description
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_description(token, language_code=None):
method_url = r'getMyDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_my_short_description(token, short_description=None, language_code=None):
method_url = r'setMyShortDescription'
payload = {}
if short_description is not None:
payload['short_description'] = short_description
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_short_description(token, language_code=None):
method_url = r'getMyShortDescription'
payload = {}
if language_code:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def get_my_commands(token, scope=None, language_code=None):
method_url = r'getMyCommands'
@ -1183,23 +1119,6 @@ async def get_my_commands(token, scope=None, language_code=None):
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_my_name(token, name=None, language_code=None):
method_url = r'setMyName'
payload = {}
if name is not None:
payload['name'] = name
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload, method='post')
async def get_my_name(token, language_code=None):
method_url = r'getMyName'
payload = {}
if language_code is not None:
payload['language_code'] = language_code
return await _process_request(token, method_url, params=payload)
async def set_chat_menu_button(token, chat_id=None, menu_button=None):
method_url = r'setChatMenuButton'
payload = {}
@ -1371,7 +1290,7 @@ async def delete_message(token, chat_id, message_id, timeout=None):
async def send_game(
token, chat_id, game_short_name,
disable_notification=None, reply_to_message_id=None, reply_markup=None, timeout=None,
allow_sending_without_reply=None, protect_content=None, message_thread_id=None):
allow_sending_without_reply=None, protect_content=None):
method_url = r'sendGame'
payload = {'chat_id': chat_id, 'game_short_name': game_short_name}
if disable_notification is not None:
@ -1386,8 +1305,6 @@ async def send_game(
payload['allow_sending_without_reply'] = allow_sending_without_reply
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -1452,8 +1369,7 @@ async def send_invoice(
need_name=None, need_phone_number=None, need_email=None, need_shipping_address=None,
send_phone_number_to_provider = None, send_email_to_provider = None, is_flexible=None,
disable_notification=None, reply_to_message_id=None, reply_markup=None, provider_data=None,
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None,
protect_content=None, message_thread_id=None):
timeout=None, allow_sending_without_reply=None, max_tip_amount=None, suggested_tip_amounts=None, protect_content=None):
"""
Use this method to send invoices. On success, the sent Message is returned.
:param token: Bot's token (you don't need to fill this)
@ -1485,8 +1401,7 @@ async def send_invoice(
:param max_tip_amount: The maximum accepted amount for tips in the smallest units of the currency
:param suggested_tip_amounts: A JSON-serialized array of suggested amounts of tips in the smallest units of the currency.
At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount.
:param protect_content: Protects the contents of the sent message from forwarding and saving
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum supergroups only
:param protect_content:
:return:
"""
method_url = r'sendInvoice'
@ -1535,8 +1450,6 @@ async def send_invoice(
payload['suggested_tip_amounts'] = json.dumps(suggested_tip_amounts)
if protect_content is not None:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
@ -1604,7 +1517,7 @@ async def answer_callback_query(token, callback_query_id, text=None, show_alert=
async def answer_inline_query(token, inline_query_id, results, cache_time=None, is_personal=None, next_offset=None,
button=None):
switch_pm_text=None, switch_pm_parameter=None):
method_url = 'answerInlineQuery'
payload = {'inline_query_id': inline_query_id, 'results': await _convert_list_json_serializable(results)}
if cache_time is not None:
@ -1613,10 +1526,10 @@ async def answer_inline_query(token, inline_query_id, results, cache_time=None,
payload['is_personal'] = is_personal
if next_offset is not None:
payload['next_offset'] = next_offset
if button is not None:
payload["button"] = button.to_json()
if switch_pm_text:
payload['switch_pm_text'] = switch_pm_text
if switch_pm_parameter:
payload['switch_pm_parameter'] = switch_pm_parameter
return await _process_request(token, method_url, params=payload, method='post')
@ -1624,87 +1537,61 @@ async def get_sticker_set(token, name):
method_url = 'getStickerSet'
return await _process_request(token, method_url, params={'name': name})
async def get_custom_emoji_stickers(token, custom_emoji_ids):
method_url = r'getCustomEmojiStickers'
return await _process_request(token, method_url, params={'custom_emoji_ids': json.dumps(custom_emoji_ids)})
async def set_sticker_keywords(token, sticker, keywords=None):
method_url = 'setStickerKeywords'
payload = {'sticker': sticker}
if keywords:
payload['keywords'] = json.dumps(keywords)
return await _process_request(token, method_url, params=payload, method='post')
async def set_sticker_mask_position(token, sticker, mask_position=None):
method_url = 'setStickerMaskPosition'
payload = {'sticker': sticker}
if mask_position:
payload['mask_position'] = mask_position.to_json()
return await _process_request(token, method_url, params=payload, method='post')
async def upload_sticker_file(token, user_id, sticker, sticker_format):
async def upload_sticker_file(token, user_id, png_sticker):
method_url = 'uploadStickerFile'
payload = {'user_id': user_id, 'sticker_format': sticker_format}
files = {'sticker': sticker}
payload = {'user_id': user_id}
files = {'png_sticker': png_sticker}
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def set_sticker_emoji_list(token, sticker, emoji_list):
method_url = 'setStickerEmojiList'
payload = {'sticker': sticker, 'emoji_list': json.dumps(emoji_list)}
return await _process_request(token, method_url, params=payload, method='post')
async def delete_sticker_set(token, name):
method_url = 'deleteStickerSet'
payload = {'name': name}
return await _process_request(token, method_url, params=payload, method='post')
async def set_custom_emoji_sticker_set_thumbnail(token, name, custom_emoji_id=None):
method_url = 'setCustomEmojiStickerSetThumbnail'
payload = {'name': name}
if custom_emoji_id is not None:
payload['custom_emoji_id'] = custom_emoji_id
return await _process_request(token, method_url, params=payload, method='post')
async def set_sticker_set_title(token, name, title):
method_url = 'setStickerSetTitle'
payload = {'name': name, 'title': title}
return await _process_request(token, method_url, params=payload, method='post')
async def create_new_sticker_set(
token, user_id, name, title, stickers, sticker_format, sticker_type=None, needs_repainting=None):
token, user_id, name, title, emojis, png_sticker, tgs_sticker,
contains_masks=None, mask_position=None, webm_sticker=None):
method_url = 'createNewStickerSet'
payload = {'user_id': user_id, 'name': name, 'title': title, 'sticker_format': sticker_format}
if sticker_type:
payload['sticker_type'] = sticker_type
if needs_repainting:
payload['needs_repainting'] = needs_repainting
files = {}
lst = []
for sticker in stickers:
json_dict, file = sticker.convert_input_sticker()
json_dict = sticker.to_dict()
if file:
list_keys = list(file.keys())
files[list_keys[0]] = file[list_keys[0]]
lst.append(json_dict)
payload['stickers'] = json.dumps(lst)
payload = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
sticker = png_sticker or tgs_sticker or webm_sticker
files = None
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if contains_masks is not None:
payload['contains_masks'] = contains_masks
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
return await _process_request(token, method_url, params=payload, files=files, method='post')
async def add_sticker_to_set(token, user_id, name, sticker):
async def add_sticker_to_set(token, user_id, name, emojis, png_sticker, tgs_sticker, mask_position, webm_sticker):
method_url = 'addStickerToSet'
json_dict, files = sticker.convert_input_sticker()
payload = {'user_id': user_id, 'name': name, 'sticker': json_dict}
payload = {'user_id': user_id, 'name': name, 'emojis': emojis}
if png_sticker:
stype = 'png_sticker'
elif webm_sticker:
stype = 'webm_sticker'
else:
stype = 'tgs_sticker'
files = None
sticker = png_sticker or tgs_sticker or webm_sticker
if not util.is_string(sticker):
files = {stype: sticker}
else:
payload[stype] = sticker
if mask_position:
payload['mask_position'] = mask_position.to_json()
if webm_sticker:
payload['webm_sticker'] = webm_sticker
return await _process_request(token, method_url, params=payload, files=files, method='post')
@ -1768,7 +1655,7 @@ async def send_poll(
is_anonymous = None, type = None, allows_multiple_answers = None, correct_option_id = None,
explanation = None, explanation_parse_mode=None, open_period = None, close_date = None, is_closed = None,
disable_notification=False, reply_to_message_id=None, allow_sending_without_reply=None,
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None, message_thread_id=None):
reply_markup=None, timeout=None, explanation_entities=None, protect_content=None):
method_url = r'sendPoll'
payload = {
'chat_id': str(chat_id),
@ -1812,76 +1699,6 @@ async def send_poll(
types.MessageEntity.to_list_of_dicts(explanation_entities))
if protect_content:
payload['protect_content'] = protect_content
if message_thread_id:
payload['message_thread_id'] = message_thread_id
return await _process_request(token, method_url, params=payload)
async def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_id=None):
method_url = r'createForumTopic'
payload = {'chat_id': chat_id, 'name': name}
if icon_color:
payload['icon_color'] = icon_color
if icon_custom_emoji_id:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return await _process_request(token, method_url, params=payload)
async def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None):
method_url = r'editForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
if name is not None:
payload['name'] = name
if icon_custom_emoji_id is not None:
payload['icon_custom_emoji_id'] = icon_custom_emoji_id
return await _process_request(token, method_url, params=payload)
async def close_forum_topic(token, chat_id, message_thread_id):
method_url = r'closeForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def reopen_forum_topic(token, chat_id, message_thread_id):
method_url = r'reopenForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def delete_forum_topic(token, chat_id, message_thread_id):
method_url = r'deleteForumTopic'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def unpin_all_forum_topic_messages(token, chat_id, message_thread_id):
method_url = r'unpinAllForumTopicMessages'
payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id}
return await _process_request(token, method_url, params=payload)
async def get_forum_topic_icon_stickers(token):
method_url = r'getForumTopicIconStickers'
return await _process_request(token, method_url)
async def edit_general_forum_topic(token, chat_id, name):
method_url = r'editGeneralForumTopic'
payload = {'chat_id': chat_id, 'name': name}
return await _process_request(token, method_url, params=payload)
async def close_general_forum_topic(token, chat_id):
method_url = r'closeGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def reopen_general_forum_topic(token, chat_id):
method_url = r'reopenGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def hide_general_forum_topic(token, chat_id):
method_url = r'hideGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def unhide_general_forum_topic(token, chat_id):
method_url = r'unhideGeneralForumTopic'
payload = {'chat_id': chat_id}
return await _process_request(token, method_url, params=payload)
async def _convert_list_json_serializable(results):
@ -1974,10 +1791,10 @@ class ApiHTTPException(ApiException):
This class represents an Exception thrown when a call to the
Telegram API server returns HTTP code that is not 200.
"""
def __init__(self, function_name, result: aiohttp.ClientResponse):
def __init__(self, function_name, result):
super(ApiHTTPException, self).__init__(
"The server returned HTTP {0} {1}. Response body:\n[{2}]" \
.format(result.status, result.reason, result.request_info),
.format(result.status_code, result.reason, result),
function_name,
result)

View File

@ -28,7 +28,7 @@ class StatePickleStorage(StateStorageBase):
"""
Create directory .save-handlers.
"""
dirs, filename = os.path.split(self.file_path)
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:

View File

@ -1,16 +1,12 @@
from telebot.asyncio_storage.base_storage import StateStorageBase, StateContext
import json
redis_installed = True
is_actual_aioredis = False
try:
import aioredis
is_actual_aioredis = True
except ImportError:
try:
from redis import asyncio as aioredis
except ImportError:
redis_installed = False
except:
redis_installed = False
class StateRedisStorage(StateStorageBase):
@ -24,10 +20,10 @@ class StateRedisStorage(StateStorageBase):
if not redis_installed:
raise ImportError('AioRedis is not installed. Install it via "pip install aioredis"')
if is_actual_aioredis:
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
if aioredis_version < (2,):
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
aioredis_version = tuple(map(int, aioredis.__version__.split(".")[0]))
if aioredis_version < (2,):
raise ImportError('Invalid aioredis version. Aioredis version should be >= 2.0.0')
self.redis = aioredis.Redis(host=host, port=port, db=db, password=password)
self.prefix = prefix
@ -171,6 +167,6 @@ class StateRedisStorage(StateStorageBase):
user_id = str(user_id)
if response:
if user_id in response:
response[user_id]['data'] = data
response[user_id]['data'] = dict(data, **response[user_id]['data'])
await self.set_record(chat_id, response)
return True

View File

@ -428,7 +428,7 @@ class StateFilter(AdvancedCustomFilter):
text = text.name
if message.chat.type in ['group', 'supergroup']:
group_state = self.bot.current_states.get_state(chat_id, user_id)
group_state = self.bot.current_states.get_state(user_id, chat_id)
if group_state == text:
return True
elif type(text) is list and group_state in text:
@ -436,7 +436,7 @@ class StateFilter(AdvancedCustomFilter):
else:
user_state = self.bot.current_states.get_state(chat_id, user_id)
user_state = self.bot.current_states.get_state(user_id, chat_id)
if user_state == text:
return True
elif type(text) is list and user_state in text:

View File

@ -25,11 +25,11 @@ from typing import Optional
class AsyncWebhookListener:
def __init__(self, bot,
secret_token: str,
host: Optional[str]="127.0.0.1",
secret_token: str, host: Optional[str]="127.0.0.1",
port: Optional[int]=443,
ssl_context: Optional[tuple]=None,
url_path: Optional[str]=None,
debug: Optional[bool]=False
) -> None:
"""
Aynchronous implementation of webhook listener
@ -55,6 +55,9 @@ class AsyncWebhookListener:
:param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
@ -69,6 +72,7 @@ class AsyncWebhookListener:
self._host = host
self._ssl_context = ssl_context
self._url_path = url_path
self._debug = debug
self._prepare_endpoint_urls()
@ -115,6 +119,7 @@ class AsyncWebhookListener:
config = Config(app=self.app,
host=self._host,
port=self._port,
debug=self._debug,
ssl_certfile=self._ssl_context[0],
ssl_keyfile=self._ssl_context[1]
)

View File

@ -1,31 +0,0 @@
from watchdog.events import FileSystemEventHandler
from watchdog.events import FileSystemEvent
import psutil
import os
import sys
import logging
logger = logging.getLogger('TeleBot')
class EventHandler(FileSystemEventHandler):
def on_any_event(self, event: FileSystemEvent):
logger.info('* Detected changes in: %s, reloading', (event.src_path))
restart_file()
def restart_file():
try:
p = psutil.Process(os.getpid())
for handler in p.open_files() + p.connections():
os.close(handler.fd)
except OSError:
pass
except Exception as e:
logger.error(e)
python = sys.executable
if os.name == 'nt':
os.execv(sys.executable, ['python'] + sys.argv)
else:
os.execl(python, python, *sys.argv)

View File

@ -1,5 +1,6 @@
"""
This file is used by TeleBot.run_webhooks() function.
Fastapi is required to run this script.
"""
@ -14,27 +15,31 @@ try:
except ImportError:
fastapi_installed = False
from telebot.types import Update
from typing import Optional
class SyncWebhookListener:
def __init__(self, bot,
secret_token: str,
host: Optional[str]="127.0.0.1",
secret_token: str, host: Optional[str]="127.0.0.1",
port: Optional[int]=443,
ssl_context: Optional[tuple]=None,
url_path: Optional[str]=None,
debug: Optional[bool]=False
) -> None:
"""
Synchronous implementation of webhook listener
for synchronous version of telebot.
Aynchronous implementation of webhook listener
for asynchronous version of telebot.
Not supposed to be used manually by user.
Use TeleBot.run_webhooks() instead.
Use AsyncTeleBot.run_webhooks() instead.
:param bot: TeleBot instance.
:type bot: telebot.TeleBot
:param bot: AsyncTeleBot instance.
:type bot: telebot.async_telebot.AsyncTeleBot
:param secret_token: Telegram secret token
:type secret_token: str
@ -51,6 +56,9 @@ class SyncWebhookListener:
:param url_path: Webhook url path
:type url_path: str
:param debug: Debug mode
:type debug: bool
:raises ImportError: If FastAPI or uvicorn is not installed.
:raises ImportError: If Starlette version is too old.
@ -65,11 +73,11 @@ class SyncWebhookListener:
self._host = host
self._ssl_context = ssl_context
self._url_path = url_path
self._debug = debug
self._prepare_endpoint_urls()
@staticmethod
def _check_dependencies():
def _check_dependencies(self):
if not fastapi_installed:
raise ImportError('Fastapi or uvicorn is not installed. Please install it via pip.')
@ -111,6 +119,7 @@ class SyncWebhookListener:
uvicorn.run(app=self.app,
host=self._host,
port=self._port,
debug=self._debug,
ssl_certfile=self._ssl_context[0],
ssl_keyfile=self._ssl_context[1]
)

View File

@ -61,8 +61,8 @@ def escape_markdown(content: str) -> str:
:rtype: :obj:`str`
"""
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\\\1", content)
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!\{\}\\])", r"\1", parse)
parse = re.sub(r"([_*\[\]()~`>\#\+\-=|\.!])", r"\\\1", content)
reparse = re.sub(r"\\\\([_*\[\]()~`>\#\+\-=|\.!])", r"\1", parse)
return reparse
@ -323,4 +323,4 @@ def hide_link(url: str) -> str:
:return: The hidden url.
:rtype: :obj:`str`
"""
return f'<a href="{url}">&#8288;</a>'
return f'<a href="{url}">&#8288;</a>'

View File

@ -174,6 +174,7 @@ class State:
def __str__(self) -> str:
return self.name
class StatesGroup:
"""
@ -185,20 +186,16 @@ class StatesGroup:
my_state = State() # returns my_state:State string.
"""
def __init_subclass__(cls) -> None:
state_list = []
for name, value in cls.__dict__.items():
if not name.startswith('__') and not callable(value) and isinstance(value, State):
# change value of that variable
value.name = ':'.join((cls.__name__, name))
value.group = cls
state_list.append(value)
cls._state_list = state_list
@property
def state_list(self):
return self._state_list
class BaseMiddleware:
"""
Base class for middleware.
@ -256,10 +253,10 @@ class SkipHandler:
Update will go to post_process,
but will skip execution of handler.
"""
def __init__(self) -> None:
pass
class CancelUpdate:
"""
Class for canceling updates.
@ -268,28 +265,6 @@ class CancelUpdate:
Update will skip handler and execution
of post_process in middlewares.
"""
def __init__(self) -> None:
pass
class ContinueHandling:
"""
Class for continue updates in handlers.
Just return instance of this class
in handlers to continue process.
.. code-block:: python3
:caption: Example of using ContinueHandling
@bot.message_handler(commands=['start'])
def start(message):
bot.send_message(message.chat.id, 'Hello World!')
return ContinueHandling()
@bot.message_handler(commands=['start'])
def start2(message):
bot.send_message(message.chat.id, 'Hello World2!')
"""
def __init__(self) -> None:
pass
pass

View File

@ -1,84 +0,0 @@
import random
import string
from io import BytesIO
try:
# noinspection PyPackageRequirements
from PIL import Image
pil_imported = True
except ImportError:
pil_imported = False
def is_string(var) -> bool:
"""
Returns True if the given object is a string.
"""
return isinstance(var, str)
def is_dict(var) -> bool:
"""
Returns True if the given object is a dictionary.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a dictionary.
:rtype: :obj:`bool`
"""
return isinstance(var, dict)
def is_bytes(var) -> bool:
"""
Returns True if the given object is a bytes object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a bytes object.
:rtype: :obj:`bool`
"""
return isinstance(var, bytes)
def is_pil_image(var) -> bool:
"""
Returns True if the given object is a PIL.Image.Image object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a PIL.Image.Image object.
:rtype: :obj:`bool`
"""
return pil_imported and isinstance(var, Image.Image)
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
if pil_imported:
photoBuffer = BytesIO()
image.convert('RGB').save(photoBuffer, extension, quality=quality)
photoBuffer.seek(0)
return photoBuffer
else:
raise RuntimeError('PIL module is not imported')
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
# https://stackoverflow.com/a/312464/9935473
for i in range(0, len(lst), n):
yield lst[i:i + n]
def generate_random_token() -> str:
"""
Generates a random token consisting of letters and digits, 16 characters long.
:return: a random token
:rtype: :obj:`str`
"""
return ''.join(random.sample(string.ascii_letters, 16))

View File

@ -41,10 +41,7 @@ class StateStorageBase:
def get_state(self, chat_id, user_id):
raise NotImplementedError
def get_interactive_data(self, chat_id, user_id):
raise NotImplementedError
def save(self, chat_id, user_id, data):
raise NotImplementedError

View File

@ -3,7 +3,6 @@ from telebot.storage.base_storage import StateStorageBase, StateContext
class StateMemoryStorage(StateStorageBase):
def __init__(self) -> None:
super().__init__()
self.data = {}
#
# {chat_id: {user_id: {'state': None, 'data': {}}, ...}, ...}

View File

@ -5,8 +5,8 @@ import pickle
class StatePickleStorage(StateStorageBase):
# noinspection PyMissingConstructor
def __init__(self, file_path="./.state-save/states.pkl") -> None:
super().__init__()
self.file_path = file_path
self.create_dir()
self.data = self.read()
@ -34,7 +34,7 @@ class StatePickleStorage(StateStorageBase):
"""
Create directory .save-handlers.
"""
dirs, filename = os.path.split(self.file_path)
dirs = self.file_path.rsplit('/', maxsplit=1)[0]
os.makedirs(dirs, exist_ok=True)
if not os.path.isfile(self.file_path):
with open(self.file_path,'wb') as file:

View File

@ -16,7 +16,6 @@ class StateRedisStorage(StateStorageBase):
TeleBot(storage=StateRedisStorage())
"""
def __init__(self, host='localhost', port=6379, db=0, password=None, prefix='telebot_'):
super().__init__()
self.redis = ConnectionPool(host=host, port=port, db=db, password=password)
#self.con = Redis(connection_pool=self.redis) -> use this when necessary
#
@ -174,7 +173,7 @@ class StateRedisStorage(StateStorageBase):
user_id = str(user_id)
if response:
if user_id in response:
response[user_id]['data'] = data
response[user_id]['data'] = dict(data, **response[user_id]['data'])
self.set_record(chat_id, response)
return True

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
import random
import re
import string
import threading
import traceback
from typing import Any, Callable, List, Dict, Optional, Union
@ -12,13 +14,21 @@ import queue as Queue
import logging
from telebot import types
from telebot.service_utils import is_pil_image, is_dict, is_string, is_bytes, chunks, generate_random_token, pil_image_to_file
try:
import ujson as json
except ImportError:
import json
try:
# noinspection PyPackageRequirements
from PIL import Image
from io import BytesIO
pil_imported = True
except:
pil_imported = False
MAX_MESSAGE_LENGTH = 4096
logger = logging.getLogger('TeleBot')
@ -27,25 +37,23 @@ thread_local = threading.local()
#: Contains all media content types.
content_type_media = [
'text', 'audio', 'document', 'animation', 'game', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact',
'location', 'venue', 'dice', 'invoice', 'successful_payment', 'connected_website', 'poll', 'passport_data',
'web_app_data',
'text', 'audio', 'animation', 'document', 'photo', 'sticker', 'video', 'video_note', 'voice', 'contact', 'dice', 'poll',
'venue', 'location'
]
#: Contains all service content types such as `User joined the group`.
content_type_service = [
'new_chat_members', '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', 'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started',
'video_chat_ended', 'video_chat_participants_invited', 'message_auto_delete_timer_changed', 'forum_topic_created',
'forum_topic_closed', 'forum_topic_reopened', 'user_shared', 'chat_shared',
'new_chat_members', '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',
'proximity_alert_triggered', 'video_chat_scheduled', 'video_chat_started', 'video_chat_ended',
'video_chat_participants_invited', 'message_auto_delete_timer_changed'
]
#: All update types, should be used for allowed_updates parameter in polling.
update_types = [
"message", "edited_message", "channel_post", "edited_channel_post", "inline_query", "chosen_inline_result",
"callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer", "my_chat_member", "chat_member",
"chat_join_request",
"message", "edited_message", "channel_post", "edited_channel_post", "inline_query",
"chosen_inline_result", "callback_query", "shipping_query", "pre_checkout_query", "poll", "poll_answer",
"my_chat_member", "chat_member", "chat_join_request"
]
@ -119,7 +127,6 @@ class ThreadPool:
"""
:meta private:
"""
def __init__(self, telebot, num_threads=2):
self.telebot = telebot
self.tasks = Queue.Queue()
@ -153,15 +160,13 @@ class ThreadPool:
for worker in self.workers:
worker.stop()
for worker in self.workers:
if worker != threading.current_thread():
worker.join()
worker.join()
class AsyncTask:
"""
:meta private:
"""
def __init__(self, target, *args, **kwargs):
self.target = target
self.args = args
@ -191,8 +196,7 @@ class CustomRequestResponse():
"""
:meta private:
"""
def __init__(self, json_text, status_code=200, reason=""):
def __init__(self, json_text, status_code = 200, reason = ""):
self.status_code = status_code
self.text = json_text
self.reason = reason
@ -205,7 +209,6 @@ def async_dec():
"""
:meta private:
"""
def decorator(fn):
def wrapper(*args, **kwargs):
return AsyncTask(fn, *args, **kwargs)
@ -215,6 +218,63 @@ def async_dec():
return decorator
def is_string(var) -> bool:
"""
Returns True if the given object is a string.
"""
return isinstance(var, str)
def is_dict(var) -> bool:
"""
Returns True if the given object is a dictionary.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a dictionary.
:rtype: :obj:`bool`
"""
return isinstance(var, dict)
def is_bytes(var) -> bool:
"""
Returns True if the given object is a bytes object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a bytes object.
:rtype: :obj:`bool`
"""
return isinstance(var, bytes)
def is_pil_image(var) -> bool:
"""
Returns True if the given object is a PIL.Image.Image object.
:param var: object to be checked
:type var: :obj:`object`
:return: True if the given object is a PIL.Image.Image object.
:rtype: :obj:`bool`
"""
return pil_imported and isinstance(var, Image.Image)
def pil_image_to_file(image, extension='JPEG', quality='web_low'):
if pil_imported:
photoBuffer = BytesIO()
image.convert('RGB').save(photoBuffer, extension, quality=quality)
photoBuffer.seek(0)
return photoBuffer
else:
raise RuntimeError('PIL module is not imported')
def is_command(text: str) -> bool:
r"""
Checks if `text` is a command. Telegram chat commands start with the '/' character.
@ -273,39 +333,6 @@ def extract_arguments(text: str) -> str or None:
result = regexp.match(text)
return result.group(2) if is_command(text) else None
def extract_entity(text: str, e: types.MessageEntity) -> str:
"""
Returns the content of the entity.
:param text: The text of the message the entity belongs to
:type text: :obj:`str`
:param e: The entity to extract
:type e: :obj:`MessageEntity`
:return: The content of the entity
:rtype: :obj:`str`
"""
offset = 0
start = 0
encoded_text = text.encode()
end = len(encoded_text)
i = 0
for byte in encoded_text:
if (byte & 0xc0) != 0x80:
if offset == e.offset:
start = i
elif offset - e.offset == e.length:
end = i
break
if byte >= 0xf0:
offset += 2
else:
offset += 1
i += 1
return encoded_text[start:end].decode()
def split_string(text: str, chars_per_string: int) -> List[str]:
"""
@ -324,7 +351,7 @@ def split_string(text: str, chars_per_string: int) -> List[str]:
return [text[i:i + chars_per_string] for i in range(0, len(text), chars_per_string)]
def smart_split(text: str, chars_per_string: int = MAX_MESSAGE_LENGTH) -> List[str]:
def smart_split(text: str, chars_per_string: int=MAX_MESSAGE_LENGTH) -> List[str]:
r"""
Splits one string into multiple strings, with a maximum amount of `chars_per_string` characters per string.
This is very useful for splitting one giant message into multiples.
@ -354,12 +381,9 @@ def smart_split(text: str, chars_per_string: int = MAX_MESSAGE_LENGTH) -> List[s
part = text[:chars_per_string]
if "\n" in part:
part = _text_before_last("\n")
elif ". " in part:
part = _text_before_last(". ")
elif " " in part:
part = _text_before_last(" ")
if "\n" in part: part = _text_before_last("\n")
elif ". " in part: part = _text_before_last(". ")
elif " " in part: part = _text_before_last(" ")
parts.append(part)
text = text[len(part):]
@ -373,14 +397,11 @@ def escape(text: str) -> str:
:return: the escaped text
"""
chars = {"&": "&amp;", "<": "&lt;", ">": "&gt;"}
if text is None:
return None
for old, new in chars.items():
text = text.replace(old, new)
for old, new in chars.items(): text = text.replace(old, new)
return text
def user_link(user: types.User, include_id: bool = False) -> str:
def user_link(user: types.User, include_id: bool=False) -> str:
"""
Returns an HTML user link. This is useful for reports.
Attention: Don't forget to set parse_mode to 'HTML'!
@ -407,10 +428,10 @@ def user_link(user: types.User, include_id: bool = False) -> str:
"""
name = escape(user.first_name)
return (f"<a href='tg://user?id={user.id}'>{name}</a>"
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
+ (f" (<pre>{user.id}</pre>)" if include_id else ""))
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int = 2) -> types.InlineKeyboardMarkup:
def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int=2) -> types.InlineKeyboardMarkup:
"""
Returns a reply markup from a dict in this format: {'text': kwargs}
This is useful to avoid always typing 'btn1 = InlineKeyboardButton(...)' 'btn2 = InlineKeyboardButton(...)'
@ -420,13 +441,11 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int = 2) -> types
.. code-block:: python3
:caption: Using quick_markup:
from telebot.util import quick_markup
markup = quick_markup({
quick_markup({
'Twitter': {'url': 'https://twitter.com'},
'Facebook': {'url': 'https://facebook.com'},
'Back': {'callback_data': 'whatever'}
}, row_width=2)
}, row_width=2):
# returns an InlineKeyboardMarkup with two buttons in a row, one leading to Twitter, the other to facebook
# and a back button below
@ -445,7 +464,7 @@ def quick_markup(values: Dict[str, Dict[str, Any]], row_width: int = 2) -> types
:param values: a dict containing all buttons to create in this format: {text: kwargs} {str:}
:type values: :obj:`dict`
:param row_width: number of :class:`telebot.types.InlineKeyboardButton` objects on each row
:param row_width: int row width
:type row_width: :obj:`int`
:return: InlineKeyboardMarkup
@ -527,7 +546,24 @@ def per_thread(key, construct_value, reset=False):
return getattr(thread_local, key)
def deprecated(warn: bool = True, alternative: Optional[Callable] = None, deprecation_text=None):
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
# https://stackoverflow.com/a/312464/9935473
for i in range(0, len(lst), n):
yield lst[i:i + n]
def generate_random_token() -> str:
"""
Generates a random token consisting of letters and digits, 16 characters long.
:return: a random token
:rtype: :obj:`str`
"""
return ''.join(random.sample(string.ascii_letters, 16))
def deprecated(warn: bool=True, alternative: Optional[Callable]=None, deprecation_text=None):
"""
Use this decorator to mark functions as deprecated.
When the function is used, an info (or warning if `warn` is True) is logged.
@ -545,7 +581,6 @@ def deprecated(warn: bool = True, alternative: Optional[Callable] = None, deprec
:return: The decorated function
"""
def decorator(function):
def wrapper(*args, **kwargs):
info = f"`{function.__name__}` is deprecated."
@ -558,9 +593,7 @@ def deprecated(warn: bool = True, alternative: Optional[Callable] = None, deprec
else:
logger.warning(info)
return function(*args, **kwargs)
return wrapper
return decorator
@ -590,7 +623,7 @@ def webhook_google_functions(bot, request):
return 'Bot ON'
def antiflood(function: Callable, *args, number_retries=5, **kwargs):
def antiflood(function: Callable, *args, **kwargs):
"""
Use this function inside loops in order to avoid getting TooManyRequests error.
Example:
@ -604,9 +637,6 @@ def antiflood(function: Callable, *args, number_retries=5, **kwargs):
:param function: The function to call
:type function: :obj:`Callable`
:param number_retries: Number of retries to send
:type function: :obj:int
:param args: The arguments to pass to the function
:type args: :obj:`tuple`
@ -617,19 +647,17 @@ def antiflood(function: Callable, *args, number_retries=5, **kwargs):
"""
from telebot.apihelper import ApiTelegramException
from time import sleep
for _ in range(number_retries - 1):
try:
return function(*args, **kwargs)
except ApiTelegramException as ex:
if ex.error_code == 429:
sleep(ex.result_json['parameters']['retry_after'])
else:
raise
else:
return function(*args, **kwargs)
msg = None
try:
msg = function(*args, **kwargs)
except ApiTelegramException as ex:
if ex.error_code == 429:
sleep(ex.result_json['parameters']['retry_after'])
msg = function(*args, **kwargs)
finally:
return msg
def parse_web_app_data(token: str, raw_init_data: str):
"""
Parses web app data.
@ -682,16 +710,4 @@ def validate_web_app_data(token: str, raw_init_data: str):
return hmac.new(secret_key.digest(), data_check_string.encode(), sha256).hexdigest() == init_data_hash
__all__ = (
"content_type_media", "content_type_service", "update_types",
"WorkerThread", "AsyncTask", "CustomRequestResponse",
"async_dec", "deprecated",
"is_bytes", "is_string", "is_dict", "is_pil_image",
"chunks", "generate_random_token", "pil_image_to_file",
"is_command", "extract_command", "extract_arguments",
"split_string", "smart_split", "escape", "user_link", "quick_markup",
"antiflood", "parse_web_app_data", "validate_web_app_data",
"or_set", "or_clear", "orify", "OrEvent", "per_thread",
"webhook_google_functions"
)

View File

@ -1,3 +1,3 @@
# Versions should comply with PEP440.
# This line is parsed in setup.py:
__version__ = '4.12.0'
__version__ = '4.6.1'

View File

@ -470,53 +470,6 @@ class TestTeleBot:
for i in range(0,200):
util.antiflood(tb.send_message, CHAT_ID, text)
assert i == 199
def test_extract_entity(self):
entities_map = {"https://core.telegram.org/api/entities": "https://core.telegram.org/api/entities",
"https://github.com/eternnoir/pyTelegramBotAPI": "https://github.com/eternnoir/pyTelegramBotAPI",
"*粗 bold text体*": "粗 bold text体",
"_斜体 italic text_": "斜体 italic text",
"[谷歌](http://www.google.com/)": "谷歌",
'`std::cout<<"test"<<std::endl;`': 'std::cout<<"test"<<std::endl;',
'''```rust
let number = loop {
println!("Pick a pattern from 0-2:");
stdin.read_line(&mut option).unwrap();
match option.lines().next().unwrap().parse::<usize>() {
Ok(number @ 0..=2) => break number,
_ => {
println!("invalid input!");
option = String::new();
continue;
}
};
};```''': '''let number = loop {
println!("Pick a pattern from 0-2:");
stdin.read_line(&mut option).unwrap();
match option.lines().next().unwrap().parse::<usize>() {
Ok(number @ 0..=2) => break number,
_ => {
println!("invalid input!");
option = String::new();
continue;
}
};
};''',
"@username": "@username",
"#hashtag索引标签": "#hashtag索引标签",
"do-not-reply@telegram.org": "do-not-reply@telegram.org",
"+12125550123": "+12125550123"}
entites = list(entities_map.keys())
contents = list(entities_map.values())
contents.sort()
text = '\n'.join(entites)
bot = telebot.TeleBot(TOKEN)
message = bot.send_message(CHAT_ID, text, parse_mode="Markdown")
extracted_contents = [util.extract_entity(
message.text, e) for e in message.entities]
extracted_contents.sort()
assert contents == extracted_contents
@staticmethod
def create_text_message(text):

View File

@ -67,9 +67,9 @@ def test_json_GroupChat():
def test_json_Document():
json_string = r'{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
json_string = r'{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AgADJQEAAqfhOEY","file_size":446}'
doc = types.Document.de_json(json_string)
assert doc.thumbnail is None
assert doc.thumb is None
assert doc.file_name == 'Text File'
@ -83,23 +83,23 @@ def test_json_Message_Audio():
def test_json_Message_Sticker():
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumbnail": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "thumb": {"file_id": "AAMCBAADHQJOFL7mAAJUMF8Dj62hpmDhpRAYvkc8CtIqipolAAJ8AAPA-8cF9yxjgjkLS97A0D4iXQARtQAHbQADHy4AAhoE", "file_unique_id": "AQADwNA-Il0AAx8uAAI", "file_size": 7776, "width": 60, "height": 60}, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumbnail.height == 60
assert msg.sticker.thumb.height == 60
assert msg.content_type == 'sticker'
def test_json_Message_Sticker_without_thumbnail():
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"type": "regular", "width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
def test_json_Message_Sticker_without_thumb():
json_string = r'{"message_id": 21552, "from": {"id": 590740002, "is_bot": false, "first_name": "⚜️ Ƥυrуα ⚜️", "username": "Purya", "language_code": "en"}, "chat": {"id": -1001309982000, "title": "123", "type": "supergroup"}, "date": 1594068909, "sticker": {"width": 368, "height": 368, "emoji": "🤖", "set_name": "ipuryapack", "is_animated": false, "is_video": true, "file_id": "CAACAgQAAx0CThS-5gACVDBfA4-toaZg4aUQGL5HWerSKoqaJQACArADwPvHBfcsY4I5C3feGgQ", "file_unique_id": "AgADfAADsPvHWQ", "file_size": 14602}}'
msg = types.Message.de_json(json_string)
assert msg.sticker.height == 368
assert msg.sticker.thumbnail is None
assert msg.sticker.thumb is None
assert msg.content_type == 'sticker'
def test_json_Message_Document():
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumbnail":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
json_string = r'{"message_id":97,"from":{"id":10734,"first_name":"Fd","last_name":"Wd","username":"dd","is_bot":true },"chat":{"id":10,"first_name":"Fd","type":"private","last_name":"Wd","username":"dd"},"date":1435478744,"document":{"file_name":"Text File","thumb":{},"file_id":"BQADBQADMwIAAsYifgZ_CEh0u682xwI","file_unique_id": "AQAD_QIfa3QAAyA4BgAB","file_size":446}}'
msg = types.Message.de_json(json_string)
assert msg.document.file_name == 'Text File'
assert msg.content_type == 'document'
@ -113,11 +113,11 @@ def test_json_Message_Photo():
def test_json_Message_Video():
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumbnail":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
json_string = r'{"message_id":101,"from":{"id":109734,"first_name":"dd","last_name":"dd","username":"dd","is_bot":true },"chat":{"id":109734,"first_name":"dd","type":"private","last_name":"dd","username":"dd"},"date":1435481960,"video":{"duration":3,"caption":"","width":360,"height":640,"thumb":{"file_id":"AAQFABPiYnBjkDwMAAIC","file_unique_id": "AQADTeisa3QAAz1nAAI","file_size":1597,"width":50,"height":90},"file_id":"BAADBQADNifgb_TOPEKErGoQI","file_unique_id": "AgADbgEAAn8VSFY","file_size":260699}}'
msg = types.Message.de_json(json_string)
assert msg.video
assert msg.video.duration == 3
assert msg.video.thumbnail.width == 50
assert msg.video.thumb.width == 50
assert msg.content_type == 'video'
@ -271,33 +271,5 @@ def test_sent_web_app_message():
assert sent_web_app_message.inline_message_id == '29430'
def test_message_entity():
# TODO: Add support for nesting entities
sample_string_1 = r'{"update_id":934522126,"message":{"message_id":1374510,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682177590,"text":"b b b","entities":[{"offset":0,"length":2,"type":"bold"},{"offset":0,"length":1,"type":"italic"},{"offset":2,"length":2,"type":"bold"},{"offset":2,"length":1,"type":"italic"},{"offset":4,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
update = types.Update.de_json(sample_string_1)
message: types.Message = update.message
assert message.html_text == "<i><b>b </b></i><i><b>b </b></i><i><b>b</b></i>"
sample_string_2 = r'{"update_id":934522166,"message":{"message_id":1374526,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179716,"text":"b b b","entities":[{"offset":0,"length":1,"type":"bold"},{"offset":2,"length":1,"type":"bold"},{"offset":4,"length":1,"type":"italic"}]}}'
message_2 = types.Update.de_json(sample_string_2).message
assert message_2.html_text == "<b>b</b> <b>b</b> <i>b</i>"
sample_string_3 = r'{"update_id":934522172,"message":{"message_id":1374530,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682179968,"text":"This is a bold text with a nested italic and bold text.","entities":[{"offset":10,"length":4,"type":"bold"},{"offset":27,"length":7,"type":"italic"},{"offset":34,"length":15,"type":"bold"},{"offset":34,"length":15,"type":"italic"}]}}'
message_3 = types.Update.de_json(sample_string_3).message
assert message_3.html_text == "This is a <b>bold</b> text with a <i>nested </i><i><b>italic and bold</b></i> text."
sample_string_4 = r'{"update_id":934522437,"message":{"message_id":1374619,"from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"chat":{"id":927266710,"first_name":">_run","username":"coder2020","type":"private"},"date":1682189507,"forward_from":{"id":927266710,"is_bot":false,"first_name":">_run","username":"coder2020","language_code":"en","is_premium":true},"forward_date":1682189124,"text":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa😋😋","entities":[{"offset":0,"length":76,"type":"bold"},{"offset":0,"length":76,"type":"italic"},{"offset":0,"length":76,"type":"underline"},{"offset":0,"length":76,"type":"strikethrough"},{"offset":76,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"},{"offset":78,"length":2,"type":"custom_emoji","custom_emoji_id":"5456188142006575553"}]}}'
message_4 = types.Update.de_json(sample_string_4).message
assert message_4.html_text == '<s><u><i><b>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</b></i></u></s><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji><tg-emoji emoji-id="5456188142006575553">😋</tg-emoji>'