mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-03-29 09:40:31 +01:00
Switch Code Formatting to Black (#2122)
* Swtich code formatting to Black * Update docs * Fix tests * TRy fixing pre-commit
This commit is contained in:
parent
8efb05290a
commit
264b2c9c72
237 changed files with 9442 additions and 5895 deletions
11
.github/CONTRIBUTING.rst
vendored
11
.github/CONTRIBUTING.rst
vendored
|
@ -91,12 +91,14 @@ Here's how to make a one-off code change.
|
||||||
|
|
||||||
Once the process terminates, you can view the built documentation by opening ``docs/build/html/index.html`` with a browser.
|
Once the process terminates, you can view the built documentation by opening ``docs/build/html/index.html`` with a browser.
|
||||||
|
|
||||||
- For consistency, please conform to `Google Python Style Guide`_ and `Google Python Style Docstrings`_. In addition, code should be formatted consistently with other code around it.
|
- For consistency, please conform to `Google Python Style Guide`_ and `Google Python Style Docstrings`_.
|
||||||
|
|
||||||
- The following exceptions to the above (Google's) style guides applies:
|
- The following exceptions to the above (Google's) style guides applies:
|
||||||
|
|
||||||
- Documenting types of global variables and complex types of class members can be done using the Sphinx docstring convention.
|
- Documenting types of global variables and complex types of class members can be done using the Sphinx docstring convention.
|
||||||
|
|
||||||
|
- In addition, PTB uses the `Black`_ coder formatting. Plugins for Black exist for some `popular editors`_. You can use those instead of manually formatting everything.
|
||||||
|
|
||||||
- Please ensure that the code you write is well-tested.
|
- Please ensure that the code you write is well-tested.
|
||||||
|
|
||||||
- Don’t break backward compatibility.
|
- Don’t break backward compatibility.
|
||||||
|
@ -189,11 +191,6 @@ Here's how to make a one-off code change.
|
||||||
Style commandments
|
Style commandments
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
Specific commandments
|
|
||||||
#####################
|
|
||||||
|
|
||||||
- Avoid using "double quotes" where you can reasonably use 'single quotes'.
|
|
||||||
|
|
||||||
Assert comparison order
|
Assert comparison order
|
||||||
#######################
|
#######################
|
||||||
|
|
||||||
|
@ -255,3 +252,5 @@ break the API classes. For example:
|
||||||
.. _AUTHORS.rst: ../AUTHORS.rst
|
.. _AUTHORS.rst: ../AUTHORS.rst
|
||||||
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.html
|
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.html
|
||||||
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
|
.. _`here`: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
|
||||||
|
.. _`Black`: https://black.readthedocs.io/en/stable/index.html
|
||||||
|
.. _`popular editors`: https://black.readthedocs.io/en/stable/editor_integration.html
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: git://github.com/python-telegram-bot/mirrors-yapf
|
- repo: https://github.com/psf/black
|
||||||
rev: 5769e088ef6e0a0d1eb63bd6d0c1fe9f3606d6c8
|
rev: 20.8b1
|
||||||
hooks:
|
hooks:
|
||||||
- id: yapf
|
- id: black
|
||||||
files: ^(telegram|tests)/.*\.py$
|
|
||||||
args:
|
args:
|
||||||
- --diff
|
- --diff
|
||||||
- repo: https://gitlab.com/pycqa/flake8
|
- repo: https://gitlab.com/pycqa/flake8
|
||||||
|
|
|
@ -45,6 +45,9 @@ We have a vibrant community of developers helping each other in our `Telegram gr
|
||||||
:target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&utm_medium=referral&utm_content=python-telegram-bot/python-telegram-bot&utm_campaign=Badge_Grade
|
:target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&utm_medium=referral&utm_content=python-telegram-bot/python-telegram-bot&utm_campaign=Badge_Grade
|
||||||
:alt: Code quality
|
:alt: Code quality
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||||
|
:target: https://github.com/psf/black
|
||||||
|
|
||||||
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg
|
.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg
|
||||||
:target: https://telegram.me/pythontelegrambotgroup
|
:target: https://telegram.me/pythontelegrambotgroup
|
||||||
:alt: Telegram Group
|
:alt: Telegram Group
|
||||||
|
|
|
@ -16,13 +16,13 @@ bot.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telegram import (ReplyKeyboardMarkup, ReplyKeyboardRemove)
|
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove
|
||||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler
|
||||||
ConversationHandler)
|
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -36,7 +36,8 @@ def start(update, context):
|
||||||
'Hi! My name is Professor Bot. I will hold a conversation with you. '
|
'Hi! My name is Professor Bot. I will hold a conversation with you. '
|
||||||
'Send /cancel to stop talking to me.\n\n'
|
'Send /cancel to stop talking to me.\n\n'
|
||||||
'Are you a boy or a girl?',
|
'Are you a boy or a girl?',
|
||||||
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
|
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True),
|
||||||
|
)
|
||||||
|
|
||||||
return GENDER
|
return GENDER
|
||||||
|
|
||||||
|
@ -44,9 +45,11 @@ def start(update, context):
|
||||||
def gender(update, context):
|
def gender(update, context):
|
||||||
user = update.message.from_user
|
user = update.message.from_user
|
||||||
logger.info("Gender of %s: %s", user.first_name, update.message.text)
|
logger.info("Gender of %s: %s", user.first_name, update.message.text)
|
||||||
update.message.reply_text('I see! Please send me a photo of yourself, '
|
update.message.reply_text(
|
||||||
'so I know what you look like, or send /skip if you don\'t want to.',
|
'I see! Please send me a photo of yourself, '
|
||||||
reply_markup=ReplyKeyboardRemove())
|
'so I know what you look like, or send /skip if you don\'t want to.',
|
||||||
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
|
)
|
||||||
|
|
||||||
return PHOTO
|
return PHOTO
|
||||||
|
|
||||||
|
@ -56,8 +59,9 @@ def photo(update, context):
|
||||||
photo_file = update.message.photo[-1].get_file()
|
photo_file = update.message.photo[-1].get_file()
|
||||||
photo_file.download('user_photo.jpg')
|
photo_file.download('user_photo.jpg')
|
||||||
logger.info("Photo of %s: %s", user.first_name, 'user_photo.jpg')
|
logger.info("Photo of %s: %s", user.first_name, 'user_photo.jpg')
|
||||||
update.message.reply_text('Gorgeous! Now, send me your location please, '
|
update.message.reply_text(
|
||||||
'or send /skip if you don\'t want to.')
|
'Gorgeous! Now, send me your location please, ' 'or send /skip if you don\'t want to.'
|
||||||
|
)
|
||||||
|
|
||||||
return LOCATION
|
return LOCATION
|
||||||
|
|
||||||
|
@ -65,8 +69,9 @@ def photo(update, context):
|
||||||
def skip_photo(update, context):
|
def skip_photo(update, context):
|
||||||
user = update.message.from_user
|
user = update.message.from_user
|
||||||
logger.info("User %s did not send a photo.", user.first_name)
|
logger.info("User %s did not send a photo.", user.first_name)
|
||||||
update.message.reply_text('I bet you look great! Now, send me your location please, '
|
update.message.reply_text(
|
||||||
'or send /skip.')
|
'I bet you look great! Now, send me your location please, ' 'or send /skip.'
|
||||||
|
)
|
||||||
|
|
||||||
return LOCATION
|
return LOCATION
|
||||||
|
|
||||||
|
@ -74,10 +79,12 @@ def skip_photo(update, context):
|
||||||
def location(update, context):
|
def location(update, context):
|
||||||
user = update.message.from_user
|
user = update.message.from_user
|
||||||
user_location = update.message.location
|
user_location = update.message.location
|
||||||
logger.info("Location of %s: %f / %f", user.first_name, user_location.latitude,
|
logger.info(
|
||||||
user_location.longitude)
|
"Location of %s: %f / %f", user.first_name, user_location.latitude, user_location.longitude
|
||||||
update.message.reply_text('Maybe I can visit you sometime! '
|
)
|
||||||
'At last, tell me something about yourself.')
|
update.message.reply_text(
|
||||||
|
'Maybe I can visit you sometime! ' 'At last, tell me something about yourself.'
|
||||||
|
)
|
||||||
|
|
||||||
return BIO
|
return BIO
|
||||||
|
|
||||||
|
@ -85,8 +92,9 @@ def location(update, context):
|
||||||
def skip_location(update, context):
|
def skip_location(update, context):
|
||||||
user = update.message.from_user
|
user = update.message.from_user
|
||||||
logger.info("User %s did not send a location.", user.first_name)
|
logger.info("User %s did not send a location.", user.first_name)
|
||||||
update.message.reply_text('You seem a bit paranoid! '
|
update.message.reply_text(
|
||||||
'At last, tell me something about yourself.')
|
'You seem a bit paranoid! ' 'At last, tell me something about yourself.'
|
||||||
|
)
|
||||||
|
|
||||||
return BIO
|
return BIO
|
||||||
|
|
||||||
|
@ -102,8 +110,9 @@ def bio(update, context):
|
||||||
def cancel(update, context):
|
def cancel(update, context):
|
||||||
user = update.message.from_user
|
user = update.message.from_user
|
||||||
logger.info("User %s canceled the conversation.", user.first_name)
|
logger.info("User %s canceled the conversation.", user.first_name)
|
||||||
update.message.reply_text('Bye! I hope we can talk again some day.',
|
update.message.reply_text(
|
||||||
reply_markup=ReplyKeyboardRemove())
|
'Bye! I hope we can talk again some day.', reply_markup=ReplyKeyboardRemove()
|
||||||
|
)
|
||||||
|
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
@ -120,20 +129,16 @@ def main():
|
||||||
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
|
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler('start', start)],
|
entry_points=[CommandHandler('start', start)],
|
||||||
|
|
||||||
states={
|
states={
|
||||||
GENDER: [MessageHandler(Filters.regex('^(Boy|Girl|Other)$'), gender)],
|
GENDER: [MessageHandler(Filters.regex('^(Boy|Girl|Other)$'), gender)],
|
||||||
|
PHOTO: [MessageHandler(Filters.photo, photo), CommandHandler('skip', skip_photo)],
|
||||||
PHOTO: [MessageHandler(Filters.photo, photo),
|
LOCATION: [
|
||||||
CommandHandler('skip', skip_photo)],
|
MessageHandler(Filters.location, location),
|
||||||
|
CommandHandler('skip', skip_location),
|
||||||
LOCATION: [MessageHandler(Filters.location, location),
|
],
|
||||||
CommandHandler('skip', skip_location)],
|
BIO: [MessageHandler(Filters.text & ~Filters.command, bio)],
|
||||||
|
|
||||||
BIO: [MessageHandler(Filters.text & ~Filters.command, bio)]
|
|
||||||
},
|
},
|
||||||
|
fallbacks=[CommandHandler('cancel', cancel)],
|
||||||
fallbacks=[CommandHandler('cancel', cancel)]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dp.add_handler(conv_handler)
|
dp.add_handler(conv_handler)
|
||||||
|
|
|
@ -17,20 +17,22 @@ bot.
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telegram import ReplyKeyboardMarkup
|
from telegram import ReplyKeyboardMarkup
|
||||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler
|
||||||
ConversationHandler)
|
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
||||||
|
|
||||||
reply_keyboard = [['Age', 'Favourite colour'],
|
reply_keyboard = [
|
||||||
['Number of siblings', 'Something else...'],
|
['Age', 'Favourite colour'],
|
||||||
['Done']]
|
['Number of siblings', 'Something else...'],
|
||||||
|
['Done'],
|
||||||
|
]
|
||||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,7 +49,8 @@ def start(update, context):
|
||||||
update.message.reply_text(
|
update.message.reply_text(
|
||||||
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
|
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
|
||||||
"Why don't you tell me something about yourself?",
|
"Why don't you tell me something about yourself?",
|
||||||
reply_markup=markup)
|
reply_markup=markup,
|
||||||
|
)
|
||||||
|
|
||||||
return CHOOSING
|
return CHOOSING
|
||||||
|
|
||||||
|
@ -56,14 +59,16 @@ def regular_choice(update, context):
|
||||||
text = update.message.text
|
text = update.message.text
|
||||||
context.user_data['choice'] = text
|
context.user_data['choice'] = text
|
||||||
update.message.reply_text(
|
update.message.reply_text(
|
||||||
'Your {}? Yes, I would love to hear about that!'.format(text.lower()))
|
'Your {}? Yes, I would love to hear about that!'.format(text.lower())
|
||||||
|
)
|
||||||
|
|
||||||
return TYPING_REPLY
|
return TYPING_REPLY
|
||||||
|
|
||||||
|
|
||||||
def custom_choice(update, context):
|
def custom_choice(update, context):
|
||||||
update.message.reply_text('Alright, please send me the category first, '
|
update.message.reply_text(
|
||||||
'for example "Most impressive skill"')
|
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||||
|
)
|
||||||
|
|
||||||
return TYPING_CHOICE
|
return TYPING_CHOICE
|
||||||
|
|
||||||
|
@ -75,10 +80,12 @@ def received_information(update, context):
|
||||||
user_data[category] = text
|
user_data[category] = text
|
||||||
del user_data['choice']
|
del user_data['choice']
|
||||||
|
|
||||||
update.message.reply_text("Neat! Just so you know, this is what you already told me:"
|
update.message.reply_text(
|
||||||
"{} You can tell me more, or change your opinion"
|
"Neat! Just so you know, this is what you already told me:"
|
||||||
" on something.".format(facts_to_str(user_data)),
|
"{} You can tell me more, or change your opinion"
|
||||||
reply_markup=markup)
|
" on something.".format(facts_to_str(user_data)),
|
||||||
|
reply_markup=markup,
|
||||||
|
)
|
||||||
|
|
||||||
return CHOOSING
|
return CHOOSING
|
||||||
|
|
||||||
|
@ -88,9 +95,9 @@ def done(update, context):
|
||||||
if 'choice' in user_data:
|
if 'choice' in user_data:
|
||||||
del user_data['choice']
|
del user_data['choice']
|
||||||
|
|
||||||
update.message.reply_text("I learned these facts about you:"
|
update.message.reply_text(
|
||||||
"{}"
|
"I learned these facts about you:" "{}" "Until next time!".format(facts_to_str(user_data))
|
||||||
"Until next time!".format(facts_to_str(user_data)))
|
)
|
||||||
|
|
||||||
user_data.clear()
|
user_data.clear()
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
@ -108,24 +115,26 @@ def main():
|
||||||
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler('start', start)],
|
entry_points=[CommandHandler('start', start)],
|
||||||
|
|
||||||
states={
|
states={
|
||||||
CHOOSING: [MessageHandler(Filters.regex('^(Age|Favourite colour|Number of siblings)$'),
|
CHOOSING: [
|
||||||
regular_choice),
|
MessageHandler(
|
||||||
MessageHandler(Filters.regex('^Something else...$'),
|
Filters.regex('^(Age|Favourite colour|Number of siblings)$'), regular_choice
|
||||||
custom_choice)
|
),
|
||||||
],
|
MessageHandler(Filters.regex('^Something else...$'), custom_choice),
|
||||||
|
],
|
||||||
TYPING_CHOICE: [
|
TYPING_CHOICE: [
|
||||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
MessageHandler(
|
||||||
regular_choice)],
|
Filters.text & ~(Filters.command | Filters.regex('^Done$')), regular_choice
|
||||||
|
)
|
||||||
|
],
|
||||||
TYPING_REPLY: [
|
TYPING_REPLY: [
|
||||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
MessageHandler(
|
||||||
received_information)],
|
Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||||
|
received_information,
|
||||||
|
)
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
fallbacks=[MessageHandler(Filters.regex('^Done$'), done)],
|
||||||
fallbacks=[MessageHandler(Filters.regex('^Done$'), done)]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dp.add_handler(conv_handler)
|
dp.add_handler(conv_handler)
|
||||||
|
|
|
@ -25,8 +25,9 @@ from telegram.ext import Updater, CommandHandler, Filters
|
||||||
# Enable logging
|
# Enable logging
|
||||||
from telegram.utils import helpers
|
from telegram.utils import helpers
|
||||||
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -48,8 +49,10 @@ def deep_linked_level_1(update, context):
|
||||||
"""Reached through the CHECK_THIS_OUT payload"""
|
"""Reached through the CHECK_THIS_OUT payload"""
|
||||||
bot = context.bot
|
bot = context.bot
|
||||||
url = helpers.create_deep_linked_url(bot.get_me().username, SO_COOL)
|
url = helpers.create_deep_linked_url(bot.get_me().username, SO_COOL)
|
||||||
text = "Awesome, you just accessed hidden functionality! " \
|
text = (
|
||||||
" Now let's get back to the private chat."
|
"Awesome, you just accessed hidden functionality! "
|
||||||
|
" Now let's get back to the private chat."
|
||||||
|
)
|
||||||
keyboard = InlineKeyboardMarkup.from_button(
|
keyboard = InlineKeyboardMarkup.from_button(
|
||||||
InlineKeyboardButton(text='Continue here!', url=url)
|
InlineKeyboardButton(text='Continue here!', url=url)
|
||||||
)
|
)
|
||||||
|
@ -60,16 +63,16 @@ def deep_linked_level_2(update, context):
|
||||||
"""Reached through the SO_COOL payload"""
|
"""Reached through the SO_COOL payload"""
|
||||||
bot = context.bot
|
bot = context.bot
|
||||||
url = helpers.create_deep_linked_url(bot.get_me().username, USING_ENTITIES)
|
url = helpers.create_deep_linked_url(bot.get_me().username, USING_ENTITIES)
|
||||||
text = "You can also mask the deep-linked URLs as links: " \
|
text = "You can also mask the deep-linked URLs as links: " "[▶️ CLICK HERE]({}).".format(url)
|
||||||
"[▶️ CLICK HERE]({}).".format(url)
|
|
||||||
update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
|
update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
|
||||||
|
|
||||||
|
|
||||||
def deep_linked_level_3(update, context):
|
def deep_linked_level_3(update, context):
|
||||||
"""Reached through the USING_ENTITIES payload"""
|
"""Reached through the USING_ENTITIES payload"""
|
||||||
payload = context.args
|
payload = context.args
|
||||||
update.message.reply_text("Congratulations! This is as deep as it gets 👏🏻\n\n"
|
update.message.reply_text(
|
||||||
"The payload was: {}".format(payload))
|
"Congratulations! This is as deep as it gets 👏🏻\n\n" "The payload was: {}".format(payload)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -90,10 +93,9 @@ def main():
|
||||||
dp.add_handler(CommandHandler("start", deep_linked_level_2, Filters.regex(SO_COOL)))
|
dp.add_handler(CommandHandler("start", deep_linked_level_2, Filters.regex(SO_COOL)))
|
||||||
|
|
||||||
# We can also pass on the deep-linking payload
|
# We can also pass on the deep-linking payload
|
||||||
dp.add_handler(CommandHandler("start",
|
dp.add_handler(
|
||||||
deep_linked_level_3,
|
CommandHandler("start", deep_linked_level_3, Filters.regex(USING_ENTITIES), pass_args=True)
|
||||||
Filters.regex(USING_ENTITIES),
|
)
|
||||||
pass_args=True))
|
|
||||||
|
|
||||||
# Make sure the deep-linking handlers occur *before* the normal /start handler.
|
# Make sure the deep-linking handlers occur *before* the normal /start handler.
|
||||||
dp.add_handler(CommandHandler("start", start))
|
dp.add_handler(CommandHandler("start", start))
|
||||||
|
|
|
@ -20,8 +20,9 @@ import logging
|
||||||
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
|
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,9 @@ import traceback
|
||||||
from telegram import Update, ParseMode
|
from telegram import Update, ParseMode
|
||||||
from telegram.ext import Updater, CallbackContext, CommandHandler
|
from telegram.ext import Updater, CallbackContext, CommandHandler
|
||||||
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ def error_handler(update: Update, context: CallbackContext):
|
||||||
html.escape(json.dumps(update.to_dict(), indent=2, ensure_ascii=False)),
|
html.escape(json.dumps(update.to_dict(), indent=2, ensure_ascii=False)),
|
||||||
html.escape(str(context.chat_data)),
|
html.escape(str(context.chat_data)),
|
||||||
html.escape(str(context.user_data)),
|
html.escape(str(context.user_data)),
|
||||||
html.escape(tb)
|
html.escape(tb),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Finally, send the message
|
# Finally, send the message
|
||||||
|
@ -61,9 +62,10 @@ def bad_command(update: Update, context: CallbackContext):
|
||||||
|
|
||||||
|
|
||||||
def start(update: Update, context: CallbackContext):
|
def start(update: Update, context: CallbackContext):
|
||||||
update.effective_message.reply_html('Use /bad_command to cause an error.\n'
|
update.effective_message.reply_html(
|
||||||
'Your chat id is <code>{}</code>.'
|
'Use /bad_command to cause an error.\n'
|
||||||
.format(update.effective_chat.id))
|
'Your chat id is <code>{}</code>.'.format(update.effective_chat.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -15,14 +15,14 @@ bot.
|
||||||
import logging
|
import logging
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from telegram import InlineQueryResultArticle, ParseMode, \
|
from telegram import InlineQueryResultArticle, ParseMode, InputTextMessageContent
|
||||||
InputTextMessageContent
|
|
||||||
from telegram.ext import Updater, InlineQueryHandler, CommandHandler
|
from telegram.ext import Updater, InlineQueryHandler, CommandHandler
|
||||||
from telegram.utils.helpers import escape_markdown
|
from telegram.utils.helpers import escape_markdown
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -44,22 +44,23 @@ def inlinequery(update, context):
|
||||||
query = update.inline_query.query
|
query = update.inline_query.query
|
||||||
results = [
|
results = [
|
||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
id=uuid4(),
|
id=uuid4(), title="Caps", input_message_content=InputTextMessageContent(query.upper())
|
||||||
title="Caps",
|
),
|
||||||
input_message_content=InputTextMessageContent(
|
|
||||||
query.upper())),
|
|
||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
id=uuid4(),
|
id=uuid4(),
|
||||||
title="Bold",
|
title="Bold",
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"*{}*".format(escape_markdown(query)),
|
"*{}*".format(escape_markdown(query)), parse_mode=ParseMode.MARKDOWN
|
||||||
parse_mode=ParseMode.MARKDOWN)),
|
),
|
||||||
|
),
|
||||||
InlineQueryResultArticle(
|
InlineQueryResultArticle(
|
||||||
id=uuid4(),
|
id=uuid4(),
|
||||||
title="Italic",
|
title="Italic",
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"_{}_".format(escape_markdown(query)),
|
"_{}_".format(escape_markdown(query)), parse_mode=ParseMode.MARKDOWN
|
||||||
parse_mode=ParseMode.MARKDOWN))]
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
update.inline_query.answer(results)
|
update.inline_query.answer(results)
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,20 @@ import logging
|
||||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
|
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
|
||||||
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def start(update, context):
|
def start(update, context):
|
||||||
keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'),
|
keyboard = [
|
||||||
InlineKeyboardButton("Option 2", callback_data='2')],
|
[
|
||||||
|
InlineKeyboardButton("Option 1", callback_data='1'),
|
||||||
[InlineKeyboardButton("Option 3", callback_data='3')]]
|
InlineKeyboardButton("Option 2", callback_data='2'),
|
||||||
|
],
|
||||||
|
[InlineKeyboardButton("Option 3", callback_data='3')],
|
||||||
|
]
|
||||||
|
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,9 @@ from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, Conversa
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -38,15 +39,14 @@ def start(update, context):
|
||||||
# The keyboard is a list of button rows, where each row is in turn
|
# The keyboard is a list of button rows, where each row is in turn
|
||||||
# a list (hence `[[...]]`).
|
# a list (hence `[[...]]`).
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("1", callback_data=str(ONE)),
|
[
|
||||||
InlineKeyboardButton("2", callback_data=str(TWO))]
|
InlineKeyboardButton("1", callback_data=str(ONE)),
|
||||||
|
InlineKeyboardButton("2", callback_data=str(TWO)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
# Send message with text and appended InlineKeyboard
|
# Send message with text and appended InlineKeyboard
|
||||||
update.message.reply_text(
|
update.message.reply_text("Start handler, Choose a route", reply_markup=reply_markup)
|
||||||
"Start handler, Choose a route",
|
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
|
||||||
# Tell ConversationHandler that we're in state `FIRST` now
|
# Tell ConversationHandler that we're in state `FIRST` now
|
||||||
return FIRST
|
return FIRST
|
||||||
|
|
||||||
|
@ -59,17 +59,16 @@ def start_over(update, context):
|
||||||
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
|
# Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
|
||||||
query.answer()
|
query.answer()
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("1", callback_data=str(ONE)),
|
[
|
||||||
InlineKeyboardButton("2", callback_data=str(TWO))]
|
InlineKeyboardButton("1", callback_data=str(ONE)),
|
||||||
|
InlineKeyboardButton("2", callback_data=str(TWO)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
# Instead of sending a new message, edit the message that
|
# Instead of sending a new message, edit the message that
|
||||||
# originated the CallbackQuery. This gives the feeling of an
|
# originated the CallbackQuery. This gives the feeling of an
|
||||||
# interactive menu.
|
# interactive menu.
|
||||||
query.edit_message_text(
|
query.edit_message_text(text="Start handler, Choose a route", reply_markup=reply_markup)
|
||||||
text="Start handler, Choose a route",
|
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
|
||||||
return FIRST
|
return FIRST
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,13 +77,14 @@ def one(update, context):
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
query.answer()
|
query.answer()
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("3", callback_data=str(THREE)),
|
[
|
||||||
InlineKeyboardButton("4", callback_data=str(FOUR))]
|
InlineKeyboardButton("3", callback_data=str(THREE)),
|
||||||
|
InlineKeyboardButton("4", callback_data=str(FOUR)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
query.edit_message_text(
|
query.edit_message_text(
|
||||||
text="First CallbackQueryHandler, Choose a route",
|
text="First CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
)
|
||||||
return FIRST
|
return FIRST
|
||||||
|
|
||||||
|
@ -94,13 +94,14 @@ def two(update, context):
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
query.answer()
|
query.answer()
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("1", callback_data=str(ONE)),
|
[
|
||||||
InlineKeyboardButton("3", callback_data=str(THREE))]
|
InlineKeyboardButton("1", callback_data=str(ONE)),
|
||||||
|
InlineKeyboardButton("3", callback_data=str(THREE)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
query.edit_message_text(
|
query.edit_message_text(
|
||||||
text="Second CallbackQueryHandler, Choose a route",
|
text="Second CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
)
|
||||||
return FIRST
|
return FIRST
|
||||||
|
|
||||||
|
@ -110,13 +111,14 @@ def three(update, context):
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
query.answer()
|
query.answer()
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("Yes, let's do it again!", callback_data=str(ONE)),
|
[
|
||||||
InlineKeyboardButton("Nah, I've had enough ...", callback_data=str(TWO))]
|
InlineKeyboardButton("Yes, let's do it again!", callback_data=str(ONE)),
|
||||||
|
InlineKeyboardButton("Nah, I've had enough ...", callback_data=str(TWO)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
query.edit_message_text(
|
query.edit_message_text(
|
||||||
text="Third CallbackQueryHandler. Do want to start over?",
|
text="Third CallbackQueryHandler. Do want to start over?", reply_markup=reply_markup
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
)
|
||||||
# Transfer to conversation state `SECOND`
|
# Transfer to conversation state `SECOND`
|
||||||
return SECOND
|
return SECOND
|
||||||
|
@ -127,13 +129,14 @@ def four(update, context):
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
query.answer()
|
query.answer()
|
||||||
keyboard = [
|
keyboard = [
|
||||||
[InlineKeyboardButton("2", callback_data=str(TWO)),
|
[
|
||||||
InlineKeyboardButton("4", callback_data=str(FOUR))]
|
InlineKeyboardButton("2", callback_data=str(TWO)),
|
||||||
|
InlineKeyboardButton("4", callback_data=str(FOUR)),
|
||||||
|
]
|
||||||
]
|
]
|
||||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
query.edit_message_text(
|
query.edit_message_text(
|
||||||
text="Fourth CallbackQueryHandler, Choose a route",
|
text="Fourth CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
)
|
||||||
return FIRST
|
return FIRST
|
||||||
|
|
||||||
|
@ -143,9 +146,7 @@ def end(update, context):
|
||||||
ConversationHandler that the conversation is over"""
|
ConversationHandler that the conversation is over"""
|
||||||
query = update.callback_query
|
query = update.callback_query
|
||||||
query.answer()
|
query.answer()
|
||||||
query.edit_message_text(
|
query.edit_message_text(text="See you next time!")
|
||||||
text="See you next time!"
|
|
||||||
)
|
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,14 +166,18 @@ def main():
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler('start', start)],
|
entry_points=[CommandHandler('start', start)],
|
||||||
states={
|
states={
|
||||||
FIRST: [CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'),
|
FIRST: [
|
||||||
CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'),
|
CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'),
|
||||||
CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'),
|
CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'),
|
||||||
CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$')],
|
CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'),
|
||||||
SECOND: [CallbackQueryHandler(start_over, pattern='^' + str(ONE) + '$'),
|
CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$'),
|
||||||
CallbackQueryHandler(end, pattern='^' + str(TWO) + '$')]
|
],
|
||||||
|
SECOND: [
|
||||||
|
CallbackQueryHandler(start_over, pattern='^' + str(ONE) + '$'),
|
||||||
|
CallbackQueryHandler(end, pattern='^' + str(TWO) + '$'),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
fallbacks=[CommandHandler('start', start)]
|
fallbacks=[CommandHandler('start', start)],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add ConversationHandler to dispatcher that will be used for handling
|
# Add ConversationHandler to dispatcher that will be used for handling
|
||||||
|
|
|
@ -16,13 +16,20 @@ bot.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telegram import (InlineKeyboardMarkup, InlineKeyboardButton)
|
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
from telegram.ext import (
|
||||||
ConversationHandler, CallbackQueryHandler)
|
Updater,
|
||||||
|
CommandHandler,
|
||||||
|
MessageHandler,
|
||||||
|
Filters,
|
||||||
|
ConversationHandler,
|
||||||
|
CallbackQueryHandler,
|
||||||
|
)
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -38,8 +45,20 @@ STOPPING, SHOWING = map(chr, range(8, 10))
|
||||||
END = ConversationHandler.END
|
END = ConversationHandler.END
|
||||||
|
|
||||||
# Different constants for this example
|
# Different constants for this example
|
||||||
(PARENTS, CHILDREN, SELF, GENDER, MALE, FEMALE, AGE, NAME, START_OVER, FEATURES,
|
(
|
||||||
CURRENT_FEATURE, CURRENT_LEVEL) = map(chr, range(10, 22))
|
PARENTS,
|
||||||
|
CHILDREN,
|
||||||
|
SELF,
|
||||||
|
GENDER,
|
||||||
|
MALE,
|
||||||
|
FEMALE,
|
||||||
|
AGE,
|
||||||
|
NAME,
|
||||||
|
START_OVER,
|
||||||
|
FEATURES,
|
||||||
|
CURRENT_FEATURE,
|
||||||
|
CURRENT_LEVEL,
|
||||||
|
) = map(chr, range(10, 22))
|
||||||
|
|
||||||
|
|
||||||
# Helper
|
# Helper
|
||||||
|
@ -53,15 +72,20 @@ def _name_switcher(level):
|
||||||
# Top level conversation callbacks
|
# Top level conversation callbacks
|
||||||
def start(update, context):
|
def start(update, context):
|
||||||
"""Select an action: Adding parent/child or show data."""
|
"""Select an action: Adding parent/child or show data."""
|
||||||
text = 'You may add a familiy member, yourself show the gathered data or end the ' \
|
text = (
|
||||||
'conversation. To abort, simply type /stop.'
|
'You may add a familiy member, yourself show the gathered data or end the '
|
||||||
buttons = [[
|
'conversation. To abort, simply type /stop.'
|
||||||
InlineKeyboardButton(text='Add family member', callback_data=str(ADDING_MEMBER)),
|
)
|
||||||
InlineKeyboardButton(text='Add yourself', callback_data=str(ADDING_SELF))
|
buttons = [
|
||||||
], [
|
[
|
||||||
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
InlineKeyboardButton(text='Add family member', callback_data=str(ADDING_MEMBER)),
|
||||||
InlineKeyboardButton(text='Done', callback_data=str(END))
|
InlineKeyboardButton(text='Add yourself', callback_data=str(ADDING_SELF)),
|
||||||
]]
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
||||||
|
InlineKeyboardButton(text='Done', callback_data=str(END)),
|
||||||
|
],
|
||||||
|
]
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
|
|
||||||
# If we're starting over we don't need do send a new message
|
# If we're starting over we don't need do send a new message
|
||||||
|
@ -69,8 +93,9 @@ def start(update, context):
|
||||||
update.callback_query.answer()
|
update.callback_query.answer()
|
||||||
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
update.callback_query.edit_message_text(text=text, reply_markup=keyboard)
|
||||||
else:
|
else:
|
||||||
update.message.reply_text('Hi, I\'m FamiliyBot and here to help you gather information'
|
update.message.reply_text(
|
||||||
'about your family.')
|
'Hi, I\'m FamiliyBot and here to help you gather information' 'about your family.'
|
||||||
|
)
|
||||||
update.message.reply_text(text=text, reply_markup=keyboard)
|
update.message.reply_text(text=text, reply_markup=keyboard)
|
||||||
|
|
||||||
context.user_data[START_OVER] = False
|
context.user_data[START_OVER] = False
|
||||||
|
@ -92,6 +117,7 @@ def adding_self(update, context):
|
||||||
|
|
||||||
def show_data(update, context):
|
def show_data(update, context):
|
||||||
"""Pretty print gathered data."""
|
"""Pretty print gathered data."""
|
||||||
|
|
||||||
def prettyprint(user_data, level):
|
def prettyprint(user_data, level):
|
||||||
people = user_data.get(level)
|
people = user_data.get(level)
|
||||||
if not people:
|
if not people:
|
||||||
|
@ -106,8 +132,9 @@ def show_data(update, context):
|
||||||
|
|
||||||
for person in user_data[level]:
|
for person in user_data[level]:
|
||||||
gender = female if person[GENDER] == FEMALE else male
|
gender = female if person[GENDER] == FEMALE else male
|
||||||
text += '\n{}: Name: {}, Age: {}'.format(gender, person.get(NAME, '-'),
|
text += '\n{}: Name: {}, Age: {}'.format(
|
||||||
person.get(AGE, '-'))
|
gender, person.get(NAME, '-'), person.get(AGE, '-')
|
||||||
|
)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
ud = context.user_data
|
ud = context.user_data
|
||||||
|
@ -115,9 +142,7 @@ def show_data(update, context):
|
||||||
text += '\n\nParents:' + prettyprint(ud, PARENTS)
|
text += '\n\nParents:' + prettyprint(ud, PARENTS)
|
||||||
text += '\n\nChildren:' + prettyprint(ud, CHILDREN)
|
text += '\n\nChildren:' + prettyprint(ud, CHILDREN)
|
||||||
|
|
||||||
buttons = [[
|
buttons = [[InlineKeyboardButton(text='Back', callback_data=str(END))]]
|
||||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
|
||||||
]]
|
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
|
|
||||||
update.callback_query.answer()
|
update.callback_query.answer()
|
||||||
|
@ -148,13 +173,16 @@ def end(update, context):
|
||||||
def select_level(update, context):
|
def select_level(update, context):
|
||||||
"""Choose to add a parent or a child."""
|
"""Choose to add a parent or a child."""
|
||||||
text = 'You may add a parent or a child. Also you can show the gathered data or go back.'
|
text = 'You may add a parent or a child. Also you can show the gathered data or go back.'
|
||||||
buttons = [[
|
buttons = [
|
||||||
InlineKeyboardButton(text='Add parent', callback_data=str(PARENTS)),
|
[
|
||||||
InlineKeyboardButton(text='Add child', callback_data=str(CHILDREN))
|
InlineKeyboardButton(text='Add parent', callback_data=str(PARENTS)),
|
||||||
], [
|
InlineKeyboardButton(text='Add child', callback_data=str(CHILDREN)),
|
||||||
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
],
|
||||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
[
|
||||||
]]
|
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
||||||
|
InlineKeyboardButton(text='Back', callback_data=str(END)),
|
||||||
|
],
|
||||||
|
]
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
|
|
||||||
update.callback_query.answer()
|
update.callback_query.answer()
|
||||||
|
@ -172,13 +200,16 @@ def select_gender(update, context):
|
||||||
|
|
||||||
male, female = _name_switcher(level)
|
male, female = _name_switcher(level)
|
||||||
|
|
||||||
buttons = [[
|
buttons = [
|
||||||
InlineKeyboardButton(text='Add ' + male, callback_data=str(MALE)),
|
[
|
||||||
InlineKeyboardButton(text='Add ' + female, callback_data=str(FEMALE))
|
InlineKeyboardButton(text='Add ' + male, callback_data=str(MALE)),
|
||||||
], [
|
InlineKeyboardButton(text='Add ' + female, callback_data=str(FEMALE)),
|
||||||
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
],
|
||||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
[
|
||||||
]]
|
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
||||||
|
InlineKeyboardButton(text='Back', callback_data=str(END)),
|
||||||
|
],
|
||||||
|
]
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
|
|
||||||
update.callback_query.answer()
|
update.callback_query.answer()
|
||||||
|
@ -198,11 +229,13 @@ def end_second_level(update, context):
|
||||||
# Third level callbacks
|
# Third level callbacks
|
||||||
def select_feature(update, context):
|
def select_feature(update, context):
|
||||||
"""Select a feature to update for the person."""
|
"""Select a feature to update for the person."""
|
||||||
buttons = [[
|
buttons = [
|
||||||
InlineKeyboardButton(text='Name', callback_data=str(NAME)),
|
[
|
||||||
InlineKeyboardButton(text='Age', callback_data=str(AGE)),
|
InlineKeyboardButton(text='Name', callback_data=str(NAME)),
|
||||||
InlineKeyboardButton(text='Done', callback_data=str(END)),
|
InlineKeyboardButton(text='Age', callback_data=str(AGE)),
|
||||||
]]
|
InlineKeyboardButton(text='Done', callback_data=str(END)),
|
||||||
|
]
|
||||||
|
]
|
||||||
keyboard = InlineKeyboardMarkup(buttons)
|
keyboard = InlineKeyboardMarkup(buttons)
|
||||||
|
|
||||||
# If we collect features for a new person, clear the cache and save the gender
|
# If we collect features for a new person, clear the cache and save the gender
|
||||||
|
@ -278,46 +311,45 @@ def main():
|
||||||
|
|
||||||
# Set up third level ConversationHandler (collecting features)
|
# Set up third level ConversationHandler (collecting features)
|
||||||
description_conv = ConversationHandler(
|
description_conv = ConversationHandler(
|
||||||
entry_points=[CallbackQueryHandler(select_feature,
|
entry_points=[
|
||||||
pattern='^' + str(MALE) + '$|^' + str(FEMALE) + '$')],
|
CallbackQueryHandler(
|
||||||
|
select_feature, pattern='^' + str(MALE) + '$|^' + str(FEMALE) + '$'
|
||||||
|
)
|
||||||
|
],
|
||||||
states={
|
states={
|
||||||
SELECTING_FEATURE: [CallbackQueryHandler(ask_for_input,
|
SELECTING_FEATURE: [
|
||||||
pattern='^(?!' + str(END) + ').*$')],
|
CallbackQueryHandler(ask_for_input, pattern='^(?!' + str(END) + ').*$')
|
||||||
|
],
|
||||||
TYPING: [MessageHandler(Filters.text & ~Filters.command, save_input)],
|
TYPING: [MessageHandler(Filters.text & ~Filters.command, save_input)],
|
||||||
},
|
},
|
||||||
|
|
||||||
fallbacks=[
|
fallbacks=[
|
||||||
CallbackQueryHandler(end_describing, pattern='^' + str(END) + '$'),
|
CallbackQueryHandler(end_describing, pattern='^' + str(END) + '$'),
|
||||||
CommandHandler('stop', stop_nested)
|
CommandHandler('stop', stop_nested),
|
||||||
],
|
],
|
||||||
|
|
||||||
map_to_parent={
|
map_to_parent={
|
||||||
# Return to second level menu
|
# Return to second level menu
|
||||||
END: SELECTING_LEVEL,
|
END: SELECTING_LEVEL,
|
||||||
# End conversation alltogether
|
# End conversation alltogether
|
||||||
STOPPING: STOPPING,
|
STOPPING: STOPPING,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set up second level ConversationHandler (adding a person)
|
# Set up second level ConversationHandler (adding a person)
|
||||||
add_member_conv = ConversationHandler(
|
add_member_conv = ConversationHandler(
|
||||||
entry_points=[CallbackQueryHandler(select_level,
|
entry_points=[CallbackQueryHandler(select_level, pattern='^' + str(ADDING_MEMBER) + '$')],
|
||||||
pattern='^' + str(ADDING_MEMBER) + '$')],
|
|
||||||
|
|
||||||
states={
|
states={
|
||||||
SELECTING_LEVEL: [CallbackQueryHandler(select_gender,
|
SELECTING_LEVEL: [
|
||||||
pattern='^{}$|^{}$'.format(str(PARENTS),
|
CallbackQueryHandler(
|
||||||
str(CHILDREN)))],
|
select_gender, pattern='^{}$|^{}$'.format(str(PARENTS), str(CHILDREN))
|
||||||
SELECTING_GENDER: [description_conv]
|
)
|
||||||
|
],
|
||||||
|
SELECTING_GENDER: [description_conv],
|
||||||
},
|
},
|
||||||
|
|
||||||
fallbacks=[
|
fallbacks=[
|
||||||
CallbackQueryHandler(show_data, pattern='^' + str(SHOWING) + '$'),
|
CallbackQueryHandler(show_data, pattern='^' + str(SHOWING) + '$'),
|
||||||
CallbackQueryHandler(end_second_level, pattern='^' + str(END) + '$'),
|
CallbackQueryHandler(end_second_level, pattern='^' + str(END) + '$'),
|
||||||
CommandHandler('stop', stop_nested)
|
CommandHandler('stop', stop_nested),
|
||||||
],
|
],
|
||||||
|
|
||||||
map_to_parent={
|
map_to_parent={
|
||||||
# After showing data return to top level menu
|
# After showing data return to top level menu
|
||||||
SHOWING: SHOWING,
|
SHOWING: SHOWING,
|
||||||
|
@ -325,7 +357,7 @@ def main():
|
||||||
END: SELECTING_ACTION,
|
END: SELECTING_ACTION,
|
||||||
# End conversation alltogether
|
# End conversation alltogether
|
||||||
STOPPING: END,
|
STOPPING: END,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set up top level ConversationHandler (selecting action)
|
# Set up top level ConversationHandler (selecting action)
|
||||||
|
@ -339,7 +371,6 @@ def main():
|
||||||
]
|
]
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler('start', start)],
|
entry_points=[CommandHandler('start', start)],
|
||||||
|
|
||||||
states={
|
states={
|
||||||
SHOWING: [CallbackQueryHandler(start, pattern='^' + str(END) + '$')],
|
SHOWING: [CallbackQueryHandler(start, pattern='^' + str(END) + '$')],
|
||||||
SELECTING_ACTION: selection_handlers,
|
SELECTING_ACTION: selection_handlers,
|
||||||
|
@ -347,7 +378,6 @@ def main():
|
||||||
DESCRIBING_SELF: [description_conv],
|
DESCRIBING_SELF: [description_conv],
|
||||||
STOPPING: [CommandHandler('start', start)],
|
STOPPING: [CommandHandler('start', start)],
|
||||||
},
|
},
|
||||||
|
|
||||||
fallbacks=[CommandHandler('stop', stop)],
|
fallbacks=[CommandHandler('stop', stop)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,9 @@ import logging
|
||||||
from telegram.ext import Updater, MessageHandler, Filters
|
from telegram.ext import Updater, MessageHandler, Filters
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.DEBUG)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -39,18 +40,28 @@ def msg(update, context):
|
||||||
print('Phone: ', data.phone_number)
|
print('Phone: ', data.phone_number)
|
||||||
elif data.type == 'email':
|
elif data.type == 'email':
|
||||||
print('Email: ', data.email)
|
print('Email: ', data.email)
|
||||||
if data.type in ('personal_details', 'passport', 'driver_license', 'identity_card',
|
if data.type in (
|
||||||
'internal_passport', 'address'):
|
'personal_details',
|
||||||
|
'passport',
|
||||||
|
'driver_license',
|
||||||
|
'identity_card',
|
||||||
|
'internal_passport',
|
||||||
|
'address',
|
||||||
|
):
|
||||||
print(data.type, data.data)
|
print(data.type, data.data)
|
||||||
if data.type in ('utility_bill', 'bank_statement', 'rental_agreement',
|
if data.type in (
|
||||||
'passport_registration', 'temporary_registration'):
|
'utility_bill',
|
||||||
|
'bank_statement',
|
||||||
|
'rental_agreement',
|
||||||
|
'passport_registration',
|
||||||
|
'temporary_registration',
|
||||||
|
):
|
||||||
print(data.type, len(data.files), 'files')
|
print(data.type, len(data.files), 'files')
|
||||||
for file in data.files:
|
for file in data.files:
|
||||||
actual_file = file.get_file()
|
actual_file = file.get_file()
|
||||||
print(actual_file)
|
print(actual_file)
|
||||||
actual_file.download()
|
actual_file.download()
|
||||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||||
'internal_passport'):
|
|
||||||
if data.front_side:
|
if data.front_side:
|
||||||
file = data.front_side.get_file()
|
file = data.front_side.get_file()
|
||||||
print(data.type, file)
|
print(data.type, file)
|
||||||
|
@ -60,16 +71,22 @@ def msg(update, context):
|
||||||
file = data.reverse_side.get_file()
|
file = data.reverse_side.get_file()
|
||||||
print(data.type, file)
|
print(data.type, file)
|
||||||
file.download()
|
file.download()
|
||||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||||
'internal_passport'):
|
|
||||||
if data.selfie:
|
if data.selfie:
|
||||||
file = data.selfie.get_file()
|
file = data.selfie.get_file()
|
||||||
print(data.type, file)
|
print(data.type, file)
|
||||||
file.download()
|
file.download()
|
||||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
if data.type in (
|
||||||
'internal_passport', 'utility_bill', 'bank_statement',
|
'passport',
|
||||||
'rental_agreement', 'passport_registration',
|
'driver_license',
|
||||||
'temporary_registration'):
|
'identity_card',
|
||||||
|
'internal_passport',
|
||||||
|
'utility_bill',
|
||||||
|
'bank_statement',
|
||||||
|
'rental_agreement',
|
||||||
|
'passport_registration',
|
||||||
|
'temporary_registration',
|
||||||
|
):
|
||||||
print(data.type, len(data.translation), 'translation')
|
print(data.type, len(data.translation), 'translation')
|
||||||
for file in data.translation:
|
for file in data.translation:
|
||||||
actual_file = file.get_file()
|
actual_file = file.get_file()
|
||||||
|
|
|
@ -8,13 +8,20 @@ Basic example for a bot that can receive payment from user.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telegram import (LabeledPrice, ShippingOption)
|
from telegram import LabeledPrice, ShippingOption
|
||||||
from telegram.ext import (Updater, CommandHandler, MessageHandler,
|
from telegram.ext import (
|
||||||
Filters, PreCheckoutQueryHandler, ShippingQueryHandler)
|
Updater,
|
||||||
|
CommandHandler,
|
||||||
|
MessageHandler,
|
||||||
|
Filters,
|
||||||
|
PreCheckoutQueryHandler,
|
||||||
|
ShippingQueryHandler,
|
||||||
|
)
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -43,10 +50,21 @@ def start_with_shipping_callback(update, context):
|
||||||
|
|
||||||
# optionally pass need_name=True, need_phone_number=True,
|
# optionally pass need_name=True, need_phone_number=True,
|
||||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||||
context.bot.send_invoice(chat_id, title, description, payload,
|
context.bot.send_invoice(
|
||||||
provider_token, start_parameter, currency, prices,
|
chat_id,
|
||||||
need_name=True, need_phone_number=True,
|
title,
|
||||||
need_email=True, need_shipping_address=True, is_flexible=True)
|
description,
|
||||||
|
payload,
|
||||||
|
provider_token,
|
||||||
|
start_parameter,
|
||||||
|
currency,
|
||||||
|
prices,
|
||||||
|
need_name=True,
|
||||||
|
need_phone_number=True,
|
||||||
|
need_email=True,
|
||||||
|
need_shipping_address=True,
|
||||||
|
is_flexible=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def start_without_shipping_callback(update, context):
|
def start_without_shipping_callback(update, context):
|
||||||
|
@ -66,8 +84,9 @@ def start_without_shipping_callback(update, context):
|
||||||
|
|
||||||
# optionally pass need_name=True, need_phone_number=True,
|
# optionally pass need_name=True, need_phone_number=True,
|
||||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||||
context.bot.send_invoice(chat_id, title, description, payload,
|
context.bot.send_invoice(
|
||||||
provider_token, start_parameter, currency, prices)
|
chat_id, title, description, payload, provider_token, start_parameter, currency, prices
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def shipping_callback(update, context):
|
def shipping_callback(update, context):
|
||||||
|
|
|
@ -15,22 +15,31 @@ bot.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from telegram import ReplyKeyboardMarkup
|
from telegram import ReplyKeyboardMarkup
|
||||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
from telegram.ext import (
|
||||||
ConversationHandler, PicklePersistence)
|
Updater,
|
||||||
|
CommandHandler,
|
||||||
|
MessageHandler,
|
||||||
|
Filters,
|
||||||
|
ConversationHandler,
|
||||||
|
PicklePersistence,
|
||||||
|
)
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
||||||
|
|
||||||
reply_keyboard = [['Age', 'Favourite colour'],
|
reply_keyboard = [
|
||||||
['Number of siblings', 'Something else...'],
|
['Age', 'Favourite colour'],
|
||||||
['Done']]
|
['Number of siblings', 'Something else...'],
|
||||||
|
['Done'],
|
||||||
|
]
|
||||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,12 +55,16 @@ def facts_to_str(user_data):
|
||||||
def start(update, context):
|
def start(update, context):
|
||||||
reply_text = "Hi! My name is Doctor Botter."
|
reply_text = "Hi! My name is Doctor Botter."
|
||||||
if context.user_data:
|
if context.user_data:
|
||||||
reply_text += " You already told me your {}. Why don't you tell me something more " \
|
reply_text += (
|
||||||
"about yourself? Or change anything I " \
|
" You already told me your {}. Why don't you tell me something more "
|
||||||
"already know.".format(", ".join(context.user_data.keys()))
|
"about yourself? Or change anything I "
|
||||||
|
"already know.".format(", ".join(context.user_data.keys()))
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
reply_text += " I will hold a more complex conversation with you. Why don't you tell me " \
|
reply_text += (
|
||||||
"something about yourself?"
|
" I will hold a more complex conversation with you. Why don't you tell me "
|
||||||
|
"something about yourself?"
|
||||||
|
)
|
||||||
update.message.reply_text(reply_text, reply_markup=markup)
|
update.message.reply_text(reply_text, reply_markup=markup)
|
||||||
|
|
||||||
return CHOOSING
|
return CHOOSING
|
||||||
|
@ -61,8 +74,9 @@ def regular_choice(update, context):
|
||||||
text = update.message.text.lower()
|
text = update.message.text.lower()
|
||||||
context.user_data['choice'] = text
|
context.user_data['choice'] = text
|
||||||
if context.user_data.get(text):
|
if context.user_data.get(text):
|
||||||
reply_text = 'Your {}, I already know the following ' \
|
reply_text = 'Your {}, I already know the following ' 'about that: {}'.format(
|
||||||
'about that: {}'.format(text, context.user_data[text])
|
text, context.user_data[text]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
reply_text = 'Your {}? Yes, I would love to hear about that!'.format(text)
|
reply_text = 'Your {}? Yes, I would love to hear about that!'.format(text)
|
||||||
update.message.reply_text(reply_text)
|
update.message.reply_text(reply_text)
|
||||||
|
@ -71,8 +85,9 @@ def regular_choice(update, context):
|
||||||
|
|
||||||
|
|
||||||
def custom_choice(update, context):
|
def custom_choice(update, context):
|
||||||
update.message.reply_text('Alright, please send me the category first, '
|
update.message.reply_text(
|
||||||
'for example "Most impressive skill"')
|
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||||
|
)
|
||||||
|
|
||||||
return TYPING_CHOICE
|
return TYPING_CHOICE
|
||||||
|
|
||||||
|
@ -83,27 +98,32 @@ def received_information(update, context):
|
||||||
context.user_data[category] = text.lower()
|
context.user_data[category] = text.lower()
|
||||||
del context.user_data['choice']
|
del context.user_data['choice']
|
||||||
|
|
||||||
update.message.reply_text("Neat! Just so you know, this is what you already told me:"
|
update.message.reply_text(
|
||||||
"{}"
|
"Neat! Just so you know, this is what you already told me:"
|
||||||
"You can tell me more, or change your opinion on "
|
"{}"
|
||||||
"something.".format(facts_to_str(context.user_data)),
|
"You can tell me more, or change your opinion on "
|
||||||
reply_markup=markup)
|
"something.".format(facts_to_str(context.user_data)),
|
||||||
|
reply_markup=markup,
|
||||||
|
)
|
||||||
|
|
||||||
return CHOOSING
|
return CHOOSING
|
||||||
|
|
||||||
|
|
||||||
def show_data(update, context):
|
def show_data(update, context):
|
||||||
update.message.reply_text("This is what you already told me:"
|
update.message.reply_text(
|
||||||
"{}".format(facts_to_str(context.user_data)))
|
"This is what you already told me:" "{}".format(facts_to_str(context.user_data))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def done(update, context):
|
def done(update, context):
|
||||||
if 'choice' in context.user_data:
|
if 'choice' in context.user_data:
|
||||||
del context.user_data['choice']
|
del context.user_data['choice']
|
||||||
|
|
||||||
update.message.reply_text("I learned these facts about you:"
|
update.message.reply_text(
|
||||||
"{}"
|
"I learned these facts about you:"
|
||||||
"Until next time!".format(facts_to_str(context.user_data)))
|
"{}"
|
||||||
|
"Until next time!".format(facts_to_str(context.user_data))
|
||||||
|
)
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,26 +138,28 @@ def main():
|
||||||
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
||||||
conv_handler = ConversationHandler(
|
conv_handler = ConversationHandler(
|
||||||
entry_points=[CommandHandler('start', start)],
|
entry_points=[CommandHandler('start', start)],
|
||||||
|
|
||||||
states={
|
states={
|
||||||
CHOOSING: [MessageHandler(Filters.regex('^(Age|Favourite colour|Number of siblings)$'),
|
CHOOSING: [
|
||||||
regular_choice),
|
MessageHandler(
|
||||||
MessageHandler(Filters.regex('^Something else...$'),
|
Filters.regex('^(Age|Favourite colour|Number of siblings)$'), regular_choice
|
||||||
custom_choice),
|
),
|
||||||
],
|
MessageHandler(Filters.regex('^Something else...$'), custom_choice),
|
||||||
|
],
|
||||||
TYPING_CHOICE: [
|
TYPING_CHOICE: [
|
||||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
MessageHandler(
|
||||||
regular_choice)],
|
Filters.text & ~(Filters.command | Filters.regex('^Done$')), regular_choice
|
||||||
|
)
|
||||||
|
],
|
||||||
TYPING_REPLY: [
|
TYPING_REPLY: [
|
||||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
MessageHandler(
|
||||||
received_information)],
|
Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||||
|
received_information,
|
||||||
|
)
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
fallbacks=[MessageHandler(Filters.regex('^Done$'), done)],
|
fallbacks=[MessageHandler(Filters.regex('^Done$'), done)],
|
||||||
name="my_conversation",
|
name="my_conversation",
|
||||||
persistent=True
|
persistent=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
dp.add_handler(conv_handler)
|
dp.add_handler(conv_handler)
|
||||||
|
|
|
@ -9,30 +9,56 @@ one the user sends the bot
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telegram import (Poll, ParseMode, KeyboardButton, KeyboardButtonPollType,
|
from telegram import (
|
||||||
ReplyKeyboardMarkup, ReplyKeyboardRemove)
|
Poll,
|
||||||
from telegram.ext import (Updater, CommandHandler, PollAnswerHandler, PollHandler, MessageHandler,
|
ParseMode,
|
||||||
Filters)
|
KeyboardButton,
|
||||||
|
KeyboardButtonPollType,
|
||||||
|
ReplyKeyboardMarkup,
|
||||||
|
ReplyKeyboardRemove,
|
||||||
|
)
|
||||||
|
from telegram.ext import (
|
||||||
|
Updater,
|
||||||
|
CommandHandler,
|
||||||
|
PollAnswerHandler,
|
||||||
|
PollHandler,
|
||||||
|
MessageHandler,
|
||||||
|
Filters,
|
||||||
|
)
|
||||||
|
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def start(update, context):
|
def start(update, context):
|
||||||
"""Inform user about what this bot can do"""
|
"""Inform user about what this bot can do"""
|
||||||
update.message.reply_text('Please select /poll to get a Poll, /quiz to get a Quiz or /preview'
|
update.message.reply_text(
|
||||||
' to generate a preview for your poll')
|
'Please select /poll to get a Poll, /quiz to get a Quiz or /preview'
|
||||||
|
' to generate a preview for your poll'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def poll(update, context):
|
def poll(update, context):
|
||||||
"""Sends a predefined poll"""
|
"""Sends a predefined poll"""
|
||||||
questions = ["Good", "Really good", "Fantastic", "Great"]
|
questions = ["Good", "Really good", "Fantastic", "Great"]
|
||||||
message = context.bot.send_poll(update.effective_chat.id, "How are you?", questions,
|
message = context.bot.send_poll(
|
||||||
is_anonymous=False, allows_multiple_answers=True)
|
update.effective_chat.id,
|
||||||
|
"How are you?",
|
||||||
|
questions,
|
||||||
|
is_anonymous=False,
|
||||||
|
allows_multiple_answers=True,
|
||||||
|
)
|
||||||
# Save some info about the poll the bot_data for later use in receive_poll_answer
|
# Save some info about the poll the bot_data for later use in receive_poll_answer
|
||||||
payload = {message.poll.id: {"questions": questions, "message_id": message.message_id,
|
payload = {
|
||||||
"chat_id": update.effective_chat.id, "answers": 0}}
|
message.poll.id: {
|
||||||
|
"questions": questions,
|
||||||
|
"message_id": message.message_id,
|
||||||
|
"chat_id": update.effective_chat.id,
|
||||||
|
"answers": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
context.bot_data.update(payload)
|
context.bot_data.update(payload)
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,25 +78,29 @@ def receive_poll_answer(update, context):
|
||||||
answer_string += questions[question_id] + " and "
|
answer_string += questions[question_id] + " and "
|
||||||
else:
|
else:
|
||||||
answer_string += questions[question_id]
|
answer_string += questions[question_id]
|
||||||
context.bot.send_message(context.bot_data[poll_id]["chat_id"],
|
context.bot.send_message(
|
||||||
"{} feels {}!".format(update.effective_user.mention_html(),
|
context.bot_data[poll_id]["chat_id"],
|
||||||
answer_string),
|
"{} feels {}!".format(update.effective_user.mention_html(), answer_string),
|
||||||
parse_mode=ParseMode.HTML)
|
parse_mode=ParseMode.HTML,
|
||||||
|
)
|
||||||
context.bot_data[poll_id]["answers"] += 1
|
context.bot_data[poll_id]["answers"] += 1
|
||||||
# Close poll after three participants voted
|
# Close poll after three participants voted
|
||||||
if context.bot_data[poll_id]["answers"] == 3:
|
if context.bot_data[poll_id]["answers"] == 3:
|
||||||
context.bot.stop_poll(context.bot_data[poll_id]["chat_id"],
|
context.bot.stop_poll(
|
||||||
context.bot_data[poll_id]["message_id"])
|
context.bot_data[poll_id]["chat_id"], context.bot_data[poll_id]["message_id"]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def quiz(update, context):
|
def quiz(update, context):
|
||||||
"""Send a predefined poll"""
|
"""Send a predefined poll"""
|
||||||
questions = ["1", "2", "4", "20"]
|
questions = ["1", "2", "4", "20"]
|
||||||
message = update.effective_message.reply_poll("How many eggs do you need for a cake?",
|
message = update.effective_message.reply_poll(
|
||||||
questions, type=Poll.QUIZ, correct_option_id=2)
|
"How many eggs do you need for a cake?", questions, type=Poll.QUIZ, correct_option_id=2
|
||||||
|
)
|
||||||
# Save some info about the poll the bot_data for later use in receive_quiz_answer
|
# Save some info about the poll the bot_data for later use in receive_quiz_answer
|
||||||
payload = {message.poll.id: {"chat_id": update.effective_chat.id,
|
payload = {
|
||||||
"message_id": message.message_id}}
|
message.poll.id: {"chat_id": update.effective_chat.id, "message_id": message.message_id}
|
||||||
|
}
|
||||||
context.bot_data.update(payload)
|
context.bot_data.update(payload)
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,9 +124,9 @@ def preview(update, context):
|
||||||
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
|
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
|
||||||
message = "Press the button to let the bot generate a preview for your poll"
|
message = "Press the button to let the bot generate a preview for your poll"
|
||||||
# using one_time_keyboard to hide the keyboard
|
# using one_time_keyboard to hide the keyboard
|
||||||
update.effective_message.reply_text(message,
|
update.effective_message.reply_text(
|
||||||
reply_markup=ReplyKeyboardMarkup(button,
|
message, reply_markup=ReplyKeyboardMarkup(button, one_time_keyboard=True)
|
||||||
one_time_keyboard=True))
|
)
|
||||||
|
|
||||||
|
|
||||||
def receive_poll(update, context):
|
def receive_poll(update, context):
|
||||||
|
@ -109,14 +139,13 @@ def receive_poll(update, context):
|
||||||
options=[o.text for o in actual_poll.options],
|
options=[o.text for o in actual_poll.options],
|
||||||
# with is_closed true, the poll/quiz is immediately closed
|
# with is_closed true, the poll/quiz is immediately closed
|
||||||
is_closed=True,
|
is_closed=True,
|
||||||
reply_markup=ReplyKeyboardRemove()
|
reply_markup=ReplyKeyboardRemove(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def help_handler(update, context):
|
def help_handler(update, context):
|
||||||
"""Display a help message"""
|
"""Display a help message"""
|
||||||
update.message.reply_text("Use /quiz, /poll or /preview to test this "
|
update.message.reply_text("Use /quiz, /poll or /preview to test this " "bot.")
|
||||||
"bot.")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -23,8 +23,9 @@ import logging
|
||||||
from telegram.ext import Updater, CommandHandler
|
from telegram.ext import Updater, CommandHandler
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
logging.basicConfig(
|
||||||
level=logging.INFO)
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -90,10 +91,9 @@ def main():
|
||||||
# on different commands - answer in Telegram
|
# on different commands - answer in Telegram
|
||||||
dp.add_handler(CommandHandler("start", start))
|
dp.add_handler(CommandHandler("start", start))
|
||||||
dp.add_handler(CommandHandler("help", start))
|
dp.add_handler(CommandHandler("help", start))
|
||||||
dp.add_handler(CommandHandler("set", set_timer,
|
dp.add_handler(
|
||||||
pass_args=True,
|
CommandHandler("set", set_timer, pass_args=True, pass_job_queue=True, pass_chat_data=True)
|
||||||
pass_job_queue=True,
|
)
|
||||||
pass_chat_data=True))
|
|
||||||
dp.add_handler(CommandHandler("unset", unset, pass_chat_data=True))
|
dp.add_handler(CommandHandler("unset", unset, pass_chat_data=True))
|
||||||
|
|
||||||
# Start the Bot
|
# Start the Bot
|
||||||
|
|
6
pyproject.toml
Normal file
6
pyproject.toml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[tool.black]
|
||||||
|
line-length = 99
|
||||||
|
target-version = ['py36']
|
||||||
|
include = '(telegram|examples|tests)/.*\.py$'
|
||||||
|
exclude = 'telegram/vendor'
|
||||||
|
skip-string-normalization = true
|
|
@ -15,13 +15,9 @@ upload-dir = docs/build/html
|
||||||
[flake8]
|
[flake8]
|
||||||
max-line-length = 99
|
max-line-length = 99
|
||||||
ignore = W503, W605
|
ignore = W503, W605
|
||||||
|
extend-ignore = E203
|
||||||
exclude = setup.py, docs/source/conf.py
|
exclude = setup.py, docs/source/conf.py
|
||||||
|
|
||||||
[yapf]
|
|
||||||
based_on_style = google
|
|
||||||
split_before_logical_operator = True
|
|
||||||
column_limit = 99
|
|
||||||
|
|
||||||
[tool:pytest]
|
[tool:pytest]
|
||||||
testpaths = tests
|
testpaths = tests
|
||||||
addopts = --no-success-flaky-report -rsxX
|
addopts = --no-success-flaky-report -rsxX
|
||||||
|
|
|
@ -102,63 +102,170 @@ from .payment.shippingquery import ShippingQuery
|
||||||
from .webhookinfo import WebhookInfo
|
from .webhookinfo import WebhookInfo
|
||||||
from .games.gamehighscore import GameHighScore
|
from .games.gamehighscore import GameHighScore
|
||||||
from .update import Update
|
from .update import Update
|
||||||
from .files.inputmedia import (InputMedia, InputMediaVideo, InputMediaPhoto, InputMediaAnimation,
|
from .files.inputmedia import (
|
||||||
InputMediaAudio, InputMediaDocument)
|
InputMedia,
|
||||||
from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOOK_PORTS,
|
InputMediaVideo,
|
||||||
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
|
InputMediaPhoto,
|
||||||
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
|
InputMediaAnimation,
|
||||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP)
|
InputMediaAudio,
|
||||||
from .passport.passportelementerrors import (PassportElementError,
|
InputMediaDocument,
|
||||||
PassportElementErrorDataField,
|
)
|
||||||
PassportElementErrorFile,
|
from .constants import (
|
||||||
PassportElementErrorFiles,
|
MAX_MESSAGE_LENGTH,
|
||||||
PassportElementErrorFrontSide,
|
MAX_CAPTION_LENGTH,
|
||||||
PassportElementErrorReverseSide,
|
SUPPORTED_WEBHOOK_PORTS,
|
||||||
PassportElementErrorSelfie,
|
MAX_FILESIZE_DOWNLOAD,
|
||||||
PassportElementErrorTranslationFile,
|
MAX_FILESIZE_UPLOAD,
|
||||||
PassportElementErrorTranslationFiles,
|
MAX_MESSAGES_PER_SECOND_PER_CHAT,
|
||||||
PassportElementErrorUnspecified)
|
MAX_MESSAGES_PER_SECOND,
|
||||||
from .passport.credentials import (Credentials,
|
MAX_MESSAGES_PER_MINUTE_PER_GROUP,
|
||||||
DataCredentials,
|
)
|
||||||
SecureData,
|
from .passport.passportelementerrors import (
|
||||||
FileCredentials,
|
PassportElementError,
|
||||||
TelegramDecryptionError)
|
PassportElementErrorDataField,
|
||||||
|
PassportElementErrorFile,
|
||||||
|
PassportElementErrorFiles,
|
||||||
|
PassportElementErrorFrontSide,
|
||||||
|
PassportElementErrorReverseSide,
|
||||||
|
PassportElementErrorSelfie,
|
||||||
|
PassportElementErrorTranslationFile,
|
||||||
|
PassportElementErrorTranslationFiles,
|
||||||
|
PassportElementErrorUnspecified,
|
||||||
|
)
|
||||||
|
from .passport.credentials import (
|
||||||
|
Credentials,
|
||||||
|
DataCredentials,
|
||||||
|
SecureData,
|
||||||
|
FileCredentials,
|
||||||
|
TelegramDecryptionError,
|
||||||
|
)
|
||||||
from .bot import Bot
|
from .bot import Bot
|
||||||
from .version import __version__ # noqa: F401
|
from .version import __version__ # noqa: F401
|
||||||
|
|
||||||
__author__ = 'devs@python-telegram-bot.org'
|
__author__ = 'devs@python-telegram-bot.org'
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Audio', 'Bot', 'Chat', 'ChatMember', 'ChatPermissions', 'ChatAction', 'ChosenInlineResult',
|
'Audio',
|
||||||
'CallbackQuery', 'Contact', 'Document', 'File', 'ForceReply', 'InlineKeyboardButton',
|
'Bot',
|
||||||
'InlineKeyboardMarkup', 'InlineQuery', 'InlineQueryResult', 'InlineQueryResult',
|
'Chat',
|
||||||
'InlineQueryResultArticle', 'InlineQueryResultAudio', 'InlineQueryResultCachedAudio',
|
'ChatMember',
|
||||||
'InlineQueryResultCachedDocument', 'InlineQueryResultCachedGif',
|
'ChatPermissions',
|
||||||
'InlineQueryResultCachedMpeg4Gif', 'InlineQueryResultCachedPhoto',
|
'ChatAction',
|
||||||
'InlineQueryResultCachedSticker', 'InlineQueryResultCachedVideo',
|
'ChosenInlineResult',
|
||||||
'InlineQueryResultCachedVoice', 'InlineQueryResultContact', 'InlineQueryResultDocument',
|
'CallbackQuery',
|
||||||
'InlineQueryResultGif', 'InlineQueryResultLocation', 'InlineQueryResultMpeg4Gif',
|
'Contact',
|
||||||
'InlineQueryResultPhoto', 'InlineQueryResultVenue', 'InlineQueryResultVideo',
|
'Document',
|
||||||
'InlineQueryResultVoice', 'InlineQueryResultGame', 'InputContactMessageContent', 'InputFile',
|
'File',
|
||||||
'InputLocationMessageContent', 'InputMessageContent', 'InputTextMessageContent',
|
'ForceReply',
|
||||||
'InputVenueMessageContent', 'Location', 'EncryptedCredentials',
|
'InlineKeyboardButton',
|
||||||
'PassportFile', 'EncryptedPassportElement', 'PassportData', 'Message', 'MessageEntity',
|
'InlineKeyboardMarkup',
|
||||||
'ParseMode', 'PhotoSize', 'ReplyKeyboardRemove', 'ReplyKeyboardMarkup', 'ReplyMarkup',
|
'InlineQuery',
|
||||||
'Sticker', 'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
|
'InlineQueryResult',
|
||||||
'Video', 'Voice', 'MAX_MESSAGE_LENGTH', 'MAX_CAPTION_LENGTH', 'SUPPORTED_WEBHOOK_PORTS',
|
'InlineQueryResult',
|
||||||
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
'InlineQueryResultArticle',
|
||||||
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
|
'InlineQueryResultAudio',
|
||||||
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
|
'InlineQueryResultCachedAudio',
|
||||||
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto',
|
'InlineQueryResultCachedDocument',
|
||||||
'StickerSet', 'MaskPosition', 'CallbackGame', 'InputMedia', 'InputMediaPhoto',
|
'InlineQueryResultCachedGif',
|
||||||
'InputMediaVideo', 'PassportElementError', 'PassportElementErrorFile',
|
'InlineQueryResultCachedMpeg4Gif',
|
||||||
'PassportElementErrorReverseSide', 'PassportElementErrorFrontSide',
|
'InlineQueryResultCachedPhoto',
|
||||||
'PassportElementErrorFiles', 'PassportElementErrorDataField', 'PassportElementErrorFile',
|
'InlineQueryResultCachedSticker',
|
||||||
'Credentials', 'DataCredentials', 'SecureData', 'FileCredentials', 'IdDocumentData',
|
'InlineQueryResultCachedVideo',
|
||||||
'PersonalDetails', 'ResidentialAddress', 'InputMediaVideo', 'InputMediaAnimation',
|
'InlineQueryResultCachedVoice',
|
||||||
'InputMediaAudio', 'InputMediaDocument', 'TelegramDecryptionError',
|
'InlineQueryResultContact',
|
||||||
'PassportElementErrorSelfie', 'PassportElementErrorTranslationFile',
|
'InlineQueryResultDocument',
|
||||||
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified', 'Poll',
|
'InlineQueryResultGif',
|
||||||
'PollOption', 'PollAnswer', 'LoginUrl', 'KeyboardButton', 'KeyboardButtonPollType', 'Dice',
|
'InlineQueryResultLocation',
|
||||||
'BotCommand'
|
'InlineQueryResultMpeg4Gif',
|
||||||
|
'InlineQueryResultPhoto',
|
||||||
|
'InlineQueryResultVenue',
|
||||||
|
'InlineQueryResultVideo',
|
||||||
|
'InlineQueryResultVoice',
|
||||||
|
'InlineQueryResultGame',
|
||||||
|
'InputContactMessageContent',
|
||||||
|
'InputFile',
|
||||||
|
'InputLocationMessageContent',
|
||||||
|
'InputMessageContent',
|
||||||
|
'InputTextMessageContent',
|
||||||
|
'InputVenueMessageContent',
|
||||||
|
'Location',
|
||||||
|
'EncryptedCredentials',
|
||||||
|
'PassportFile',
|
||||||
|
'EncryptedPassportElement',
|
||||||
|
'PassportData',
|
||||||
|
'Message',
|
||||||
|
'MessageEntity',
|
||||||
|
'ParseMode',
|
||||||
|
'PhotoSize',
|
||||||
|
'ReplyKeyboardRemove',
|
||||||
|
'ReplyKeyboardMarkup',
|
||||||
|
'ReplyMarkup',
|
||||||
|
'Sticker',
|
||||||
|
'TelegramError',
|
||||||
|
'TelegramObject',
|
||||||
|
'Update',
|
||||||
|
'User',
|
||||||
|
'UserProfilePhotos',
|
||||||
|
'Venue',
|
||||||
|
'Video',
|
||||||
|
'Voice',
|
||||||
|
'MAX_MESSAGE_LENGTH',
|
||||||
|
'MAX_CAPTION_LENGTH',
|
||||||
|
'SUPPORTED_WEBHOOK_PORTS',
|
||||||
|
'MAX_FILESIZE_DOWNLOAD',
|
||||||
|
'MAX_FILESIZE_UPLOAD',
|
||||||
|
'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
||||||
|
'MAX_MESSAGES_PER_SECOND',
|
||||||
|
'MAX_MESSAGES_PER_MINUTE_PER_GROUP',
|
||||||
|
'WebhookInfo',
|
||||||
|
'Animation',
|
||||||
|
'Game',
|
||||||
|
'GameHighScore',
|
||||||
|
'VideoNote',
|
||||||
|
'LabeledPrice',
|
||||||
|
'SuccessfulPayment',
|
||||||
|
'ShippingOption',
|
||||||
|
'ShippingAddress',
|
||||||
|
'PreCheckoutQuery',
|
||||||
|
'OrderInfo',
|
||||||
|
'Invoice',
|
||||||
|
'ShippingQuery',
|
||||||
|
'ChatPhoto',
|
||||||
|
'StickerSet',
|
||||||
|
'MaskPosition',
|
||||||
|
'CallbackGame',
|
||||||
|
'InputMedia',
|
||||||
|
'InputMediaPhoto',
|
||||||
|
'InputMediaVideo',
|
||||||
|
'PassportElementError',
|
||||||
|
'PassportElementErrorFile',
|
||||||
|
'PassportElementErrorReverseSide',
|
||||||
|
'PassportElementErrorFrontSide',
|
||||||
|
'PassportElementErrorFiles',
|
||||||
|
'PassportElementErrorDataField',
|
||||||
|
'PassportElementErrorFile',
|
||||||
|
'Credentials',
|
||||||
|
'DataCredentials',
|
||||||
|
'SecureData',
|
||||||
|
'FileCredentials',
|
||||||
|
'IdDocumentData',
|
||||||
|
'PersonalDetails',
|
||||||
|
'ResidentialAddress',
|
||||||
|
'InputMediaVideo',
|
||||||
|
'InputMediaAnimation',
|
||||||
|
'InputMediaAudio',
|
||||||
|
'InputMediaDocument',
|
||||||
|
'TelegramDecryptionError',
|
||||||
|
'PassportElementErrorSelfie',
|
||||||
|
'PassportElementErrorTranslationFile',
|
||||||
|
'PassportElementErrorTranslationFiles',
|
||||||
|
'PassportElementErrorUnspecified',
|
||||||
|
'Poll',
|
||||||
|
'PollOption',
|
||||||
|
'PollAnswer',
|
||||||
|
'LoginUrl',
|
||||||
|
'KeyboardButton',
|
||||||
|
'KeyboardButtonPollType',
|
||||||
|
'Dice',
|
||||||
|
'BotCommand',
|
||||||
]
|
]
|
||||||
|
|
|
@ -28,8 +28,9 @@ from . import __version__ as telegram_ver
|
||||||
|
|
||||||
def _git_revision() -> Optional[str]:
|
def _git_revision() -> Optional[str]:
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(["git", "describe", "--long", "--tags"],
|
output = subprocess.check_output(
|
||||||
stderr=subprocess.STDOUT)
|
["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT
|
||||||
|
)
|
||||||
except (subprocess.SubprocessError, OSError):
|
except (subprocess.SubprocessError, OSError):
|
||||||
return None
|
return None
|
||||||
return output.decode().strip()
|
return output.decode().strip()
|
||||||
|
@ -37,8 +38,10 @@ def _git_revision() -> Optional[str]:
|
||||||
|
|
||||||
def print_ver_info() -> None:
|
def print_ver_info() -> None:
|
||||||
git_revision = _git_revision()
|
git_revision = _git_revision()
|
||||||
print('python-telegram-bot {}'.format(telegram_ver) + (' ({})'.format(git_revision)
|
print(
|
||||||
if git_revision else ''))
|
'python-telegram-bot {}'.format(telegram_ver)
|
||||||
|
+ (' ({})'.format(git_revision) if git_revision else '')
|
||||||
|
)
|
||||||
print('certifi {}'.format(certifi.__version__)) # type: ignore[attr-defined]
|
print('certifi {}'.format(certifi.__version__)) # type: ignore[attr-defined]
|
||||||
print('Python {}'.format(sys.version.replace('\n', ' ')))
|
print('Python {}'.format(sys.version.replace('\n', ' ')))
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,7 @@ class TelegramObject:
|
||||||
return cls(bot=bot, **data) # type: ignore[call-arg]
|
return cls(bot=bot, **data) # type: ignore[call-arg]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_list(cls: Type[TO],
|
def de_list(cls: Type[TO], data: Optional[List[JSONDict]], bot: 'Bot') -> List[Optional[TO]]:
|
||||||
data: Optional[List[JSONDict]],
|
|
||||||
bot: 'Bot') -> List[Optional[TO]]:
|
|
||||||
if not data:
|
if not data:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -104,11 +102,15 @@ class TelegramObject:
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
if self._id_attrs == ():
|
if self._id_attrs == ():
|
||||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
warnings.warn(
|
||||||
"equivalence.".format(self.__class__.__name__))
|
"Objects of type {} can not be meaningfully tested for "
|
||||||
|
"equivalence.".format(self.__class__.__name__)
|
||||||
|
)
|
||||||
if other._id_attrs == ():
|
if other._id_attrs == ():
|
||||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
warnings.warn(
|
||||||
"equivalence.".format(other.__class__.__name__))
|
"Objects of type {} can not be meaningfully tested for "
|
||||||
|
"equivalence.".format(other.__class__.__name__)
|
||||||
|
)
|
||||||
return self._id_attrs == other._id_attrs
|
return self._id_attrs == other._id_attrs
|
||||||
return super().__eq__(other) # pylint: disable=no-member
|
return super().__eq__(other) # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
1708
telegram/bot.py
1708
telegram/bot.py
File diff suppressed because it is too large
Load diff
|
@ -38,6 +38,7 @@ class BotCommand(TelegramObject):
|
||||||
English letters, digits and underscores.
|
English letters, digits and underscores.
|
||||||
description (:obj:`str`): Description of the command, 3-256 characters.
|
description (:obj:`str`): Description of the command, 3-256 characters.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, command: str, description: str, **kwargs: Any):
|
def __init__(self, command: str, description: str, **kwargs: Any):
|
||||||
self.command = command
|
self.command = command
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
|
@ -78,16 +78,18 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
from_user: User,
|
id: str,
|
||||||
chat_instance: str,
|
from_user: User,
|
||||||
message: Message = None,
|
chat_instance: str,
|
||||||
data: str = None,
|
message: Message = None,
|
||||||
inline_message_id: str = None,
|
data: str = None,
|
||||||
game_short_name: str = None,
|
inline_message_id: str = None,
|
||||||
bot: 'Bot' = None,
|
game_short_name: str = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.id = id
|
self.id = id
|
||||||
self.from_user = from_user
|
self.from_user = from_user
|
||||||
|
@ -143,14 +145,21 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.edit_message_text(text, inline_message_id=self.inline_message_id,
|
return self.bot.edit_message_text(
|
||||||
*args, **kwargs)
|
text, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.edit_message_text(text, chat_id=self.message.chat_id,
|
return self.bot.edit_message_text(
|
||||||
message_id=self.message.message_id, *args, **kwargs)
|
text,
|
||||||
|
chat_id=self.message.chat_id,
|
||||||
|
message_id=self.message.message_id,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def edit_message_caption(self, caption: str, *args: Any,
|
def edit_message_caption(
|
||||||
**kwargs: Any) -> Union[Message, bool]:
|
self, caption: str, *args: Any, **kwargs: Any
|
||||||
|
) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
|
||||||
bot.edit_message_caption(caption=caption,
|
bot.edit_message_caption(caption=caption,
|
||||||
|
@ -170,16 +179,21 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.edit_message_caption(caption=caption,
|
return self.bot.edit_message_caption(
|
||||||
inline_message_id=self.inline_message_id,
|
caption=caption, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.edit_message_caption(caption=caption, chat_id=self.message.chat_id,
|
return self.bot.edit_message_caption(
|
||||||
message_id=self.message.message_id,
|
caption=caption,
|
||||||
*args, **kwargs)
|
chat_id=self.message.chat_id,
|
||||||
|
message_id=self.message.message_id,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def edit_message_reply_markup(self, reply_markup: 'InlineKeyboardMarkup', *args: Any,
|
def edit_message_reply_markup(
|
||||||
**kwargs: Any) -> Union[Message, bool]:
|
self, reply_markup: 'InlineKeyboardMarkup', *args: Any, **kwargs: Any
|
||||||
|
) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
|
||||||
bot.edit_message_reply_markup(chat_id=update.callback_query.message.chat_id,
|
bot.edit_message_reply_markup(chat_id=update.callback_query.message.chat_id,
|
||||||
|
@ -199,14 +213,20 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.edit_message_reply_markup(reply_markup=reply_markup,
|
return self.bot.edit_message_reply_markup(
|
||||||
inline_message_id=self.inline_message_id,
|
reply_markup=reply_markup,
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.edit_message_reply_markup(reply_markup=reply_markup,
|
return self.bot.edit_message_reply_markup(
|
||||||
chat_id=self.message.chat_id,
|
reply_markup=reply_markup,
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id,
|
||||||
*args, **kwargs)
|
message_id=self.message.message_id,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
@ -228,12 +248,13 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.edit_message_media(inline_message_id=self.inline_message_id,
|
return self.bot.edit_message_media(
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.edit_message_media(chat_id=self.message.chat_id,
|
return self.bot.edit_message_media(
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
|
|
||||||
def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
@ -257,12 +278,13 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.edit_message_live_location(inline_message_id=self.inline_message_id,
|
return self.bot.edit_message_live_location(
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.edit_message_live_location(chat_id=self.message.chat_id,
|
return self.bot.edit_message_live_location(
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
|
|
||||||
def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
@ -286,12 +308,13 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.stop_message_live_location(inline_message_id=self.inline_message_id,
|
return self.bot.stop_message_live_location(
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.stop_message_live_location(chat_id=self.message.chat_id,
|
return self.bot.stop_message_live_location(
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
|
|
||||||
def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
@ -313,12 +336,13 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.set_game_score(inline_message_id=self.inline_message_id,
|
return self.bot.set_game_score(
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.set_game_score(chat_id=self.message.chat_id,
|
return self.bot.set_game_score(
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
|
|
||||||
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
||||||
"""Shortcut for either::
|
"""Shortcut for either::
|
||||||
|
@ -339,9 +363,10 @@ class CallbackQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.inline_message_id:
|
if self.inline_message_id:
|
||||||
return self.bot.get_game_high_scores(inline_message_id=self.inline_message_id,
|
return self.bot.get_game_high_scores(
|
||||||
*args, **kwargs)
|
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bot.get_game_high_scores(chat_id=self.message.chat_id,
|
return self.bot.get_game_high_scores(
|
||||||
message_id=self.message.message_id,
|
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||||
*args, **kwargs)
|
)
|
||||||
|
|
|
@ -24,6 +24,7 @@ from .chatpermissions import ChatPermissions
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, List, TYPE_CHECKING
|
from typing import Any, Optional, List, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, Message, ChatMember
|
from telegram import Bot, Message, ChatMember
|
||||||
|
|
||||||
|
@ -100,23 +101,25 @@ class Chat(TelegramObject):
|
||||||
CHANNEL: str = 'channel'
|
CHANNEL: str = 'channel'
|
||||||
""":obj:`str`: 'channel'"""
|
""":obj:`str`: 'channel'"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: int,
|
self,
|
||||||
type: str,
|
id: int,
|
||||||
title: str = None,
|
type: str,
|
||||||
username: str = None,
|
title: str = None,
|
||||||
first_name: str = None,
|
username: str = None,
|
||||||
last_name: str = None,
|
first_name: str = None,
|
||||||
bot: 'Bot' = None,
|
last_name: str = None,
|
||||||
photo: ChatPhoto = None,
|
bot: 'Bot' = None,
|
||||||
description: str = None,
|
photo: ChatPhoto = None,
|
||||||
invite_link: str = None,
|
description: str = None,
|
||||||
pinned_message: 'Message' = None,
|
invite_link: str = None,
|
||||||
permissions: ChatPermissions = None,
|
pinned_message: 'Message' = None,
|
||||||
sticker_set_name: str = None,
|
permissions: ChatPermissions = None,
|
||||||
can_set_sticker_set: bool = None,
|
sticker_set_name: str = None,
|
||||||
slow_mode_delay: int = None,
|
can_set_sticker_set: bool = None,
|
||||||
**kwargs: Any):
|
slow_mode_delay: int = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.id = int(id)
|
self.id = int(id)
|
||||||
self.type = type
|
self.type = type
|
||||||
|
@ -156,6 +159,7 @@ class Chat(TelegramObject):
|
||||||
|
|
||||||
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
|
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
|
||||||
from telegram import Message
|
from telegram import Message
|
||||||
|
|
||||||
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
|
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
|
||||||
data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot)
|
data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot)
|
||||||
|
|
||||||
|
@ -243,7 +247,7 @@ class Chat(TelegramObject):
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`bool`: If the action was sent successfully.
|
:obj:`bool`: If the action was sent successfully.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.bot.set_chat_permissions(self.id, *args, **kwargs)
|
return self.bot.set_chat_permissions(self.id, *args, **kwargs)
|
||||||
|
|
||||||
def set_administrator_custom_title(self, *args: Any, **kwargs: Any) -> bool:
|
def set_administrator_custom_title(self, *args: Any, **kwargs: Any) -> bool:
|
||||||
|
@ -254,7 +258,7 @@ class Chat(TelegramObject):
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`bool`: If the action was sent successfully.
|
:obj:`bool`: If the action was sent successfully.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs)
|
return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs)
|
||||||
|
|
||||||
def send_message(self, *args: Any, **kwargs: Any) -> 'Message':
|
def send_message(self, *args: Any, **kwargs: Any) -> 'Message':
|
||||||
|
|
|
@ -24,6 +24,7 @@ from telegram.utils.helpers import to_timestamp, from_timestamp
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -110,6 +111,7 @@ class ChatMember(TelegramObject):
|
||||||
may add web page previews to his messages.
|
may add web page previews to his messages.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ADMINISTRATOR: str = 'administrator'
|
ADMINISTRATOR: str = 'administrator'
|
||||||
""":obj:`str`: 'administrator'"""
|
""":obj:`str`: 'administrator'"""
|
||||||
CREATOR: str = 'creator'
|
CREATOR: str = 'creator'
|
||||||
|
@ -123,27 +125,29 @@ class ChatMember(TelegramObject):
|
||||||
RESTRICTED: str = 'restricted'
|
RESTRICTED: str = 'restricted'
|
||||||
""":obj:`str`: 'restricted'"""
|
""":obj:`str`: 'restricted'"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
user: User,
|
self,
|
||||||
status: str,
|
user: User,
|
||||||
until_date: datetime.datetime = None,
|
status: str,
|
||||||
can_be_edited: bool = None,
|
until_date: datetime.datetime = None,
|
||||||
can_change_info: bool = None,
|
can_be_edited: bool = None,
|
||||||
can_post_messages: bool = None,
|
can_change_info: bool = None,
|
||||||
can_edit_messages: bool = None,
|
can_post_messages: bool = None,
|
||||||
can_delete_messages: bool = None,
|
can_edit_messages: bool = None,
|
||||||
can_invite_users: bool = None,
|
can_delete_messages: bool = None,
|
||||||
can_restrict_members: bool = None,
|
can_invite_users: bool = None,
|
||||||
can_pin_messages: bool = None,
|
can_restrict_members: bool = None,
|
||||||
can_promote_members: bool = None,
|
can_pin_messages: bool = None,
|
||||||
can_send_messages: bool = None,
|
can_promote_members: bool = None,
|
||||||
can_send_media_messages: bool = None,
|
can_send_messages: bool = None,
|
||||||
can_send_polls: bool = None,
|
can_send_media_messages: bool = None,
|
||||||
can_send_other_messages: bool = None,
|
can_send_polls: bool = None,
|
||||||
can_add_web_page_previews: bool = None,
|
can_send_other_messages: bool = None,
|
||||||
is_member: bool = None,
|
can_add_web_page_previews: bool = None,
|
||||||
custom_title: str = None,
|
is_member: bool = None,
|
||||||
**kwargs: Any):
|
custom_title: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.user = user
|
self.user = user
|
||||||
self.status = status
|
self.status = status
|
||||||
|
|
|
@ -77,16 +77,18 @@ class ChatPermissions(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
can_send_messages: bool = None,
|
self,
|
||||||
can_send_media_messages: bool = None,
|
can_send_messages: bool = None,
|
||||||
can_send_polls: bool = None,
|
can_send_media_messages: bool = None,
|
||||||
can_send_other_messages: bool = None,
|
can_send_polls: bool = None,
|
||||||
can_add_web_page_previews: bool = None,
|
can_send_other_messages: bool = None,
|
||||||
can_change_info: bool = None,
|
can_add_web_page_previews: bool = None,
|
||||||
can_invite_users: bool = None,
|
can_change_info: bool = None,
|
||||||
can_pin_messages: bool = None,
|
can_invite_users: bool = None,
|
||||||
**kwargs: Any):
|
can_pin_messages: bool = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.can_send_messages = can_send_messages
|
self.can_send_messages = can_send_messages
|
||||||
self.can_send_media_messages = can_send_media_messages
|
self.can_send_media_messages = can_send_media_messages
|
||||||
|
@ -105,5 +107,5 @@ class ChatPermissions(TelegramObject):
|
||||||
self.can_add_web_page_previews,
|
self.can_add_web_page_previews,
|
||||||
self.can_change_info,
|
self.can_change_info,
|
||||||
self.can_invite_users,
|
self.can_invite_users,
|
||||||
self.can_pin_messages
|
self.can_pin_messages,
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
from telegram import TelegramObject, User, Location
|
from telegram import TelegramObject, User, Location
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -61,13 +62,15 @@ class ChosenInlineResult(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
result_id: str,
|
self,
|
||||||
from_user: User,
|
result_id: str,
|
||||||
query: str,
|
from_user: User,
|
||||||
location: Location = None,
|
query: str,
|
||||||
inline_message_id: str = None,
|
location: Location = None,
|
||||||
**kwargs: Any):
|
inline_message_id: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.result_id = result_id
|
self.result_id = result_id
|
||||||
self.from_user = from_user
|
self.from_user = from_user
|
||||||
|
|
|
@ -48,9 +48,9 @@ MAX_CAPTION_LENGTH: int = 1024
|
||||||
# constants above this line are tested
|
# constants above this line are tested
|
||||||
|
|
||||||
SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443]
|
SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443]
|
||||||
MAX_FILESIZE_DOWNLOAD: int = int(20E6) # (20MB)
|
MAX_FILESIZE_DOWNLOAD: int = int(20e6) # (20MB)
|
||||||
MAX_FILESIZE_UPLOAD: int = int(50E6) # (50MB)
|
MAX_FILESIZE_UPLOAD: int = int(50e6) # (50MB)
|
||||||
MAX_PHOTOSIZE_UPLOAD: int = int(10E6) # (10MB)
|
MAX_PHOTOSIZE_UPLOAD: int = int(10e6) # (10MB)
|
||||||
MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1
|
MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1
|
||||||
MAX_MESSAGES_PER_SECOND: int = 30
|
MAX_MESSAGES_PER_SECOND: int = 30
|
||||||
MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20
|
MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20
|
||||||
|
|
|
@ -48,6 +48,7 @@ class Dice(TelegramObject):
|
||||||
value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball.
|
value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball.
|
||||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, value: int, emoji: str, **kwargs: Any):
|
def __init__(self, value: int, emoji: str, **kwargs: Any):
|
||||||
self.value = value
|
self.value = value
|
||||||
self.emoji = emoji
|
self.emoji = emoji
|
||||||
|
|
|
@ -31,7 +31,7 @@ def _lstrip_str(in_s: str, lstr: str) -> str:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if in_s.startswith(lstr):
|
if in_s.startswith(lstr):
|
||||||
res = in_s[len(lstr):]
|
res = in_s[len(lstr) :]
|
||||||
else:
|
else:
|
||||||
res = in_s
|
res = in_s
|
||||||
return res
|
return res
|
||||||
|
@ -116,10 +116,10 @@ class RetryAfter(TelegramError):
|
||||||
|
|
||||||
class Conflict(TelegramError):
|
class Conflict(TelegramError):
|
||||||
"""
|
"""
|
||||||
Raised when a long poll or webhook conflicts with another one.
|
Raised when a long poll or webhook conflicts with another one.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
msg (:obj:`str`): The message from telegrams server.
|
msg (:obj:`str`): The message from telegrams server.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -45,11 +45,38 @@ from .pollanswerhandler import PollAnswerHandler
|
||||||
from .pollhandler import PollHandler
|
from .pollhandler import PollHandler
|
||||||
from .defaults import Defaults
|
from .defaults import Defaults
|
||||||
|
|
||||||
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
|
__all__ = (
|
||||||
'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler',
|
'Dispatcher',
|
||||||
'MessageHandler', 'BaseFilter', 'MessageFilter', 'UpdateFilter', 'Filters',
|
'JobQueue',
|
||||||
'RegexHandler', 'StringCommandHandler', 'StringRegexHandler', 'TypeHandler',
|
'Job',
|
||||||
'ConversationHandler', 'PreCheckoutQueryHandler', 'ShippingQueryHandler',
|
'Updater',
|
||||||
'MessageQueue', 'DelayQueue', 'DispatcherHandlerStop', 'run_async', 'CallbackContext',
|
'CallbackQueryHandler',
|
||||||
'BasePersistence', 'PicklePersistence', 'DictPersistence', 'PrefixHandler',
|
'ChosenInlineResultHandler',
|
||||||
'PollAnswerHandler', 'PollHandler', 'Defaults')
|
'CommandHandler',
|
||||||
|
'Handler',
|
||||||
|
'InlineQueryHandler',
|
||||||
|
'MessageHandler',
|
||||||
|
'BaseFilter',
|
||||||
|
'MessageFilter',
|
||||||
|
'UpdateFilter',
|
||||||
|
'Filters',
|
||||||
|
'RegexHandler',
|
||||||
|
'StringCommandHandler',
|
||||||
|
'StringRegexHandler',
|
||||||
|
'TypeHandler',
|
||||||
|
'ConversationHandler',
|
||||||
|
'PreCheckoutQueryHandler',
|
||||||
|
'ShippingQueryHandler',
|
||||||
|
'MessageQueue',
|
||||||
|
'DelayQueue',
|
||||||
|
'DispatcherHandlerStop',
|
||||||
|
'run_async',
|
||||||
|
'CallbackContext',
|
||||||
|
'BasePersistence',
|
||||||
|
'PicklePersistence',
|
||||||
|
'DictPersistence',
|
||||||
|
'PrefixHandler',
|
||||||
|
'PollAnswerHandler',
|
||||||
|
'PollHandler',
|
||||||
|
'Defaults',
|
||||||
|
)
|
||||||
|
|
|
@ -108,10 +108,12 @@ class BasePersistence(ABC):
|
||||||
instance.update_bot_data = update_bot_data_replace_bot
|
instance.update_bot_data = update_bot_data_replace_bot
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
store_user_data: bool = True,
|
self,
|
||||||
store_chat_data: bool = True,
|
store_user_data: bool = True,
|
||||||
store_bot_data: bool = True):
|
store_chat_data: bool = True,
|
||||||
|
store_bot_data: bool = True,
|
||||||
|
):
|
||||||
self.store_user_data = store_user_data
|
self.store_user_data = store_user_data
|
||||||
self.store_chat_data = store_chat_data
|
self.store_chat_data = store_chat_data
|
||||||
self.store_bot_data = store_bot_data
|
self.store_bot_data = store_bot_data
|
||||||
|
@ -157,8 +159,11 @@ class BasePersistence(ABC):
|
||||||
return new_obj
|
return new_obj
|
||||||
if hasattr(obj, '__slots__'):
|
if hasattr(obj, '__slots__'):
|
||||||
for attr_name in new_obj.__slots__:
|
for attr_name in new_obj.__slots__:
|
||||||
setattr(new_obj, attr_name,
|
setattr(
|
||||||
cls.replace_bot(cls.replace_bot(getattr(new_obj, attr_name))))
|
new_obj,
|
||||||
|
attr_name,
|
||||||
|
cls.replace_bot(cls.replace_bot(getattr(new_obj, attr_name))),
|
||||||
|
)
|
||||||
return new_obj
|
return new_obj
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
@ -196,14 +201,17 @@ class BasePersistence(ABC):
|
||||||
return new_obj
|
return new_obj
|
||||||
if hasattr(obj, '__slots__'):
|
if hasattr(obj, '__slots__'):
|
||||||
for attr_name in obj.__slots__:
|
for attr_name in obj.__slots__:
|
||||||
setattr(new_obj, attr_name,
|
setattr(
|
||||||
self.insert_bot(self.insert_bot(getattr(new_obj, attr_name))))
|
new_obj,
|
||||||
|
attr_name,
|
||||||
|
self.insert_bot(self.insert_bot(getattr(new_obj, attr_name))),
|
||||||
|
)
|
||||||
return new_obj
|
return new_obj
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
def get_user_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||||
persistence object. It should return the user_data if stored, or an empty
|
persistence object. It should return the user_data if stored, or an empty
|
||||||
``defaultdict(dict)``.
|
``defaultdict(dict)``.
|
||||||
|
|
||||||
|
@ -213,7 +221,7 @@ class BasePersistence(ABC):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
def get_chat_data(self) -> DefaultDict[int, Dict[Any, Any]]:
|
||||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||||
persistence object. It should return the chat_data if stored, or an empty
|
persistence object. It should return the chat_data if stored, or an empty
|
||||||
``defaultdict(dict)``.
|
``defaultdict(dict)``.
|
||||||
|
|
||||||
|
@ -223,7 +231,7 @@ class BasePersistence(ABC):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_bot_data(self) -> Dict[Any, Any]:
|
def get_bot_data(self) -> Dict[Any, Any]:
|
||||||
""""Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
""" "Will be called by :class:`telegram.ext.Dispatcher` upon creation with a
|
||||||
persistence object. It should return the bot_data if stored, or an empty
|
persistence object. It should return the bot_data if stored, or an empty
|
||||||
:obj:`dict`.
|
:obj:`dict`.
|
||||||
|
|
||||||
|
@ -233,7 +241,7 @@ class BasePersistence(ABC):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_conversations(self, name: str) -> ConversationDict:
|
def get_conversations(self, name: str) -> ConversationDict:
|
||||||
""""Will be called by :class:`telegram.ext.Dispatcher` when a
|
""" "Will be called by :class:`telegram.ext.Dispatcher` when a
|
||||||
:class:`telegram.ext.ConversationHandler` is added if
|
:class:`telegram.ext.ConversationHandler` is added if
|
||||||
:attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`.
|
:attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`.
|
||||||
It should return the conversations for the handler with `name` or an empty :obj:`dict`
|
It should return the conversations for the handler with `name` or an empty :obj:`dict`
|
||||||
|
@ -246,9 +254,9 @@ class BasePersistence(ABC):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update_conversation(self,
|
def update_conversation(
|
||||||
name: str, key: Tuple[int, ...],
|
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||||
new_state: Optional[object]) -> None:
|
) -> None:
|
||||||
"""Will be called when a :attr:`telegram.ext.ConversationHandler.update_state`
|
"""Will be called when a :attr:`telegram.ext.ConversationHandler.update_state`
|
||||||
is called. This allows the storage of the new state in the persistence.
|
is called. This allows the storage of the new state in the persistence.
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ from queue import Queue
|
||||||
from typing import Dict, Any, Tuple, TYPE_CHECKING, Optional, Match, List, NoReturn, Union
|
from typing import Dict, Any, Tuple, TYPE_CHECKING, Optional, Match, List, NoReturn, Union
|
||||||
|
|
||||||
from telegram import Update
|
from telegram import Update
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
from telegram.ext import Dispatcher, Job, JobQueue
|
from telegram.ext import Dispatcher, Job, JobQueue
|
||||||
|
@ -91,8 +92,9 @@ class CallbackContext:
|
||||||
dispatcher (:class:`telegram.ext.Dispatcher`):
|
dispatcher (:class:`telegram.ext.Dispatcher`):
|
||||||
"""
|
"""
|
||||||
if not dispatcher.use_context:
|
if not dispatcher.use_context:
|
||||||
raise ValueError('CallbackContext should not be used with a non context aware '
|
raise ValueError(
|
||||||
'dispatcher!')
|
'CallbackContext should not be used with a non context aware ' 'dispatcher!'
|
||||||
|
)
|
||||||
self._dispatcher = dispatcher
|
self._dispatcher = dispatcher
|
||||||
self._bot_data = dispatcher.bot_data
|
self._bot_data = dispatcher.bot_data
|
||||||
self._chat_data: Optional[Dict[Any, Any]] = None
|
self._chat_data: Optional[Dict[Any, Any]] = None
|
||||||
|
@ -115,8 +117,9 @@ class CallbackContext:
|
||||||
|
|
||||||
@bot_data.setter
|
@bot_data.setter
|
||||||
def bot_data(self, value: Any) -> NoReturn:
|
def bot_data(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to bot_data, see "
|
raise AttributeError(
|
||||||
"https://git.io/fjxKe")
|
"You can not assign a new value to bot_data, see " "https://git.io/fjxKe"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def chat_data(self) -> Optional[Dict]:
|
def chat_data(self) -> Optional[Dict]:
|
||||||
|
@ -124,8 +127,9 @@ class CallbackContext:
|
||||||
|
|
||||||
@chat_data.setter
|
@chat_data.setter
|
||||||
def chat_data(self, value: Any) -> NoReturn:
|
def chat_data(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to chat_data, see "
|
raise AttributeError(
|
||||||
"https://git.io/fjxKe")
|
"You can not assign a new value to chat_data, see " "https://git.io/fjxKe"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_data(self) -> Optional[Dict]:
|
def user_data(self) -> Optional[Dict]:
|
||||||
|
@ -133,16 +137,19 @@ class CallbackContext:
|
||||||
|
|
||||||
@user_data.setter
|
@user_data.setter
|
||||||
def user_data(self, value: Any) -> NoReturn:
|
def user_data(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to user_data, see "
|
raise AttributeError(
|
||||||
"https://git.io/fjxKe")
|
"You can not assign a new value to user_data, see " "https://git.io/fjxKe"
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_error(cls,
|
def from_error(
|
||||||
update: object,
|
cls,
|
||||||
error: Exception,
|
update: object,
|
||||||
dispatcher: 'Dispatcher',
|
error: Exception,
|
||||||
async_args: Union[List, Tuple] = None,
|
dispatcher: 'Dispatcher',
|
||||||
async_kwargs: Dict[str, Any] = None) -> 'CallbackContext':
|
async_args: Union[List, Tuple] = None,
|
||||||
|
async_kwargs: Dict[str, Any] = None,
|
||||||
|
) -> 'CallbackContext':
|
||||||
self = cls.from_update(update, dispatcher)
|
self = cls.from_update(update, dispatcher)
|
||||||
self.error = error
|
self.error = error
|
||||||
self.async_args = async_args
|
self.async_args = async_args
|
||||||
|
|
|
@ -24,8 +24,18 @@ from telegram import Update
|
||||||
from .handler import Handler
|
from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Pattern, Match, Dict, \
|
from typing import (
|
||||||
cast
|
Callable,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Optional,
|
||||||
|
Union,
|
||||||
|
TypeVar,
|
||||||
|
Pattern,
|
||||||
|
Match,
|
||||||
|
Dict,
|
||||||
|
cast,
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
@ -110,23 +120,26 @@ class CallbackQueryHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
self,
|
||||||
pass_update_queue: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pattern: Union[str, Pattern] = None,
|
pass_job_queue: bool = False,
|
||||||
pass_groups: bool = False,
|
pattern: Union[str, Pattern] = None,
|
||||||
pass_groupdict: bool = False,
|
pass_groups: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_groupdict: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
run_async: bool = False):
|
pass_chat_data: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
pass_user_data=pass_user_data,
|
pass_user_data=pass_user_data,
|
||||||
pass_chat_data=pass_chat_data,
|
pass_chat_data=pass_chat_data,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(pattern, str):
|
if isinstance(pattern, str):
|
||||||
pattern = re.compile(pattern)
|
pattern = re.compile(pattern)
|
||||||
|
@ -155,10 +168,12 @@ class CallbackQueryHandler(Handler):
|
||||||
return True
|
return True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_optional_args(self,
|
def collect_optional_args(
|
||||||
dispatcher: 'Dispatcher',
|
self,
|
||||||
update: HandlerArg = None,
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Union[bool, Match] = None) -> Dict[str, Any]:
|
update: HandlerArg = None,
|
||||||
|
check_result: Union[bool, Match] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||||
if self.pattern:
|
if self.pattern:
|
||||||
check_result = cast(Match, check_result)
|
check_result = cast(Match, check_result)
|
||||||
|
@ -168,11 +183,13 @@ class CallbackQueryHandler(Handler):
|
||||||
optional_args['groupdict'] = check_result.groupdict()
|
optional_args['groupdict'] = check_result.groupdict()
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Union[bool, Match]) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Union[bool, Match],
|
||||||
|
) -> None:
|
||||||
if self.pattern:
|
if self.pattern:
|
||||||
check_result = cast(Match, check_result)
|
check_result = cast(Match, check_result)
|
||||||
context.matches = [check_result]
|
context.matches = [check_result]
|
||||||
|
|
|
@ -23,6 +23,7 @@ from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Optional, Union, TypeVar
|
from typing import Optional, Union, TypeVar
|
||||||
|
|
||||||
RT = TypeVar('RT')
|
RT = TypeVar('RT')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, List, Tuple
|
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, List, Tuple
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -130,24 +131,27 @@ class CommandHandler(Handler):
|
||||||
ValueError - when command is too long or has illegal chars.
|
ValueError - when command is too long or has illegal chars.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
command: Union[str, List[str]],
|
self,
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
command: Union[str, List[str]],
|
||||||
filters: BaseFilter = None,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
allow_edited: bool = None,
|
filters: BaseFilter = None,
|
||||||
pass_args: bool = False,
|
allow_edited: bool = None,
|
||||||
pass_update_queue: bool = False,
|
pass_args: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_job_queue: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
run_async: bool = False):
|
pass_chat_data: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
pass_user_data=pass_user_data,
|
pass_user_data=pass_user_data,
|
||||||
pass_chat_data=pass_chat_data,
|
pass_chat_data=pass_chat_data,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(command, str):
|
if isinstance(command, str):
|
||||||
self.command = [command.lower()]
|
self.command = [command.lower()]
|
||||||
|
@ -163,17 +167,18 @@ class CommandHandler(Handler):
|
||||||
self.filters = Filters.update.messages
|
self.filters = Filters.update.messages
|
||||||
|
|
||||||
if allow_edited is not None:
|
if allow_edited is not None:
|
||||||
warnings.warn('allow_edited is deprecated. See https://git.io/fxJuV for more info',
|
warnings.warn(
|
||||||
TelegramDeprecationWarning,
|
'allow_edited is deprecated. See https://git.io/fxJuV for more info',
|
||||||
stacklevel=2)
|
TelegramDeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
if not allow_edited:
|
if not allow_edited:
|
||||||
self.filters &= ~Filters.update.edited_message
|
self.filters &= ~Filters.update.edited_message
|
||||||
self.pass_args = pass_args
|
self.pass_args = pass_args
|
||||||
|
|
||||||
def check_update(
|
def check_update(
|
||||||
self,
|
self, update: HandlerArg
|
||||||
update: HandlerArg) -> Optional[Union[bool, Tuple[List[str],
|
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
|
||||||
Optional[Union[bool, Dict]]]]]:
|
|
||||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -186,15 +191,22 @@ class CommandHandler(Handler):
|
||||||
if isinstance(update, Update) and update.effective_message:
|
if isinstance(update, Update) and update.effective_message:
|
||||||
message = update.effective_message
|
message = update.effective_message
|
||||||
|
|
||||||
if (message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
|
if (
|
||||||
and message.entities[0].offset == 0 and message.text and message.bot):
|
message.entities
|
||||||
command = message.text[1:message.entities[0].length]
|
and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||||
|
and message.entities[0].offset == 0
|
||||||
|
and message.text
|
||||||
|
and message.bot
|
||||||
|
):
|
||||||
|
command = message.text[1 : message.entities[0].length]
|
||||||
args = message.text.split()[1:]
|
args = message.text.split()[1:]
|
||||||
command_parts = command.split('@')
|
command_parts = command.split('@')
|
||||||
command_parts.append(message.bot.username)
|
command_parts.append(message.bot.username)
|
||||||
|
|
||||||
if not (command_parts[0].lower() in self.command
|
if not (
|
||||||
and command_parts[1].lower() == message.bot.username.lower()):
|
command_parts[0].lower() in self.command
|
||||||
|
and command_parts[1].lower() == message.bot.username.lower()
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
filter_result = self.filters(update)
|
filter_result = self.filters(update)
|
||||||
|
@ -205,22 +217,23 @@ class CommandHandler(Handler):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_optional_args(
|
def collect_optional_args(
|
||||||
self,
|
self,
|
||||||
dispatcher: 'Dispatcher',
|
dispatcher: 'Dispatcher',
|
||||||
update: HandlerArg = None,
|
update: HandlerArg = None,
|
||||||
check_result: Optional[Union[bool, Tuple[List[str],
|
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None,
|
||||||
Optional[bool]]]] = None) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update)
|
optional_args = super().collect_optional_args(dispatcher, update)
|
||||||
if self.pass_args and isinstance(check_result, tuple):
|
if self.pass_args and isinstance(check_result, tuple):
|
||||||
optional_args['args'] = check_result[0]
|
optional_args['args'] = check_result[0]
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
||||||
def collect_additional_context(
|
def collect_additional_context(
|
||||||
self,
|
self,
|
||||||
context: 'CallbackContext',
|
context: 'CallbackContext',
|
||||||
update: HandlerArg,
|
update: HandlerArg,
|
||||||
dispatcher: 'Dispatcher',
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||||
|
) -> None:
|
||||||
if isinstance(check_result, tuple):
|
if isinstance(check_result, tuple):
|
||||||
context.args = check_result[0]
|
context.args = check_result[0]
|
||||||
if isinstance(check_result[1], dict):
|
if isinstance(check_result[1], dict):
|
||||||
|
@ -330,29 +343,36 @@ class PrefixHandler(CommandHandler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
prefix: Union[str, List[str]],
|
self,
|
||||||
command: Union[str, List[str]],
|
prefix: Union[str, List[str]],
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
command: Union[str, List[str]],
|
||||||
filters: BaseFilter = None,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_args: bool = False,
|
filters: BaseFilter = None,
|
||||||
pass_update_queue: bool = False,
|
pass_args: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_job_queue: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
run_async: bool = False):
|
pass_chat_data: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
|
|
||||||
self._prefix: List[str] = list()
|
self._prefix: List[str] = list()
|
||||||
self._command: List[str] = list()
|
self._command: List[str] = list()
|
||||||
self._commands: List[str] = list()
|
self._commands: List[str] = list()
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
'nocommand', callback, filters=filters, allow_edited=None, pass_args=pass_args,
|
'nocommand',
|
||||||
|
callback,
|
||||||
|
filters=filters,
|
||||||
|
allow_edited=None,
|
||||||
|
pass_args=pass_args,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
pass_user_data=pass_user_data,
|
pass_user_data=pass_user_data,
|
||||||
pass_chat_data=pass_chat_data,
|
pass_chat_data=pass_chat_data,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
|
|
||||||
self.prefix = prefix # type: ignore[assignment]
|
self.prefix = prefix # type: ignore[assignment]
|
||||||
self.command = command # type: ignore[assignment]
|
self.command = command # type: ignore[assignment]
|
||||||
|
@ -385,8 +405,9 @@ class PrefixHandler(CommandHandler):
|
||||||
def _build_commands(self) -> None:
|
def _build_commands(self) -> None:
|
||||||
self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command]
|
self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command]
|
||||||
|
|
||||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Tuple[List[str],
|
def check_update(
|
||||||
Optional[Union[bool, Dict]]]]]:
|
self, update: HandlerArg
|
||||||
|
) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]:
|
||||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -411,11 +432,12 @@ class PrefixHandler(CommandHandler):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_additional_context(
|
def collect_additional_context(
|
||||||
self,
|
self,
|
||||||
context: 'CallbackContext',
|
context: 'CallbackContext',
|
||||||
update: HandlerArg,
|
update: HandlerArg,
|
||||||
dispatcher: 'Dispatcher',
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||||
|
) -> None:
|
||||||
if isinstance(check_result, tuple):
|
if isinstance(check_result, tuple):
|
||||||
context.args = check_result[0]
|
context.args = check_result[0]
|
||||||
if isinstance(check_result[1], dict):
|
if isinstance(check_result[1], dict):
|
||||||
|
|
|
@ -23,9 +23,15 @@ import warnings
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
|
||||||
from telegram import Update
|
from telegram import Update
|
||||||
from telegram.ext import (Handler, CallbackQueryHandler, InlineQueryHandler,
|
from telegram.ext import (
|
||||||
ChosenInlineResultHandler, CallbackContext, BasePersistence,
|
Handler,
|
||||||
DispatcherHandlerStop)
|
CallbackQueryHandler,
|
||||||
|
InlineQueryHandler,
|
||||||
|
ChosenInlineResultHandler,
|
||||||
|
CallbackContext,
|
||||||
|
BasePersistence,
|
||||||
|
DispatcherHandlerStop,
|
||||||
|
)
|
||||||
from telegram.utils.promise import Promise
|
from telegram.utils.promise import Promise
|
||||||
|
|
||||||
from telegram.utils.types import ConversationDict, HandlerArg
|
from telegram.utils.types import ConversationDict, HandlerArg
|
||||||
|
@ -37,11 +43,13 @@ CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
|
||||||
|
|
||||||
|
|
||||||
class _ConversationTimeoutContext:
|
class _ConversationTimeoutContext:
|
||||||
def __init__(self,
|
def __init__(
|
||||||
conversation_key: Tuple[int, ...],
|
self,
|
||||||
update: Update,
|
conversation_key: Tuple[int, ...],
|
||||||
dispatcher: 'Dispatcher',
|
update: Update,
|
||||||
callback_context: Optional[CallbackContext]):
|
dispatcher: 'Dispatcher',
|
||||||
|
callback_context: Optional[CallbackContext],
|
||||||
|
):
|
||||||
self.conversation_key = conversation_key
|
self.conversation_key = conversation_key
|
||||||
self.update = update
|
self.update = update
|
||||||
self.dispatcher = dispatcher
|
self.dispatcher = dispatcher
|
||||||
|
@ -160,6 +168,7 @@ class ConversationHandler(Handler):
|
||||||
ValueError
|
ValueError
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
END = -1
|
END = -1
|
||||||
""":obj:`int`: Used as a constant to return when a conversation is ended."""
|
""":obj:`int`: Used as a constant to return when a conversation is ended."""
|
||||||
TIMEOUT = -2
|
TIMEOUT = -2
|
||||||
|
@ -168,18 +177,20 @@ class ConversationHandler(Handler):
|
||||||
""":obj:`int`: Used as a constant to handle state when a conversation is still waiting on the
|
""":obj:`int`: Used as a constant to handle state when a conversation is still waiting on the
|
||||||
previous ``@run_sync`` decorated running handler to finish."""
|
previous ``@run_sync`` decorated running handler to finish."""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
entry_points: List[Handler],
|
self,
|
||||||
states: Dict[object, List[Handler]],
|
entry_points: List[Handler],
|
||||||
fallbacks: List[Handler],
|
states: Dict[object, List[Handler]],
|
||||||
allow_reentry: bool = False,
|
fallbacks: List[Handler],
|
||||||
per_chat: bool = True,
|
allow_reentry: bool = False,
|
||||||
per_user: bool = True,
|
per_chat: bool = True,
|
||||||
per_message: bool = False,
|
per_user: bool = True,
|
||||||
conversation_timeout: int = None,
|
per_message: bool = False,
|
||||||
name: str = None,
|
conversation_timeout: int = None,
|
||||||
persistent: bool = False,
|
name: str = None,
|
||||||
map_to_parent: Dict[object, object] = None):
|
persistent: bool = False,
|
||||||
|
map_to_parent: Dict[object, object] = None,
|
||||||
|
):
|
||||||
self.run_async = False
|
self.run_async = False
|
||||||
|
|
||||||
self._entry_points = entry_points
|
self._entry_points = entry_points
|
||||||
|
@ -211,8 +222,10 @@ class ConversationHandler(Handler):
|
||||||
raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'")
|
raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'")
|
||||||
|
|
||||||
if self.per_message and not self.per_chat:
|
if self.per_message and not self.per_chat:
|
||||||
warnings.warn("If 'per_message=True' is used, 'per_chat=True' should also be used, "
|
warnings.warn(
|
||||||
"since message IDs are not globally unique.")
|
"If 'per_message=True' is used, 'per_chat=True' should also be used, "
|
||||||
|
"since message IDs are not globally unique."
|
||||||
|
)
|
||||||
|
|
||||||
all_handlers = list()
|
all_handlers = list()
|
||||||
all_handlers.extend(entry_points)
|
all_handlers.extend(entry_points)
|
||||||
|
@ -224,22 +237,28 @@ class ConversationHandler(Handler):
|
||||||
if self.per_message:
|
if self.per_message:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if not isinstance(handler, CallbackQueryHandler):
|
if not isinstance(handler, CallbackQueryHandler):
|
||||||
warnings.warn("If 'per_message=True', all entry points and state handlers"
|
warnings.warn(
|
||||||
" must be 'CallbackQueryHandler', since no other handlers "
|
"If 'per_message=True', all entry points and state handlers"
|
||||||
"have a message context.")
|
" must be 'CallbackQueryHandler', since no other handlers "
|
||||||
|
"have a message context."
|
||||||
|
)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if isinstance(handler, CallbackQueryHandler):
|
if isinstance(handler, CallbackQueryHandler):
|
||||||
warnings.warn("If 'per_message=False', 'CallbackQueryHandler' will not be "
|
warnings.warn(
|
||||||
"tracked for every message.")
|
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
||||||
|
"tracked for every message."
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
if self.per_chat:
|
if self.per_chat:
|
||||||
for handler in all_handlers:
|
for handler in all_handlers:
|
||||||
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
|
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
|
||||||
warnings.warn("If 'per_chat=True', 'InlineQueryHandler' can not be used, "
|
warnings.warn(
|
||||||
"since inline queries have no chat context.")
|
"If 'per_chat=True', 'InlineQueryHandler' can not be used, "
|
||||||
|
"since inline queries have no chat context."
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -304,8 +323,9 @@ class ConversationHandler(Handler):
|
||||||
|
|
||||||
@conversation_timeout.setter
|
@conversation_timeout.setter
|
||||||
def conversation_timeout(self, value: Any) -> NoReturn:
|
def conversation_timeout(self, value: Any) -> NoReturn:
|
||||||
raise ValueError('You can not assign a new value to conversation_timeout after '
|
raise ValueError(
|
||||||
'initialization.')
|
'You can not assign a new value to conversation_timeout after ' 'initialization.'
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> Optional[str]:
|
def name(self) -> Optional[str]:
|
||||||
|
@ -362,8 +382,10 @@ class ConversationHandler(Handler):
|
||||||
key.append(user.id)
|
key.append(user.id)
|
||||||
|
|
||||||
if self.per_message:
|
if self.per_message:
|
||||||
key.append(update.callback_query.inline_message_id # type: ignore[union-attr]
|
key.append(
|
||||||
or update.callback_query.message.message_id) # type: ignore[union-attr]
|
update.callback_query.inline_message_id # type: ignore[union-attr]
|
||||||
|
or update.callback_query.message.message_id # type: ignore[union-attr]
|
||||||
|
)
|
||||||
|
|
||||||
return tuple(key)
|
return tuple(key)
|
||||||
|
|
||||||
|
@ -380,11 +402,17 @@ class ConversationHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Ignore messages in channels
|
# Ignore messages in channels
|
||||||
if (not isinstance(update, Update)
|
if (
|
||||||
or update.channel_post
|
not isinstance(update, Update)
|
||||||
or self.per_chat and not update.effective_chat
|
or update.channel_post
|
||||||
or self.per_message and not update.callback_query
|
or self.per_chat
|
||||||
or update.callback_query and self.per_chat and not update.callback_query.message):
|
and not update.effective_chat
|
||||||
|
or self.per_message
|
||||||
|
and not update.callback_query
|
||||||
|
or update.callback_query
|
||||||
|
and self.per_chat
|
||||||
|
and not update.callback_query.message
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
key = self._get_key(update)
|
key = self._get_key(update)
|
||||||
|
@ -438,7 +466,7 @@ class ConversationHandler(Handler):
|
||||||
if state is not None and not handler:
|
if state is not None and not handler:
|
||||||
handlers = self.states.get(state)
|
handlers = self.states.get(state)
|
||||||
|
|
||||||
for candidate in (handlers or []):
|
for candidate in handlers or []:
|
||||||
check = candidate.check_update(update)
|
check = candidate.check_update(update)
|
||||||
if check is not None and check is not False:
|
if check is not None and check is not False:
|
||||||
handler = candidate
|
handler = candidate
|
||||||
|
@ -457,11 +485,13 @@ class ConversationHandler(Handler):
|
||||||
|
|
||||||
return key, handler, check # type: ignore[return-value]
|
return key, handler, check # type: ignore[return-value]
|
||||||
|
|
||||||
def handle_update(self, # type: ignore[override]
|
def handle_update( # type: ignore[override]
|
||||||
update: HandlerArg,
|
self,
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: CheckUpdateType,
|
dispatcher: 'Dispatcher',
|
||||||
context: CallbackContext = None) -> Optional[object]:
|
check_result: CheckUpdateType,
|
||||||
|
context: CallbackContext = None,
|
||||||
|
) -> Optional[object]:
|
||||||
"""Send the update to the callback for the current state and Handler
|
"""Send the update to the callback for the current state and Handler
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -492,9 +522,12 @@ class ConversationHandler(Handler):
|
||||||
if self.conversation_timeout and new_state != self.END and dispatcher.job_queue:
|
if self.conversation_timeout and new_state != self.END and dispatcher.job_queue:
|
||||||
# Add the new timeout job
|
# Add the new timeout job
|
||||||
self.timeout_jobs[conversation_key] = dispatcher.job_queue.run_once(
|
self.timeout_jobs[conversation_key] = dispatcher.job_queue.run_once(
|
||||||
self._trigger_timeout, self.conversation_timeout, # type: ignore[arg-type]
|
self._trigger_timeout, # type: ignore[arg-type]
|
||||||
context=_ConversationTimeoutContext(conversation_key, update,
|
self.conversation_timeout,
|
||||||
dispatcher, context))
|
context=_ConversationTimeoutContext(
|
||||||
|
conversation_key, update, dispatcher, context
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
||||||
self.update_state(self.END, conversation_key)
|
self.update_state(self.END, conversation_key)
|
||||||
|
@ -510,9 +543,7 @@ class ConversationHandler(Handler):
|
||||||
raise DispatcherHandlerStop()
|
raise DispatcherHandlerStop()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def update_state(self,
|
def update_state(self, new_state: object, key: Tuple[int, ...]) -> None:
|
||||||
new_state: object,
|
|
||||||
key: Tuple[int, ...]) -> None:
|
|
||||||
if new_state == self.END:
|
if new_state == self.END:
|
||||||
with self._conversations_lock:
|
with self._conversations_lock:
|
||||||
if key in self.conversations:
|
if key in self.conversations:
|
||||||
|
@ -525,8 +556,9 @@ class ConversationHandler(Handler):
|
||||||
with self._conversations_lock:
|
with self._conversations_lock:
|
||||||
self.conversations[key] = (self.conversations.get(key), new_state)
|
self.conversations[key] = (self.conversations.get(key), new_state)
|
||||||
if self.persistent and self.persistence and self.name:
|
if self.persistent and self.persistence and self.name:
|
||||||
self.persistence.update_conversation(self.name, key,
|
self.persistence.update_conversation(
|
||||||
(self.conversations.get(key), new_state))
|
self.name, key, (self.conversations.get(key), new_state)
|
||||||
|
)
|
||||||
|
|
||||||
elif new_state is not None:
|
elif new_state is not None:
|
||||||
with self._conversations_lock:
|
with self._conversations_lock:
|
||||||
|
@ -534,9 +566,7 @@ class ConversationHandler(Handler):
|
||||||
if self.persistent and self.persistence and self.name:
|
if self.persistent and self.persistence and self.name:
|
||||||
self.persistence.update_conversation(self.name, key, new_state)
|
self.persistence.update_conversation(self.name, key, new_state)
|
||||||
|
|
||||||
def _trigger_timeout(self,
|
def _trigger_timeout(self, context: _ConversationTimeoutContext, job: 'Job' = None) -> None:
|
||||||
context: _ConversationTimeoutContext,
|
|
||||||
job: 'Job' = None) -> None:
|
|
||||||
self.logger.debug('conversation timeout was triggered!')
|
self.logger.debug('conversation timeout was triggered!')
|
||||||
|
|
||||||
# Backward compatibility with bots that do not use CallbackContext
|
# Backward compatibility with bots that do not use CallbackContext
|
||||||
|
@ -559,9 +589,12 @@ class ConversationHandler(Handler):
|
||||||
check = handler.check_update(context.update)
|
check = handler.check_update(context.update)
|
||||||
if check is not None and check is not False:
|
if check is not None and check is not False:
|
||||||
try:
|
try:
|
||||||
handler.handle_update(context.update, context.dispatcher, check,
|
handler.handle_update(
|
||||||
callback_context)
|
context.update, context.dispatcher, check, callback_context
|
||||||
|
)
|
||||||
except DispatcherHandlerStop:
|
except DispatcherHandlerStop:
|
||||||
self.logger.warning('DispatcherHandlerStop in TIMEOUT state of '
|
self.logger.warning(
|
||||||
'ConversationHandler has no effect. Ignoring.')
|
'DispatcherHandlerStop in TIMEOUT state of '
|
||||||
|
'ConversationHandler has no effect. Ignoring.'
|
||||||
|
)
|
||||||
self.update_state(self.END, context.conversation_key)
|
self.update_state(self.END, context.conversation_key)
|
||||||
|
|
|
@ -60,15 +60,18 @@ class Defaults:
|
||||||
somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the
|
somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the
|
||||||
``pytz`` module. Defaults to UTC.
|
``pytz`` module. Defaults to UTC.
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
parse_mode: str = None,
|
def __init__(
|
||||||
disable_notification: bool = None,
|
self,
|
||||||
disable_web_page_preview: bool = None,
|
parse_mode: str = None,
|
||||||
# Timeout needs special treatment, since the bot methods have two different
|
disable_notification: bool = None,
|
||||||
# default values for timeout (None and 20s)
|
disable_web_page_preview: bool = None,
|
||||||
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
# Timeout needs special treatment, since the bot methods have two different
|
||||||
quote: bool = None,
|
# default values for timeout (None and 20s)
|
||||||
tzinfo: pytz.BaseTzInfo = pytz.utc):
|
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
||||||
|
quote: bool = None,
|
||||||
|
tzinfo: pytz.BaseTzInfo = pytz.utc,
|
||||||
|
):
|
||||||
self._parse_mode = parse_mode
|
self._parse_mode = parse_mode
|
||||||
self._disable_notification = disable_notification
|
self._disable_notification = disable_notification
|
||||||
self._disable_web_page_preview = disable_web_page_preview
|
self._disable_web_page_preview = disable_web_page_preview
|
||||||
|
@ -82,8 +85,10 @@ class Defaults:
|
||||||
|
|
||||||
@parse_mode.setter
|
@parse_mode.setter
|
||||||
def parse_mode(self, value: Any) -> NoReturn:
|
def parse_mode(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def disable_notification(self) -> Optional[bool]:
|
def disable_notification(self) -> Optional[bool]:
|
||||||
|
@ -91,8 +96,10 @@ class Defaults:
|
||||||
|
|
||||||
@disable_notification.setter
|
@disable_notification.setter
|
||||||
def disable_notification(self, value: Any) -> NoReturn:
|
def disable_notification(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def disable_web_page_preview(self) -> Optional[bool]:
|
def disable_web_page_preview(self) -> Optional[bool]:
|
||||||
|
@ -100,8 +107,10 @@ class Defaults:
|
||||||
|
|
||||||
@disable_web_page_preview.setter
|
@disable_web_page_preview.setter
|
||||||
def disable_web_page_preview(self, value: Any) -> NoReturn:
|
def disable_web_page_preview(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def timeout(self) -> Union[float, DefaultValue]:
|
def timeout(self) -> Union[float, DefaultValue]:
|
||||||
|
@ -109,8 +118,10 @@ class Defaults:
|
||||||
|
|
||||||
@timeout.setter
|
@timeout.setter
|
||||||
def timeout(self, value: Any) -> NoReturn:
|
def timeout(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def quote(self) -> Optional[bool]:
|
def quote(self) -> Optional[bool]:
|
||||||
|
@ -118,8 +129,10 @@ class Defaults:
|
||||||
|
|
||||||
@quote.setter
|
@quote.setter
|
||||||
def quote(self, value: Any) -> NoReturn:
|
def quote(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tzinfo(self) -> pytz.BaseTzInfo:
|
def tzinfo(self) -> pytz.BaseTzInfo:
|
||||||
|
@ -127,16 +140,22 @@ class Defaults:
|
||||||
|
|
||||||
@tzinfo.setter
|
@tzinfo.setter
|
||||||
def tzinfo(self, value: Any) -> NoReturn:
|
def tzinfo(self, value: Any) -> NoReturn:
|
||||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
raise AttributeError(
|
||||||
"not have any effect.")
|
"You can not assign a new value to defaults after because it would "
|
||||||
|
"not have any effect."
|
||||||
|
)
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return hash((self._parse_mode,
|
return hash(
|
||||||
self._disable_notification,
|
(
|
||||||
self._disable_web_page_preview,
|
self._parse_mode,
|
||||||
self._timeout,
|
self._disable_notification,
|
||||||
self._quote,
|
self._disable_web_page_preview,
|
||||||
self._tzinfo))
|
self._timeout,
|
||||||
|
self._quote,
|
||||||
|
self._tzinfo,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def __eq__(self, other: object) -> bool:
|
def __eq__(self, other: object) -> bool:
|
||||||
if isinstance(other, Defaults):
|
if isinstance(other, Defaults):
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
"""This module contains the DictPersistence class."""
|
"""This module contains the DictPersistence class."""
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from telegram.utils.helpers import decode_user_chat_data_from_json,\
|
from telegram.utils.helpers import (
|
||||||
decode_conversations_from_json, encode_conversations_to_json
|
decode_user_chat_data_from_json,
|
||||||
|
decode_conversations_from_json,
|
||||||
|
encode_conversations_to_json,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
@ -76,17 +79,21 @@ class DictPersistence(BasePersistence):
|
||||||
conversation on creating this persistence. Default is ``""``.
|
conversation on creating this persistence. Default is ``""``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
store_user_data: bool = True,
|
self,
|
||||||
store_chat_data: bool = True,
|
store_user_data: bool = True,
|
||||||
store_bot_data: bool = True,
|
store_chat_data: bool = True,
|
||||||
user_data_json: str = '',
|
store_bot_data: bool = True,
|
||||||
chat_data_json: str = '',
|
user_data_json: str = '',
|
||||||
bot_data_json: str = '',
|
chat_data_json: str = '',
|
||||||
conversations_json: str = ''):
|
bot_data_json: str = '',
|
||||||
super().__init__(store_user_data=store_user_data,
|
conversations_json: str = '',
|
||||||
store_chat_data=store_chat_data,
|
):
|
||||||
store_bot_data=store_bot_data)
|
super().__init__(
|
||||||
|
store_user_data=store_user_data,
|
||||||
|
store_chat_data=store_chat_data,
|
||||||
|
store_bot_data=store_bot_data,
|
||||||
|
)
|
||||||
self._user_data = None
|
self._user_data = None
|
||||||
self._chat_data = None
|
self._chat_data = None
|
||||||
self._bot_data = None
|
self._bot_data = None
|
||||||
|
@ -226,9 +233,9 @@ class DictPersistence(BasePersistence):
|
||||||
self._conversations = {}
|
self._conversations = {}
|
||||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||||
|
|
||||||
def update_conversation(self,
|
def update_conversation(
|
||||||
name: str, key: Tuple[int, ...],
|
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||||
new_state: Optional[object]) -> None:
|
) -> None:
|
||||||
"""Will update the conversations for the given handler.
|
"""Will update the conversations for the given handler.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
|
@ -47,8 +47,9 @@ if TYPE_CHECKING:
|
||||||
DEFAULT_GROUP = 0
|
DEFAULT_GROUP = 0
|
||||||
|
|
||||||
|
|
||||||
def run_async(func: Callable[[Update, CallbackContext],
|
def run_async(
|
||||||
Any]) -> Callable[[Update, CallbackContext], Any]:
|
func: Callable[[Update, CallbackContext], Any]
|
||||||
|
) -> Callable[[Update, CallbackContext], Any]:
|
||||||
"""
|
"""
|
||||||
Function decorator that will run the function in a new thread.
|
Function decorator that will run the function in a new thread.
|
||||||
|
|
||||||
|
@ -67,12 +68,15 @@ def run_async(func: Callable[[Update, CallbackContext],
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def async_func(*args: Any, **kwargs: Any) -> Any:
|
def async_func(*args: Any, **kwargs: Any) -> Any:
|
||||||
warnings.warn('The @run_async decorator is deprecated. Use the `run_async` parameter of'
|
warnings.warn(
|
||||||
'`Dispatcher.add_handler` or `Dispatcher.run_async` instead.',
|
'The @run_async decorator is deprecated. Use the `run_async` parameter of'
|
||||||
TelegramDeprecationWarning,
|
'`Dispatcher.add_handler` or `Dispatcher.run_async` instead.',
|
||||||
stacklevel=2)
|
TelegramDeprecationWarning,
|
||||||
return Dispatcher.get_instance()._run_async(func, *args, update=None, error_handling=False,
|
stacklevel=2,
|
||||||
**kwargs)
|
)
|
||||||
|
return Dispatcher.get_instance()._run_async(
|
||||||
|
func, *args, update=None, error_handling=False, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
return async_func
|
return async_func
|
||||||
|
|
||||||
|
@ -96,6 +100,7 @@ class DispatcherHandlerStop(Exception):
|
||||||
Args:
|
Args:
|
||||||
state (:obj:`object`, optional): The next state of the conversation.
|
state (:obj:`object`, optional): The next state of the conversation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, state: object = None) -> None:
|
def __init__(self, state: object = None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.state = state
|
self.state = state
|
||||||
|
@ -137,14 +142,16 @@ class Dispatcher:
|
||||||
__singleton = None
|
__singleton = None
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
bot: 'Bot',
|
self,
|
||||||
update_queue: Queue,
|
bot: 'Bot',
|
||||||
workers: int = 4,
|
update_queue: Queue,
|
||||||
exception_event: Event = None,
|
workers: int = 4,
|
||||||
job_queue: 'JobQueue' = None,
|
exception_event: Event = None,
|
||||||
persistence: BasePersistence = None,
|
job_queue: 'JobQueue' = None,
|
||||||
use_context: bool = True):
|
persistence: BasePersistence = None,
|
||||||
|
use_context: bool = True,
|
||||||
|
):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.update_queue = update_queue
|
self.update_queue = update_queue
|
||||||
self.job_queue = job_queue
|
self.job_queue = job_queue
|
||||||
|
@ -152,8 +159,11 @@ class Dispatcher:
|
||||||
self.use_context = use_context
|
self.use_context = use_context
|
||||||
|
|
||||||
if not use_context:
|
if not use_context:
|
||||||
warnings.warn('Old Handler API is deprecated - see https://git.io/fxJuV for details',
|
warnings.warn(
|
||||||
TelegramDeprecationWarning, stacklevel=3)
|
'Old Handler API is deprecated - see https://git.io/fxJuV for details',
|
||||||
|
TelegramDeprecationWarning,
|
||||||
|
stacklevel=3,
|
||||||
|
)
|
||||||
|
|
||||||
self.user_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
self.user_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||||
self.chat_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
self.chat_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||||
|
@ -211,8 +221,9 @@ class Dispatcher:
|
||||||
base_name = '{}_'.format(base_name) if base_name else ''
|
base_name = '{}_'.format(base_name) if base_name else ''
|
||||||
|
|
||||||
for i in range(workers):
|
for i in range(workers):
|
||||||
thread = Thread(target=self._pooled, name='Bot:{}:worker:{}{}'.format(self.bot.id,
|
thread = Thread(
|
||||||
base_name, i))
|
target=self._pooled, name='Bot:{}:worker:{}{}'.format(self.bot.id, base_name, i)
|
||||||
|
)
|
||||||
self.__async_threads.add(thread)
|
self.__async_threads.add(thread)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
@ -235,8 +246,9 @@ class Dispatcher:
|
||||||
if cls.__singleton is not None:
|
if cls.__singleton is not None:
|
||||||
return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable
|
return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('{} not initialized or multiple instances exist'.format(
|
raise RuntimeError(
|
||||||
cls.__name__))
|
'{} not initialized or multiple instances exist'.format(cls.__name__)
|
||||||
|
)
|
||||||
|
|
||||||
def _pooled(self) -> None:
|
def _pooled(self) -> None:
|
||||||
thr_name = current_thread().getName()
|
thr_name = current_thread().getName()
|
||||||
|
@ -245,8 +257,9 @@ class Dispatcher:
|
||||||
|
|
||||||
# If unpacking fails, the thread pool is being closed from Updater._join_async_threads
|
# If unpacking fails, the thread pool is being closed from Updater._join_async_threads
|
||||||
if not isinstance(promise, Promise):
|
if not isinstance(promise, Promise):
|
||||||
self.logger.debug("Closing run_async thread %s/%d", thr_name,
|
self.logger.debug(
|
||||||
len(self.__async_threads))
|
"Closing run_async thread %s/%d", thr_name, len(self.__async_threads)
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
promise.run()
|
promise.run()
|
||||||
|
@ -258,7 +271,8 @@ class Dispatcher:
|
||||||
if isinstance(promise.exception, DispatcherHandlerStop):
|
if isinstance(promise.exception, DispatcherHandlerStop):
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'DispatcherHandlerStop is not supported with async functions; func: %s',
|
'DispatcherHandlerStop is not supported with async functions; func: %s',
|
||||||
promise.pooled_function.__name__)
|
promise.pooled_function.__name__,
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Avoid infinite recursion of error handlers.
|
# Avoid infinite recursion of error handlers.
|
||||||
|
@ -280,11 +294,9 @@ class Dispatcher:
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||||
|
|
||||||
def run_async(self,
|
def run_async(
|
||||||
func: Callable[..., Any],
|
self, func: Callable[..., Any], *args: Any, update: HandlerArg = None, **kwargs: Any
|
||||||
*args: Any,
|
) -> Promise:
|
||||||
update: HandlerArg = None,
|
|
||||||
**kwargs: Any) -> Promise:
|
|
||||||
"""
|
"""
|
||||||
Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised
|
Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised
|
||||||
by the function will be handled by the error handlers registered with
|
by the function will be handled by the error handlers registered with
|
||||||
|
@ -310,12 +322,14 @@ class Dispatcher:
|
||||||
"""
|
"""
|
||||||
return self._run_async(func, *args, update=update, error_handling=True, **kwargs)
|
return self._run_async(func, *args, update=update, error_handling=True, **kwargs)
|
||||||
|
|
||||||
def _run_async(self,
|
def _run_async(
|
||||||
func: Callable[..., Any],
|
self,
|
||||||
*args: Any,
|
func: Callable[..., Any],
|
||||||
update: HandlerArg = None,
|
*args: Any,
|
||||||
error_handling: bool = True,
|
update: HandlerArg = None,
|
||||||
**kwargs: Any) -> Promise:
|
error_handling: bool = True,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> Promise:
|
||||||
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
||||||
promise = Promise(func, args, kwargs, update=update, error_handling=error_handling)
|
promise = Promise(func, args, kwargs, update=update, error_handling=error_handling)
|
||||||
self.__async_queue.put(promise)
|
self.__async_queue.put(promise)
|
||||||
|
@ -482,7 +496,8 @@ class Dispatcher:
|
||||||
if not self.persistence:
|
if not self.persistence:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"ConversationHandler {} can not be persistent if dispatcher has no "
|
"ConversationHandler {} can not be persistent if dispatcher has no "
|
||||||
"persistence".format(handler.name))
|
"persistence".format(handler.name)
|
||||||
|
)
|
||||||
handler.persistence = self.persistence
|
handler.persistence = self.persistence
|
||||||
handler.conversations = self.persistence.get_conversations(handler.name)
|
handler.conversations = self.persistence.get_conversations(handler.name)
|
||||||
|
|
||||||
|
@ -541,9 +556,11 @@ class Dispatcher:
|
||||||
try:
|
try:
|
||||||
self.dispatch_error(update, e)
|
self.dispatch_error(update, e)
|
||||||
except Exception:
|
except Exception:
|
||||||
message = 'Saving bot data raised an error and an ' \
|
message = (
|
||||||
'uncaught error was raised while handling ' \
|
'Saving bot data raised an error and an '
|
||||||
'the error with an error_handler'
|
'uncaught error was raised while handling '
|
||||||
|
'the error with an error_handler'
|
||||||
|
)
|
||||||
self.logger.exception(message)
|
self.logger.exception(message)
|
||||||
if self.persistence.store_chat_data:
|
if self.persistence.store_chat_data:
|
||||||
for chat_id in chat_ids:
|
for chat_id in chat_ids:
|
||||||
|
@ -553,9 +570,11 @@ class Dispatcher:
|
||||||
try:
|
try:
|
||||||
self.dispatch_error(update, e)
|
self.dispatch_error(update, e)
|
||||||
except Exception:
|
except Exception:
|
||||||
message = 'Saving chat data raised an error and an ' \
|
message = (
|
||||||
'uncaught error was raised while handling ' \
|
'Saving chat data raised an error and an '
|
||||||
'the error with an error_handler'
|
'uncaught error was raised while handling '
|
||||||
|
'the error with an error_handler'
|
||||||
|
)
|
||||||
self.logger.exception(message)
|
self.logger.exception(message)
|
||||||
if self.persistence.store_user_data:
|
if self.persistence.store_user_data:
|
||||||
for user_id in user_ids:
|
for user_id in user_ids:
|
||||||
|
@ -565,14 +584,16 @@ class Dispatcher:
|
||||||
try:
|
try:
|
||||||
self.dispatch_error(update, e)
|
self.dispatch_error(update, e)
|
||||||
except Exception:
|
except Exception:
|
||||||
message = 'Saving user data raised an error and an ' \
|
message = (
|
||||||
'uncaught error was raised while handling ' \
|
'Saving user data raised an error and an '
|
||||||
'the error with an error_handler'
|
'uncaught error was raised while handling '
|
||||||
|
'the error with an error_handler'
|
||||||
|
)
|
||||||
self.logger.exception(message)
|
self.logger.exception(message)
|
||||||
|
|
||||||
def add_error_handler(self,
|
def add_error_handler(
|
||||||
callback: Callable[[Any, CallbackContext], None],
|
self, callback: Callable[[Any, CallbackContext], None], run_async: bool = False
|
||||||
run_async: bool = False) -> None:
|
) -> None:
|
||||||
"""Registers an error handler in the Dispatcher. This handler will receive every error
|
"""Registers an error handler in the Dispatcher. This handler will receive every error
|
||||||
which happens in your bot.
|
which happens in your bot.
|
||||||
|
|
||||||
|
@ -610,10 +631,9 @@ class Dispatcher:
|
||||||
"""
|
"""
|
||||||
self.error_handlers.pop(callback, None)
|
self.error_handlers.pop(callback, None)
|
||||||
|
|
||||||
def dispatch_error(self,
|
def dispatch_error(
|
||||||
update: Optional[HandlerArg],
|
self, update: Optional[HandlerArg], error: Exception, promise: Promise = None
|
||||||
error: Exception,
|
) -> None:
|
||||||
promise: Promise = None) -> None:
|
|
||||||
"""Dispatches an error.
|
"""Dispatches an error.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -629,9 +649,9 @@ class Dispatcher:
|
||||||
if self.error_handlers:
|
if self.error_handlers:
|
||||||
for callback, run_async in self.error_handlers.items():
|
for callback, run_async in self.error_handlers.items():
|
||||||
if self.use_context:
|
if self.use_context:
|
||||||
context = CallbackContext.from_error(update, error, self,
|
context = CallbackContext.from_error(
|
||||||
async_args=async_args,
|
update, error, self, async_args=async_args, async_kwargs=async_kwargs
|
||||||
async_kwargs=async_kwargs)
|
)
|
||||||
if run_async:
|
if run_async:
|
||||||
self.run_async(callback, update, context, update=update)
|
self.run_async(callback, update, context, update=update)
|
||||||
else:
|
else:
|
||||||
|
@ -644,4 +664,5 @@ class Dispatcher:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.logger.exception(
|
self.logger.exception(
|
||||||
'No error handlers are registered, logging exception.', exc_info=error)
|
'No error handlers are registered, logging exception.', exc_info=error
|
||||||
|
)
|
||||||
|
|
|
@ -27,8 +27,14 @@ from telegram import Chat, Update, MessageEntity, Message
|
||||||
|
|
||||||
from typing import Optional, Dict, Union, List, Pattern, Match, cast, Set, FrozenSet
|
from typing import Optional, Dict, Union, List, Pattern, Match, cast, Set, FrozenSet
|
||||||
|
|
||||||
__all__ = ['Filters', 'BaseFilter', 'MessageFilter', 'UpdateFilter', 'InvertedFilter',
|
__all__ = [
|
||||||
'MergedFilter']
|
'Filters',
|
||||||
|
'BaseFilter',
|
||||||
|
'MessageFilter',
|
||||||
|
'UpdateFilter',
|
||||||
|
'InvertedFilter',
|
||||||
|
'MergedFilter',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class BaseFilter(ABC):
|
class BaseFilter(ABC):
|
||||||
|
@ -120,6 +126,7 @@ class MessageFilter(BaseFilter, ABC):
|
||||||
(depends on the handler).
|
(depends on the handler).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||||
return self.filter(update.effective_message)
|
return self.filter(update.effective_message)
|
||||||
|
|
||||||
|
@ -151,12 +158,12 @@ class UpdateFilter(BaseFilter, ABC):
|
||||||
(depends on the handler).
|
(depends on the handler).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||||
return self.filter(update)
|
return self.filter(update)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def filter(self,
|
def filter(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||||
update: Update) -> Optional[Union[bool, Dict]]:
|
|
||||||
"""This method must be overwritten.
|
"""This method must be overwritten.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -175,6 +182,7 @@ class InvertedFilter(UpdateFilter):
|
||||||
f: The filter to invert.
|
f: The filter to invert.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, f: BaseFilter):
|
def __init__(self, f: BaseFilter):
|
||||||
self.f = f
|
self.f = f
|
||||||
|
|
||||||
|
@ -194,22 +202,22 @@ class MergedFilter(UpdateFilter):
|
||||||
or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter.
|
or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
base_filter: BaseFilter,
|
def __init__(
|
||||||
and_filter: BaseFilter = None,
|
self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None
|
||||||
or_filter: BaseFilter = None):
|
):
|
||||||
self.base_filter = base_filter
|
self.base_filter = base_filter
|
||||||
if self.base_filter.data_filter:
|
if self.base_filter.data_filter:
|
||||||
self.data_filter = True
|
self.data_filter = True
|
||||||
self.and_filter = and_filter
|
self.and_filter = and_filter
|
||||||
if (self.and_filter
|
if (
|
||||||
and not isinstance(self.and_filter, bool)
|
self.and_filter
|
||||||
and self.and_filter.data_filter):
|
and not isinstance(self.and_filter, bool)
|
||||||
|
and self.and_filter.data_filter
|
||||||
|
):
|
||||||
self.data_filter = True
|
self.data_filter = True
|
||||||
self.or_filter = or_filter
|
self.or_filter = or_filter
|
||||||
if (self.or_filter
|
if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter:
|
||||||
and not isinstance(self.and_filter, bool)
|
|
||||||
and self.or_filter.data_filter):
|
|
||||||
self.data_filter = True
|
self.data_filter = True
|
||||||
|
|
||||||
def _merge(self, base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> Dict:
|
def _merge(self, base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> Dict:
|
||||||
|
@ -257,18 +265,17 @@ class MergedFilter(UpdateFilter):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return "<{} {} {}>".format(self.base_filter, "and" if self.and_filter else "or",
|
return "<{} {} {}>".format(
|
||||||
self.and_filter or self.or_filter)
|
self.base_filter, "and" if self.and_filter else "or", self.and_filter or self.or_filter
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class _DiceEmoji(MessageFilter):
|
class _DiceEmoji(MessageFilter):
|
||||||
|
|
||||||
def __init__(self, emoji: str = None, name: str = None):
|
def __init__(self, emoji: str = None, name: str = None):
|
||||||
self.name = 'Filters.dice.{}'.format(name) if name else 'Filters.dice'
|
self.name = 'Filters.dice.{}'.format(name) if name else 'Filters.dice'
|
||||||
self.emoji = emoji
|
self.emoji = emoji
|
||||||
|
|
||||||
class _DiceValues(MessageFilter):
|
class _DiceValues(MessageFilter):
|
||||||
|
|
||||||
def __init__(self, values: Union[int, List[int]], name: str, emoji: str = None):
|
def __init__(self, values: Union[int, List[int]], name: str, emoji: str = None):
|
||||||
self.values = [values] if isinstance(values, int) else values
|
self.values = [values] if isinstance(values, int) else values
|
||||||
self.emoji = emoji
|
self.emoji = emoji
|
||||||
|
@ -281,8 +288,9 @@ class _DiceEmoji(MessageFilter):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __call__(self, # type: ignore[override]
|
def __call__( # type: ignore[override]
|
||||||
update: Union[Update, List[int]]) -> Union[bool, '_DiceValues']:
|
self, update: Union[Update, List[int]]
|
||||||
|
) -> Union[bool, '_DiceValues']:
|
||||||
if isinstance(update, Update):
|
if isinstance(update, Update):
|
||||||
return self.filter(update.effective_message)
|
return self.filter(update.effective_message)
|
||||||
else:
|
else:
|
||||||
|
@ -319,7 +327,6 @@ class Filters:
|
||||||
name = 'Filters.text'
|
name = 'Filters.text'
|
||||||
|
|
||||||
class _TextStrings(MessageFilter):
|
class _TextStrings(MessageFilter):
|
||||||
|
|
||||||
def __init__(self, strings: List[str]):
|
def __init__(self, strings: List[str]):
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.name = 'Filters.text({})'.format(strings)
|
self.name = 'Filters.text({})'.format(strings)
|
||||||
|
@ -329,8 +336,9 @@ class Filters:
|
||||||
return message.text in self.strings
|
return message.text in self.strings
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __call__(self, # type: ignore[override]
|
def __call__( # type: ignore[override]
|
||||||
update: Union[Update, List[str]]) -> Union[bool, '_TextStrings']:
|
self, update: Union[Update, List[str]]
|
||||||
|
) -> Union[bool, '_TextStrings']:
|
||||||
if isinstance(update, Update):
|
if isinstance(update, Update):
|
||||||
return self.filter(update.effective_message)
|
return self.filter(update.effective_message)
|
||||||
else:
|
else:
|
||||||
|
@ -371,7 +379,6 @@ class Filters:
|
||||||
name = 'Filters.caption'
|
name = 'Filters.caption'
|
||||||
|
|
||||||
class _CaptionStrings(MessageFilter):
|
class _CaptionStrings(MessageFilter):
|
||||||
|
|
||||||
def __init__(self, strings: List[str]):
|
def __init__(self, strings: List[str]):
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.name = 'Filters.caption({})'.format(strings)
|
self.name = 'Filters.caption({})'.format(strings)
|
||||||
|
@ -381,8 +388,9 @@ class Filters:
|
||||||
return message.caption in self.strings
|
return message.caption in self.strings
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __call__(self, # type: ignore[override]
|
def __call__( # type: ignore[override]
|
||||||
update: Union[Update, List[str]]) -> Union[bool, '_CaptionStrings']:
|
self, update: Union[Update, List[str]]
|
||||||
|
) -> Union[bool, '_CaptionStrings']:
|
||||||
if isinstance(update, Update):
|
if isinstance(update, Update):
|
||||||
return self.filter(update.effective_message)
|
return self.filter(update.effective_message)
|
||||||
else:
|
else:
|
||||||
|
@ -407,26 +415,30 @@ class Filters:
|
||||||
name = 'Filters.command'
|
name = 'Filters.command'
|
||||||
|
|
||||||
class _CommandOnlyStart(MessageFilter):
|
class _CommandOnlyStart(MessageFilter):
|
||||||
|
|
||||||
def __init__(self, only_start: bool):
|
def __init__(self, only_start: bool):
|
||||||
self.only_start = only_start
|
self.only_start = only_start
|
||||||
self.name = 'Filters.command({})'.format(only_start)
|
self.name = 'Filters.command({})'.format(only_start)
|
||||||
|
|
||||||
def filter(self, message: Message) -> bool:
|
def filter(self, message: Message) -> bool:
|
||||||
return bool(message.entities
|
return bool(
|
||||||
and any([e.type == MessageEntity.BOT_COMMAND
|
message.entities
|
||||||
for e in message.entities]))
|
and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities])
|
||||||
|
)
|
||||||
|
|
||||||
def __call__(self, # type: ignore[override]
|
def __call__( # type: ignore[override]
|
||||||
update: Union[bool, Update]) -> Union[bool, '_CommandOnlyStart']:
|
self, update: Union[bool, Update]
|
||||||
|
) -> Union[bool, '_CommandOnlyStart']:
|
||||||
if isinstance(update, Update):
|
if isinstance(update, Update):
|
||||||
return self.filter(update.effective_message)
|
return self.filter(update.effective_message)
|
||||||
else:
|
else:
|
||||||
return self._CommandOnlyStart(update)
|
return self._CommandOnlyStart(update)
|
||||||
|
|
||||||
def filter(self, message: Message) -> bool:
|
def filter(self, message: Message) -> bool:
|
||||||
return bool(message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
|
return bool(
|
||||||
and message.entities[0].offset == 0)
|
message.entities
|
||||||
|
and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||||
|
and message.entities[0].offset == 0
|
||||||
|
)
|
||||||
|
|
||||||
command = _Command()
|
command = _Command()
|
||||||
"""
|
"""
|
||||||
|
@ -485,8 +497,7 @@ class Filters:
|
||||||
self.pattern: Pattern = pattern
|
self.pattern: Pattern = pattern
|
||||||
self.name = 'Filters.regex({})'.format(self.pattern)
|
self.name = 'Filters.regex({})'.format(self.pattern)
|
||||||
|
|
||||||
def filter(self,
|
def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]:
|
||||||
message: Message) -> Optional[Dict[str, List[Match]]]:
|
|
||||||
"""""" # remove method from docs
|
"""""" # remove method from docs
|
||||||
if message.text:
|
if message.text:
|
||||||
match = self.pattern.search(message.text)
|
match = self.pattern.search(message.text)
|
||||||
|
@ -739,6 +750,7 @@ officedocument.wordprocessingml.document")``-
|
||||||
``Filters.status_update`` for all status update messages.
|
``Filters.status_update`` for all status update messages.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class _NewChatMembers(MessageFilter):
|
class _NewChatMembers(MessageFilter):
|
||||||
name = 'Filters.status_update.new_chat_members'
|
name = 'Filters.status_update.new_chat_members'
|
||||||
|
|
||||||
|
@ -788,8 +800,11 @@ officedocument.wordprocessingml.document")``-
|
||||||
name = 'Filters.status_update.chat_created'
|
name = 'Filters.status_update.chat_created'
|
||||||
|
|
||||||
def filter(self, message: Message) -> bool:
|
def filter(self, message: Message) -> bool:
|
||||||
return bool(message.group_chat_created or message.supergroup_chat_created
|
return bool(
|
||||||
or message.channel_chat_created)
|
message.group_chat_created
|
||||||
|
or message.supergroup_chat_created
|
||||||
|
or message.channel_chat_created
|
||||||
|
)
|
||||||
|
|
||||||
chat_created = _ChatCreated()
|
chat_created = _ChatCreated()
|
||||||
"""Messages that contain :attr:`telegram.Message.group_chat_created`,
|
"""Messages that contain :attr:`telegram.Message.group_chat_created`,
|
||||||
|
@ -827,11 +842,17 @@ officedocument.wordprocessingml.document")``-
|
||||||
name = 'Filters.status_update'
|
name = 'Filters.status_update'
|
||||||
|
|
||||||
def filter(self, message: Update) -> bool:
|
def filter(self, message: Update) -> bool:
|
||||||
return bool(self.new_chat_members(message) or self.left_chat_member(message)
|
return bool(
|
||||||
or self.new_chat_title(message) or self.new_chat_photo(message)
|
self.new_chat_members(message)
|
||||||
or self.delete_chat_photo(message) or self.chat_created(message)
|
or self.left_chat_member(message)
|
||||||
or self.migrate(message) or self.pinned_message(message)
|
or self.new_chat_title(message)
|
||||||
or self.connected_website(message))
|
or self.new_chat_photo(message)
|
||||||
|
or self.delete_chat_photo(message)
|
||||||
|
or self.chat_created(message)
|
||||||
|
or self.migrate(message)
|
||||||
|
or self.pinned_message(message)
|
||||||
|
or self.connected_website(message)
|
||||||
|
)
|
||||||
|
|
||||||
status_update = _StatusUpdate()
|
status_update = _StatusUpdate()
|
||||||
"""Subset for messages containing a status update.
|
"""Subset for messages containing a status update.
|
||||||
|
@ -976,10 +997,13 @@ officedocument.wordprocessingml.document")``-
|
||||||
RuntimeError: If user_id and username are both present.
|
RuntimeError: If user_id and username are both present.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
user_id: Union[int, List[int]] = None,
|
def __init__(
|
||||||
username: Union[str, List[str]] = None,
|
self,
|
||||||
allow_empty: bool = False):
|
user_id: Union[int, List[int]] = None,
|
||||||
|
username: Union[str, List[str]] = None,
|
||||||
|
allow_empty: bool = False,
|
||||||
|
):
|
||||||
self.allow_empty = allow_empty
|
self.allow_empty = allow_empty
|
||||||
self.__lock = Lock()
|
self.__lock = Lock()
|
||||||
|
|
||||||
|
@ -1008,15 +1032,17 @@ officedocument.wordprocessingml.document")``-
|
||||||
def _set_user_ids(self, user_id: Union[int, List[int]]) -> None:
|
def _set_user_ids(self, user_id: Union[int, List[int]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if user_id and self._usernames:
|
if user_id and self._usernames:
|
||||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
self._user_ids = self._parse_user_id(user_id)
|
self._user_ids = self._parse_user_id(user_id)
|
||||||
|
|
||||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if username and self._user_ids:
|
if username and self._user_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"user_ids.")
|
"Can't set username in conjunction with (already set) " "user_ids."
|
||||||
|
)
|
||||||
self._usernames = self._parse_username(username)
|
self._usernames = self._parse_username(username)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1047,8 +1073,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._user_ids:
|
if self._user_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"user_ids.")
|
"Can't set username in conjunction with (already set) " "user_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames |= parsed_username
|
self._usernames |= parsed_username
|
||||||
|
@ -1063,8 +1090,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_user_id = self._parse_user_id(user_id)
|
parsed_user_id = self._parse_user_id(user_id)
|
||||||
|
|
||||||
|
@ -1080,8 +1108,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._user_ids:
|
if self._user_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"user_ids.")
|
"Can't set username in conjunction with (already set) " "user_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames -= parsed_username
|
self._usernames -= parsed_username
|
||||||
|
@ -1096,8 +1125,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
parsed_user_id = self._parse_user_id(user_id)
|
parsed_user_id = self._parse_user_id(user_id)
|
||||||
self._user_ids -= parsed_user_id
|
self._user_ids -= parsed_user_id
|
||||||
|
|
||||||
|
@ -1107,8 +1137,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
if self.user_ids:
|
if self.user_ids:
|
||||||
return message.from_user.id in self.user_ids
|
return message.from_user.id in self.user_ids
|
||||||
if self.usernames:
|
if self.usernames:
|
||||||
return bool(message.from_user.username
|
return bool(
|
||||||
and message.from_user.username in self.usernames)
|
message.from_user.username and message.from_user.username in self.usernames
|
||||||
|
)
|
||||||
return self.allow_empty
|
return self.allow_empty
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1145,10 +1176,13 @@ officedocument.wordprocessingml.document")``-
|
||||||
Raises:
|
Raises:
|
||||||
RuntimeError: If bot_id and username are both present.
|
RuntimeError: If bot_id and username are both present.
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
bot_id: Union[int, List[int]] = None,
|
def __init__(
|
||||||
username: Union[str, List[str]] = None,
|
self,
|
||||||
allow_empty: bool = False):
|
bot_id: Union[int, List[int]] = None,
|
||||||
|
username: Union[str, List[str]] = None,
|
||||||
|
allow_empty: bool = False,
|
||||||
|
):
|
||||||
self.allow_empty = allow_empty
|
self.allow_empty = allow_empty
|
||||||
self.__lock = Lock()
|
self.__lock = Lock()
|
||||||
|
|
||||||
|
@ -1177,15 +1211,17 @@ officedocument.wordprocessingml.document")``-
|
||||||
def _set_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
|
def _set_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if bot_id and self._usernames:
|
if bot_id and self._usernames:
|
||||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
self._bot_ids = self._parse_bot_id(bot_id)
|
self._bot_ids = self._parse_bot_id(bot_id)
|
||||||
|
|
||||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if username and self._bot_ids:
|
if username and self._bot_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"bot_ids.")
|
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||||
|
)
|
||||||
self._usernames = self._parse_username(username)
|
self._usernames = self._parse_username(username)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1216,8 +1252,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._bot_ids:
|
if self._bot_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"bot_ids.")
|
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames |= parsed_username
|
self._usernames |= parsed_username
|
||||||
|
@ -1233,8 +1270,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_bot_id = self._parse_bot_id(bot_id)
|
parsed_bot_id = self._parse_bot_id(bot_id)
|
||||||
|
|
||||||
|
@ -1250,8 +1288,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._bot_ids:
|
if self._bot_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"bot_ids.")
|
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames -= parsed_username
|
self._usernames -= parsed_username
|
||||||
|
@ -1266,8 +1305,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
parsed_bot_id = self._parse_bot_id(bot_id)
|
parsed_bot_id = self._parse_bot_id(bot_id)
|
||||||
self._bot_ids -= parsed_bot_id
|
self._bot_ids -= parsed_bot_id
|
||||||
|
|
||||||
|
@ -1277,8 +1317,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
if self.bot_ids:
|
if self.bot_ids:
|
||||||
return message.via_bot.id in self.bot_ids
|
return message.via_bot.id in self.bot_ids
|
||||||
if self.usernames:
|
if self.usernames:
|
||||||
return bool(message.via_bot.username
|
return bool(
|
||||||
and message.via_bot.username in self.usernames)
|
message.via_bot.username and message.via_bot.username in self.usernames
|
||||||
|
)
|
||||||
return self.allow_empty
|
return self.allow_empty
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1316,10 +1357,12 @@ officedocument.wordprocessingml.document")``-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
chat_id: Union[int, List[int]] = None,
|
self,
|
||||||
username: Union[str, List[str]] = None,
|
chat_id: Union[int, List[int]] = None,
|
||||||
allow_empty: bool = False):
|
username: Union[str, List[str]] = None,
|
||||||
|
allow_empty: bool = False,
|
||||||
|
):
|
||||||
self.allow_empty = allow_empty
|
self.allow_empty = allow_empty
|
||||||
self.__lock = Lock()
|
self.__lock = Lock()
|
||||||
|
|
||||||
|
@ -1348,15 +1391,17 @@ officedocument.wordprocessingml.document")``-
|
||||||
def _set_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
|
def _set_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if chat_id and self._usernames:
|
if chat_id and self._usernames:
|
||||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
self._chat_ids = self._parse_chat_id(chat_id)
|
self._chat_ids = self._parse_chat_id(chat_id)
|
||||||
|
|
||||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if username and self._chat_ids:
|
if username and self._chat_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"chat_ids.")
|
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||||
|
)
|
||||||
self._usernames = self._parse_username(username)
|
self._usernames = self._parse_username(username)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1387,8 +1432,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._chat_ids:
|
if self._chat_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"chat_ids.")
|
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames |= parsed_username
|
self._usernames |= parsed_username
|
||||||
|
@ -1403,8 +1449,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_chat_id = self._parse_chat_id(chat_id)
|
parsed_chat_id = self._parse_chat_id(chat_id)
|
||||||
|
|
||||||
|
@ -1420,8 +1467,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._chat_ids:
|
if self._chat_ids:
|
||||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"chat_ids.")
|
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||||
|
)
|
||||||
|
|
||||||
parsed_username = self._parse_username(username)
|
parsed_username = self._parse_username(username)
|
||||||
self._usernames -= parsed_username
|
self._usernames -= parsed_username
|
||||||
|
@ -1436,8 +1484,9 @@ officedocument.wordprocessingml.document")``-
|
||||||
"""
|
"""
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
if self._usernames:
|
if self._usernames:
|
||||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
raise RuntimeError(
|
||||||
"usernames.")
|
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||||
|
)
|
||||||
parsed_chat_id = self._parse_chat_id(chat_id)
|
parsed_chat_id = self._parse_chat_id(chat_id)
|
||||||
self._chat_ids -= parsed_chat_id
|
self._chat_ids -= parsed_chat_id
|
||||||
|
|
||||||
|
@ -1447,8 +1496,7 @@ officedocument.wordprocessingml.document")``-
|
||||||
if self.chat_ids:
|
if self.chat_ids:
|
||||||
return message.chat.id in self.chat_ids
|
return message.chat.id in self.chat_ids
|
||||||
if self.usernames:
|
if self.usernames:
|
||||||
return bool(message.chat.username
|
return bool(message.chat.username and message.chat.username in self.usernames)
|
||||||
and message.chat.username in self.usernames)
|
|
||||||
return self.allow_empty
|
return self.allow_empty
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -1550,8 +1598,10 @@ officedocument.wordprocessingml.document")``-
|
||||||
|
|
||||||
def filter(self, message: Message) -> bool:
|
def filter(self, message: Message) -> bool:
|
||||||
"""""" # remove method from docs
|
"""""" # remove method from docs
|
||||||
return bool(message.from_user.language_code and any(
|
return bool(
|
||||||
[message.from_user.language_code.startswith(x) for x in self.lang]))
|
message.from_user.language_code
|
||||||
|
and any([message.from_user.language_code.startswith(x) for x in self.lang])
|
||||||
|
)
|
||||||
|
|
||||||
class _UpdateType(UpdateFilter):
|
class _UpdateType(UpdateFilter):
|
||||||
name = 'Filters.update'
|
name = 'Filters.update'
|
||||||
|
|
|
@ -24,6 +24,7 @@ from telegram.utils.promise import Promise
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from telegram import Update
|
from telegram import Update
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -87,13 +88,16 @@ class Handler(ABC):
|
||||||
Defaults to :obj:`False`.
|
Defaults to :obj:`False`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self,
|
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
def __init__(
|
||||||
pass_update_queue: bool = False,
|
self,
|
||||||
pass_job_queue: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_user_data: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_job_queue: bool = False,
|
||||||
run_async: bool = False):
|
pass_user_data: bool = False,
|
||||||
|
pass_chat_data: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
self.callback: Callable[[HandlerArg, 'CallbackContext'], RT] = callback
|
self.callback: Callable[[HandlerArg, 'CallbackContext'], RT] = callback
|
||||||
self.pass_update_queue = pass_update_queue
|
self.pass_update_queue = pass_update_queue
|
||||||
self.pass_job_queue = pass_job_queue
|
self.pass_job_queue = pass_job_queue
|
||||||
|
@ -117,11 +121,13 @@ class Handler(ABC):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def handle_update(self,
|
def handle_update(
|
||||||
update: HandlerArg,
|
self,
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: object,
|
dispatcher: 'Dispatcher',
|
||||||
context: 'CallbackContext' = None) -> Union[RT, Promise]:
|
check_result: object,
|
||||||
|
context: 'CallbackContext' = None,
|
||||||
|
) -> Union[RT, Promise]:
|
||||||
"""
|
"""
|
||||||
This method is called if it was determined that an update should indeed
|
This method is called if it was determined that an update should indeed
|
||||||
be handled by this instance. Calls :attr:`callback` along with its respectful
|
be handled by this instance. Calls :attr:`callback` along with its respectful
|
||||||
|
@ -146,16 +152,19 @@ class Handler(ABC):
|
||||||
else:
|
else:
|
||||||
optional_args = self.collect_optional_args(dispatcher, update, check_result)
|
optional_args = self.collect_optional_args(dispatcher, update, check_result)
|
||||||
if self.run_async:
|
if self.run_async:
|
||||||
return dispatcher.run_async(self.callback, dispatcher.bot, update, update=update,
|
return dispatcher.run_async(
|
||||||
**optional_args)
|
self.callback, dispatcher.bot, update, update=update, **optional_args
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.callback(dispatcher.bot, update, **optional_args) # type: ignore
|
return self.callback(dispatcher.bot, update, **optional_args) # type: ignore
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Any) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Any,
|
||||||
|
) -> None:
|
||||||
"""Prepares additional arguments for the context. Override if needed.
|
"""Prepares additional arguments for the context. Override if needed.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -167,10 +176,9 @@ class Handler(ABC):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def collect_optional_args(self,
|
def collect_optional_args(
|
||||||
dispatcher: 'Dispatcher',
|
self, dispatcher: 'Dispatcher', update: HandlerArg = None, check_result: Any = None
|
||||||
update: HandlerArg = None,
|
) -> Dict[str, Any]:
|
||||||
check_result: Any = None) -> Dict[str, Any]:
|
|
||||||
"""
|
"""
|
||||||
Prepares the optional arguments. If the handler has additional optional args,
|
Prepares the optional arguments. If the handler has additional optional args,
|
||||||
it should subclass this method, but remember to call this super method.
|
it should subclass this method, but remember to call this super method.
|
||||||
|
@ -193,10 +201,12 @@ class Handler(ABC):
|
||||||
if self.pass_user_data and isinstance(update, Update):
|
if self.pass_user_data and isinstance(update, Update):
|
||||||
user = update.effective_user
|
user = update.effective_user
|
||||||
optional_args['user_data'] = dispatcher.user_data[
|
optional_args['user_data'] = dispatcher.user_data[
|
||||||
user.id if user else None] # type: ignore[index]
|
user.id if user else None # type: ignore[index]
|
||||||
|
]
|
||||||
if self.pass_chat_data and isinstance(update, Update):
|
if self.pass_chat_data and isinstance(update, Update):
|
||||||
chat = update.effective_chat
|
chat = update.effective_chat
|
||||||
optional_args['chat_data'] = dispatcher.chat_data[
|
optional_args['chat_data'] = dispatcher.chat_data[
|
||||||
chat.id if chat else None] # type: ignore[index]
|
chat.id if chat else None # type: ignore[index]
|
||||||
|
]
|
||||||
|
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
|
@ -24,8 +24,18 @@ from telegram import Update
|
||||||
from .handler import Handler
|
from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern, Match, \
|
from typing import (
|
||||||
cast
|
Callable,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Optional,
|
||||||
|
Union,
|
||||||
|
TypeVar,
|
||||||
|
Dict,
|
||||||
|
Pattern,
|
||||||
|
Match,
|
||||||
|
cast,
|
||||||
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
@ -110,23 +120,26 @@ class InlineQueryHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
self,
|
||||||
pass_update_queue: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pattern: Union[str, Pattern] = None,
|
pass_job_queue: bool = False,
|
||||||
pass_groups: bool = False,
|
pattern: Union[str, Pattern] = None,
|
||||||
pass_groupdict: bool = False,
|
pass_groups: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_groupdict: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
run_async: bool = False):
|
pass_chat_data: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
pass_user_data=pass_user_data,
|
pass_user_data=pass_user_data,
|
||||||
pass_chat_data=pass_chat_data,
|
pass_chat_data=pass_chat_data,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(pattern, str):
|
if isinstance(pattern, str):
|
||||||
pattern = re.compile(pattern)
|
pattern = re.compile(pattern)
|
||||||
|
@ -157,10 +170,12 @@ class InlineQueryHandler(Handler):
|
||||||
return True
|
return True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_optional_args(self,
|
def collect_optional_args(
|
||||||
dispatcher: 'Dispatcher',
|
self,
|
||||||
update: HandlerArg = None,
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Optional[Union[bool, Match]] = None) -> Dict[str, Any]:
|
update: HandlerArg = None,
|
||||||
|
check_result: Optional[Union[bool, Match]] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||||
if self.pattern:
|
if self.pattern:
|
||||||
check_result = cast(Match, check_result)
|
check_result = cast(Match, check_result)
|
||||||
|
@ -170,11 +185,13 @@ class InlineQueryHandler(Handler):
|
||||||
optional_args['groupdict'] = check_result.groupdict()
|
optional_args['groupdict'] = check_result.groupdict()
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Optional[Union[bool, Match]]) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Optional[Union[bool, Match]],
|
||||||
|
) -> None:
|
||||||
if self.pattern:
|
if self.pattern:
|
||||||
check_result = cast(Match, check_result)
|
check_result = cast(Match, check_result)
|
||||||
context.matches = [check_result]
|
context.matches = [check_result]
|
||||||
|
|
|
@ -31,6 +31,7 @@ from telegram.ext.callbackcontext import CallbackContext
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Union, Callable, Tuple, Optional, List, Any, cast, overload
|
from typing import TYPE_CHECKING, Union, Callable, Tuple, Optional, List, Any, cast, overload
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import Dispatcher
|
from telegram.ext import Dispatcher
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
@ -56,8 +57,9 @@ class JobQueue:
|
||||||
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
|
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
|
||||||
self.logger = logging.getLogger(self.__class__.__name__)
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
self.scheduler = BackgroundScheduler(timezone=pytz.utc)
|
self.scheduler = BackgroundScheduler(timezone=pytz.utc)
|
||||||
self.scheduler.add_listener(self._update_persistence,
|
self.scheduler.add_listener(
|
||||||
mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
self._update_persistence, mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
# Dispatch errors and don't log them in the APS logger
|
# Dispatch errors and don't log them in the APS logger
|
||||||
def aps_log_filter(record): # type: ignore
|
def aps_log_filter(record): # type: ignore
|
||||||
|
@ -82,25 +84,29 @@ class JobQueue:
|
||||||
self._dispatcher.dispatch_error(None, event.exception)
|
self._dispatcher.dispatch_error(None, event.exception)
|
||||||
# Errors should not stop the thread.
|
# Errors should not stop the thread.
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception('An error was raised while processing the job and an '
|
self.logger.exception(
|
||||||
'uncaught error was raised while handling the error '
|
'An error was raised while processing the job and an '
|
||||||
'with an error_handler.')
|
'uncaught error was raised while handling the error '
|
||||||
|
'with an error_handler.'
|
||||||
|
)
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def _parse_time_input(self, time: None, shift_day: bool = False) -> None:
|
def _parse_time_input(self, time: None, shift_day: bool = False) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
def _parse_time_input(self,
|
def _parse_time_input(
|
||||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
self,
|
||||||
datetime.time],
|
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time],
|
||||||
shift_day: bool = False) -> datetime.datetime:
|
shift_day: bool = False,
|
||||||
|
) -> datetime.datetime:
|
||||||
...
|
...
|
||||||
|
|
||||||
def _parse_time_input(self,
|
def _parse_time_input(
|
||||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
self,
|
||||||
datetime.time, None],
|
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time, None],
|
||||||
shift_day: bool = False) -> Optional[datetime.datetime]:
|
shift_day: bool = False,
|
||||||
|
) -> Optional[datetime.datetime]:
|
||||||
if time is None:
|
if time is None:
|
||||||
return None
|
return None
|
||||||
if isinstance(time, (int, float)):
|
if isinstance(time, (int, float)):
|
||||||
|
@ -109,7 +115,8 @@ class JobQueue:
|
||||||
return self._tz_now() + time
|
return self._tz_now() + time
|
||||||
if isinstance(time, datetime.time):
|
if isinstance(time, datetime.time):
|
||||||
dt = datetime.datetime.combine(
|
dt = datetime.datetime.combine(
|
||||||
datetime.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time)
|
datetime.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time
|
||||||
|
)
|
||||||
if dt.tzinfo is None:
|
if dt.tzinfo is None:
|
||||||
dt = self.scheduler.timezone.localize(dt)
|
dt = self.scheduler.timezone.localize(dt)
|
||||||
if shift_day and dt <= datetime.datetime.now(pytz.utc):
|
if shift_day and dt <= datetime.datetime.now(pytz.utc):
|
||||||
|
@ -131,12 +138,14 @@ class JobQueue:
|
||||||
if dispatcher.bot.defaults:
|
if dispatcher.bot.defaults:
|
||||||
self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc)
|
self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc)
|
||||||
|
|
||||||
def run_once(self,
|
def run_once(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
when: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
callback: Callable[['CallbackContext'], None],
|
||||||
context: object = None,
|
when: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
||||||
name: str = None,
|
context: object = None,
|
||||||
job_kwargs: JSONDict = None) -> 'Job':
|
name: str = None,
|
||||||
|
job_kwargs: JSONDict = None,
|
||||||
|
) -> 'Job':
|
||||||
"""Creates a new ``Job`` that runs once and adds it to the queue.
|
"""Creates a new ``Job`` that runs once and adds it to the queue.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -183,27 +192,29 @@ class JobQueue:
|
||||||
job = Job(callback, context, name, self)
|
job = Job(callback, context, name, self)
|
||||||
dt = self._parse_time_input(when, shift_day=True)
|
dt = self._parse_time_input(when, shift_day=True)
|
||||||
|
|
||||||
j = self.scheduler.add_job(callback,
|
j = self.scheduler.add_job(
|
||||||
name=name,
|
callback,
|
||||||
trigger='date',
|
name=name,
|
||||||
run_date=dt,
|
trigger='date',
|
||||||
args=self._build_args(job),
|
run_date=dt,
|
||||||
timezone=dt.tzinfo or self.scheduler.timezone,
|
args=self._build_args(job),
|
||||||
**job_kwargs)
|
timezone=dt.tzinfo or self.scheduler.timezone,
|
||||||
|
**job_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
job.job = j
|
job.job = j
|
||||||
return job
|
return job
|
||||||
|
|
||||||
def run_repeating(self,
|
def run_repeating(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
interval: Union[float, datetime.timedelta],
|
callback: Callable[['CallbackContext'], None],
|
||||||
first: Union[float, datetime.timedelta, datetime.datetime,
|
interval: Union[float, datetime.timedelta],
|
||||||
datetime.time] = None,
|
first: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None,
|
||||||
last: Union[float, datetime.timedelta, datetime.datetime,
|
last: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None,
|
||||||
datetime.time] = None,
|
context: object = None,
|
||||||
context: object = None,
|
name: str = None,
|
||||||
name: str = None,
|
job_kwargs: JSONDict = None,
|
||||||
job_kwargs: JSONDict = None) -> 'Job':
|
) -> 'Job':
|
||||||
"""Creates a new ``Job`` that runs at specified intervals and adds it to the queue.
|
"""Creates a new ``Job`` that runs at specified intervals and adds it to the queue.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -277,26 +288,30 @@ class JobQueue:
|
||||||
if isinstance(interval, datetime.timedelta):
|
if isinstance(interval, datetime.timedelta):
|
||||||
interval = interval.total_seconds()
|
interval = interval.total_seconds()
|
||||||
|
|
||||||
j = self.scheduler.add_job(callback,
|
j = self.scheduler.add_job(
|
||||||
trigger='interval',
|
callback,
|
||||||
args=self._build_args(job),
|
trigger='interval',
|
||||||
start_date=dt_first,
|
args=self._build_args(job),
|
||||||
end_date=dt_last,
|
start_date=dt_first,
|
||||||
seconds=interval,
|
end_date=dt_last,
|
||||||
name=name,
|
seconds=interval,
|
||||||
**job_kwargs)
|
name=name,
|
||||||
|
**job_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
job.job = j
|
job.job = j
|
||||||
return job
|
return job
|
||||||
|
|
||||||
def run_monthly(self,
|
def run_monthly(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
when: datetime.time,
|
callback: Callable[['CallbackContext'], None],
|
||||||
day: int,
|
when: datetime.time,
|
||||||
context: object = None,
|
day: int,
|
||||||
name: str = None,
|
context: object = None,
|
||||||
day_is_strict: bool = True,
|
name: str = None,
|
||||||
job_kwargs: JSONDict = None) -> 'Job':
|
day_is_strict: bool = True,
|
||||||
|
job_kwargs: JSONDict = None,
|
||||||
|
) -> 'Job':
|
||||||
"""Creates a new ``Job`` that runs on a monthly basis and adds it to the queue.
|
"""Creates a new ``Job`` that runs on a monthly basis and adds it to the queue.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -332,45 +347,55 @@ class JobQueue:
|
||||||
job = Job(callback, context, name, self)
|
job = Job(callback, context, name, self)
|
||||||
|
|
||||||
if day_is_strict:
|
if day_is_strict:
|
||||||
j = self.scheduler.add_job(callback,
|
j = self.scheduler.add_job(
|
||||||
trigger='cron',
|
callback,
|
||||||
args=self._build_args(job),
|
trigger='cron',
|
||||||
name=name,
|
args=self._build_args(job),
|
||||||
day=day,
|
name=name,
|
||||||
hour=when.hour,
|
day=day,
|
||||||
minute=when.minute,
|
hour=when.hour,
|
||||||
second=when.second,
|
minute=when.minute,
|
||||||
timezone=when.tzinfo or self.scheduler.timezone,
|
second=when.second,
|
||||||
**job_kwargs)
|
timezone=when.tzinfo or self.scheduler.timezone,
|
||||||
|
**job_kwargs,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
trigger = OrTrigger([CronTrigger(day=day,
|
trigger = OrTrigger(
|
||||||
hour=when.hour,
|
[
|
||||||
minute=when.minute,
|
CronTrigger(
|
||||||
second=when.second,
|
day=day,
|
||||||
timezone=when.tzinfo,
|
hour=when.hour,
|
||||||
**job_kwargs),
|
minute=when.minute,
|
||||||
CronTrigger(day='last',
|
second=when.second,
|
||||||
hour=when.hour,
|
timezone=when.tzinfo,
|
||||||
minute=when.minute,
|
**job_kwargs,
|
||||||
second=when.second,
|
),
|
||||||
timezone=when.tzinfo or self.scheduler.timezone,
|
CronTrigger(
|
||||||
**job_kwargs)])
|
day='last',
|
||||||
j = self.scheduler.add_job(callback,
|
hour=when.hour,
|
||||||
trigger=trigger,
|
minute=when.minute,
|
||||||
args=self._build_args(job),
|
second=when.second,
|
||||||
name=name,
|
timezone=when.tzinfo or self.scheduler.timezone,
|
||||||
**job_kwargs)
|
**job_kwargs,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
j = self.scheduler.add_job(
|
||||||
|
callback, trigger=trigger, args=self._build_args(job), name=name, **job_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
job.job = j
|
job.job = j
|
||||||
return job
|
return job
|
||||||
|
|
||||||
def run_daily(self,
|
def run_daily(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
time: datetime.time,
|
callback: Callable[['CallbackContext'], None],
|
||||||
days: Tuple[int, ...] = Days.EVERY_DAY,
|
time: datetime.time,
|
||||||
context: object = None,
|
days: Tuple[int, ...] = Days.EVERY_DAY,
|
||||||
name: str = None,
|
context: object = None,
|
||||||
job_kwargs: JSONDict = None) -> 'Job':
|
name: str = None,
|
||||||
|
job_kwargs: JSONDict = None,
|
||||||
|
) -> 'Job':
|
||||||
"""Creates a new ``Job`` that runs on a daily basis and adds it to the queue.
|
"""Creates a new ``Job`` that runs on a daily basis and adds it to the queue.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -409,25 +434,29 @@ class JobQueue:
|
||||||
name = name or callback.__name__
|
name = name or callback.__name__
|
||||||
job = Job(callback, context, name, self)
|
job = Job(callback, context, name, self)
|
||||||
|
|
||||||
j = self.scheduler.add_job(callback,
|
j = self.scheduler.add_job(
|
||||||
name=name,
|
callback,
|
||||||
args=self._build_args(job),
|
name=name,
|
||||||
trigger='cron',
|
args=self._build_args(job),
|
||||||
day_of_week=','.join([str(d) for d in days]),
|
trigger='cron',
|
||||||
hour=time.hour,
|
day_of_week=','.join([str(d) for d in days]),
|
||||||
minute=time.minute,
|
hour=time.hour,
|
||||||
second=time.second,
|
minute=time.minute,
|
||||||
timezone=time.tzinfo or self.scheduler.timezone,
|
second=time.second,
|
||||||
**job_kwargs)
|
timezone=time.tzinfo or self.scheduler.timezone,
|
||||||
|
**job_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
job.job = j
|
job.job = j
|
||||||
return job
|
return job
|
||||||
|
|
||||||
def run_custom(self,
|
def run_custom(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
job_kwargs: JSONDict,
|
callback: Callable[['CallbackContext'], None],
|
||||||
context: object = None,
|
job_kwargs: JSONDict,
|
||||||
name: str = None) -> 'Job':
|
context: object = None,
|
||||||
|
name: str = None,
|
||||||
|
) -> 'Job':
|
||||||
"""Creates a new customly defined ``Job``.
|
"""Creates a new customly defined ``Job``.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -453,10 +482,7 @@ class JobQueue:
|
||||||
name = name or callback.__name__
|
name = name or callback.__name__
|
||||||
job = Job(callback, context, name, self)
|
job = Job(callback, context, name, self)
|
||||||
|
|
||||||
j = self.scheduler.add_job(callback,
|
j = self.scheduler.add_job(callback, args=self._build_args(job), name=name, **job_kwargs)
|
||||||
args=self._build_args(job),
|
|
||||||
name=name,
|
|
||||||
**job_kwargs)
|
|
||||||
|
|
||||||
job.job = j
|
job.job = j
|
||||||
return job
|
return job
|
||||||
|
@ -516,12 +542,14 @@ class Job:
|
||||||
job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for.
|
job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
callback: Callable[['CallbackContext'], None],
|
self,
|
||||||
context: object = None,
|
callback: Callable[['CallbackContext'], None],
|
||||||
name: str = None,
|
context: object = None,
|
||||||
job_queue: JobQueue = None,
|
name: str = None,
|
||||||
job: 'Job' = None):
|
job_queue: JobQueue = None,
|
||||||
|
job: 'Job' = None,
|
||||||
|
):
|
||||||
|
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
self.context = context
|
self.context = context
|
||||||
|
@ -545,9 +573,11 @@ class Job:
|
||||||
dispatcher.dispatch_error(None, e)
|
dispatcher.dispatch_error(None, e)
|
||||||
# Errors should not stop the thread.
|
# Errors should not stop the thread.
|
||||||
except Exception:
|
except Exception:
|
||||||
dispatcher.logger.exception('An error was raised while processing the job and an '
|
dispatcher.logger.exception(
|
||||||
'uncaught error was raised while handling the error '
|
'An error was raised while processing the job and an '
|
||||||
'with an error_handler.')
|
'uncaught error was raised while handling the error '
|
||||||
|
'with an error_handler.'
|
||||||
|
)
|
||||||
|
|
||||||
def schedule_removal(self) -> None:
|
def schedule_removal(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -28,6 +28,7 @@ from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -120,17 +121,19 @@ class MessageHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
filters: BaseFilter,
|
self,
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
filters: BaseFilter,
|
||||||
pass_update_queue: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_job_queue: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
message_updates: bool = None,
|
pass_chat_data: bool = False,
|
||||||
channel_post_updates: bool = None,
|
message_updates: bool = None,
|
||||||
edited_updates: bool = None,
|
channel_post_updates: bool = None,
|
||||||
run_async: bool = False):
|
edited_updates: bool = None,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
|
@ -138,36 +141,44 @@ class MessageHandler(Handler):
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
pass_user_data=pass_user_data,
|
pass_user_data=pass_user_data,
|
||||||
pass_chat_data=pass_chat_data,
|
pass_chat_data=pass_chat_data,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
if message_updates is False and channel_post_updates is False and edited_updates is False:
|
if message_updates is False and channel_post_updates is False and edited_updates is False:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'message_updates, channel_post_updates and edited_updates are all False')
|
'message_updates, channel_post_updates and edited_updates are all False'
|
||||||
|
)
|
||||||
if filters is not None:
|
if filters is not None:
|
||||||
self.filters = Filters.update & filters
|
self.filters = Filters.update & filters
|
||||||
else:
|
else:
|
||||||
self.filters = Filters.update
|
self.filters = Filters.update
|
||||||
if message_updates is not None:
|
if message_updates is not None:
|
||||||
warnings.warn('message_updates is deprecated. See https://git.io/fxJuV for more info',
|
warnings.warn(
|
||||||
TelegramDeprecationWarning,
|
'message_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||||
stacklevel=2)
|
TelegramDeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
if message_updates is False:
|
if message_updates is False:
|
||||||
self.filters &= ~Filters.update.message
|
self.filters &= ~Filters.update.message
|
||||||
|
|
||||||
if channel_post_updates is not None:
|
if channel_post_updates is not None:
|
||||||
warnings.warn('channel_post_updates is deprecated. See https://git.io/fxJuV '
|
warnings.warn(
|
||||||
'for more info',
|
'channel_post_updates is deprecated. See https://git.io/fxJuV ' 'for more info',
|
||||||
TelegramDeprecationWarning,
|
TelegramDeprecationWarning,
|
||||||
stacklevel=2)
|
stacklevel=2,
|
||||||
|
)
|
||||||
if channel_post_updates is False:
|
if channel_post_updates is False:
|
||||||
self.filters &= ~Filters.update.channel_post
|
self.filters &= ~Filters.update.channel_post
|
||||||
|
|
||||||
if edited_updates is not None:
|
if edited_updates is not None:
|
||||||
warnings.warn('edited_updates is deprecated. See https://git.io/fxJuV for more info',
|
warnings.warn(
|
||||||
TelegramDeprecationWarning,
|
'edited_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||||
stacklevel=2)
|
TelegramDeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
if edited_updates is False:
|
if edited_updates is False:
|
||||||
self.filters &= ~(Filters.update.edited_message
|
self.filters &= ~(
|
||||||
| Filters.update.edited_channel_post)
|
Filters.update.edited_message | Filters.update.edited_channel_post
|
||||||
|
)
|
||||||
|
|
||||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Dict[str, Any]]]:
|
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Dict[str, Any]]]:
|
||||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||||
|
@ -183,10 +194,12 @@ class MessageHandler(Handler):
|
||||||
return self.filters(update)
|
return self.filters(update)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Optional[Union[bool, Dict[str, Any]]]) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Optional[Union[bool, Dict[str, Any]]],
|
||||||
|
) -> None:
|
||||||
if isinstance(check_result, dict):
|
if isinstance(check_result, dict):
|
||||||
context.update(check_result)
|
context.update(check_result)
|
||||||
|
|
|
@ -38,6 +38,7 @@ curtime = time.perf_counter
|
||||||
|
|
||||||
class DelayQueueError(RuntimeError):
|
class DelayQueueError(RuntimeError):
|
||||||
"""Indicates processing errors."""
|
"""Indicates processing errors."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,17 +76,19 @@ class DelayQueue(threading.Thread):
|
||||||
|
|
||||||
_instcnt = 0 # instance counter
|
_instcnt = 0 # instance counter
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
queue: q.Queue = None,
|
self,
|
||||||
burst_limit: int = 30,
|
queue: q.Queue = None,
|
||||||
time_limit_ms: int = 1000,
|
burst_limit: int = 30,
|
||||||
exc_route: Callable[[Exception], None] = None,
|
time_limit_ms: int = 1000,
|
||||||
autostart: bool = True,
|
exc_route: Callable[[Exception], None] = None,
|
||||||
name: str = None):
|
autostart: bool = True,
|
||||||
|
name: str = None,
|
||||||
|
):
|
||||||
self._queue = queue if queue is not None else q.Queue()
|
self._queue = queue if queue is not None else q.Queue()
|
||||||
self.burst_limit = burst_limit
|
self.burst_limit = burst_limit
|
||||||
self.time_limit = time_limit_ms / 1000
|
self.time_limit = time_limit_ms / 1000
|
||||||
self.exc_route = (exc_route if exc_route is not None else self._default_exception_handler)
|
self.exc_route = exc_route if exc_route is not None else self._default_exception_handler
|
||||||
self.__exit_req = False # flag to gently exit thread
|
self.__exit_req = False # flag to gently exit thread
|
||||||
self.__class__._instcnt += 1
|
self.__class__._instcnt += 1
|
||||||
if name is None:
|
if name is None:
|
||||||
|
@ -201,24 +204,28 @@ class MessageQueue:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
all_burst_limit: int = 30,
|
self,
|
||||||
all_time_limit_ms: int = 1000,
|
all_burst_limit: int = 30,
|
||||||
group_burst_limit: int = 20,
|
all_time_limit_ms: int = 1000,
|
||||||
group_time_limit_ms: int = 60000,
|
group_burst_limit: int = 20,
|
||||||
exc_route: Callable[[Exception], None] = None,
|
group_time_limit_ms: int = 60000,
|
||||||
autostart: bool = True):
|
exc_route: Callable[[Exception], None] = None,
|
||||||
|
autostart: bool = True,
|
||||||
|
):
|
||||||
# create according delay queues, use composition
|
# create according delay queues, use composition
|
||||||
self._all_delayq = DelayQueue(
|
self._all_delayq = DelayQueue(
|
||||||
burst_limit=all_burst_limit,
|
burst_limit=all_burst_limit,
|
||||||
time_limit_ms=all_time_limit_ms,
|
time_limit_ms=all_time_limit_ms,
|
||||||
exc_route=exc_route,
|
exc_route=exc_route,
|
||||||
autostart=autostart)
|
autostart=autostart,
|
||||||
|
)
|
||||||
self._group_delayq = DelayQueue(
|
self._group_delayq = DelayQueue(
|
||||||
burst_limit=group_burst_limit,
|
burst_limit=group_burst_limit,
|
||||||
time_limit_ms=group_time_limit_ms,
|
time_limit_ms=group_time_limit_ms,
|
||||||
exc_route=exc_route,
|
exc_route=exc_route,
|
||||||
autostart=autostart)
|
autostart=autostart,
|
||||||
|
)
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
"""Method is used to manually start the ``MessageQueue`` processing."""
|
"""Method is used to manually start the ``MessageQueue`` processing."""
|
||||||
|
@ -297,11 +304,12 @@ def queuedmessage(method: Callable) -> Callable:
|
||||||
|
|
||||||
@functools.wraps(method)
|
@functools.wraps(method)
|
||||||
def wrapped(self: 'Bot', *args: Any, **kwargs: Any) -> Any:
|
def wrapped(self: 'Bot', *args: Any, **kwargs: Any) -> Any:
|
||||||
queued = kwargs.pop('queued',
|
queued = kwargs.pop(
|
||||||
self._is_messages_queued_default) # type: ignore[attr-defined]
|
'queued', self._is_messages_queued_default # type: ignore[attr-defined]
|
||||||
|
)
|
||||||
isgroup = kwargs.pop('isgroup', False)
|
isgroup = kwargs.pop('isgroup', False)
|
||||||
if queued:
|
if queued:
|
||||||
prom = promise.Promise(method, (self, ) + args, kwargs)
|
prom = promise.Promise(method, (self,) + args, kwargs)
|
||||||
return self._msg_queue(prom, isgroup) # type: ignore[attr-defined]
|
return self._msg_queue(prom, isgroup) # type: ignore[attr-defined]
|
||||||
return method(self, *args, **kwargs)
|
return method(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -74,16 +74,20 @@ class PicklePersistence(BasePersistence):
|
||||||
Default is :obj:`False`.
|
Default is :obj:`False`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
filename: str,
|
self,
|
||||||
store_user_data: bool = True,
|
filename: str,
|
||||||
store_chat_data: bool = True,
|
store_user_data: bool = True,
|
||||||
store_bot_data: bool = True,
|
store_chat_data: bool = True,
|
||||||
single_file: bool = True,
|
store_bot_data: bool = True,
|
||||||
on_flush: bool = False):
|
single_file: bool = True,
|
||||||
super().__init__(store_user_data=store_user_data,
|
on_flush: bool = False,
|
||||||
store_chat_data=store_chat_data,
|
):
|
||||||
store_bot_data=store_bot_data)
|
super().__init__(
|
||||||
|
store_user_data=store_user_data,
|
||||||
|
store_chat_data=store_chat_data,
|
||||||
|
store_bot_data=store_bot_data,
|
||||||
|
)
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.single_file = single_file
|
self.single_file = single_file
|
||||||
self.on_flush = on_flush
|
self.on_flush = on_flush
|
||||||
|
@ -125,8 +129,12 @@ class PicklePersistence(BasePersistence):
|
||||||
|
|
||||||
def dump_singlefile(self) -> None:
|
def dump_singlefile(self) -> None:
|
||||||
with open(self.filename, "wb") as f:
|
with open(self.filename, "wb") as f:
|
||||||
data = {'conversations': self.conversations, 'user_data': self.user_data,
|
data = {
|
||||||
'chat_data': self.chat_data, 'bot_data': self.bot_data}
|
'conversations': self.conversations,
|
||||||
|
'user_data': self.user_data,
|
||||||
|
'chat_data': self.chat_data,
|
||||||
|
'bot_data': self.bot_data,
|
||||||
|
}
|
||||||
pickle.dump(data, f)
|
pickle.dump(data, f)
|
||||||
|
|
||||||
def dump_file(self, filename: str, data: Any) -> None:
|
def dump_file(self, filename: str, data: Any) -> None:
|
||||||
|
@ -212,9 +220,9 @@ class PicklePersistence(BasePersistence):
|
||||||
self.load_singlefile()
|
self.load_singlefile()
|
||||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||||
|
|
||||||
def update_conversation(self,
|
def update_conversation(
|
||||||
name: str, key: Tuple[int, ...],
|
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||||
new_state: Optional[object]) -> None:
|
) -> None:
|
||||||
"""Will update the conversations for the given handler and depending on :attr:`on_flush`
|
"""Will update the conversations for the given handler and depending on :attr:`on_flush`
|
||||||
save the pickle file.
|
save the pickle file.
|
||||||
|
|
||||||
|
@ -290,8 +298,7 @@ class PicklePersistence(BasePersistence):
|
||||||
self.dump_singlefile()
|
self.dump_singlefile()
|
||||||
|
|
||||||
def flush(self) -> None:
|
def flush(self) -> None:
|
||||||
""" Will save all data in memory to pickle file(s).
|
"""Will save all data in memory to pickle file(s)."""
|
||||||
"""
|
|
||||||
if self.single_file:
|
if self.single_file:
|
||||||
if self.user_data or self.chat_data or self.bot_data or self.conversations:
|
if self.user_data or self.chat_data or self.bot_data or self.conversations:
|
||||||
self.dump_singlefile()
|
self.dump_singlefile()
|
||||||
|
|
|
@ -27,6 +27,7 @@ from telegram.ext import MessageHandler, Filters
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern
|
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -108,41 +109,48 @@ class RegexHandler(MessageHandler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
pattern: Union[str, Pattern],
|
self,
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
pattern: Union[str, Pattern],
|
||||||
pass_groups: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_groupdict: bool = False,
|
pass_groups: bool = False,
|
||||||
pass_update_queue: bool = False,
|
pass_groupdict: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
pass_user_data: bool = False,
|
pass_job_queue: bool = False,
|
||||||
pass_chat_data: bool = False,
|
pass_user_data: bool = False,
|
||||||
allow_edited: bool = False,
|
pass_chat_data: bool = False,
|
||||||
message_updates: bool = True,
|
allow_edited: bool = False,
|
||||||
channel_post_updates: bool = False,
|
message_updates: bool = True,
|
||||||
edited_updates: bool = False,
|
channel_post_updates: bool = False,
|
||||||
run_async: bool = False):
|
edited_updates: bool = False,
|
||||||
warnings.warn('RegexHandler is deprecated. See https://git.io/fxJuV for more info',
|
run_async: bool = False,
|
||||||
TelegramDeprecationWarning,
|
):
|
||||||
stacklevel=2)
|
warnings.warn(
|
||||||
super().__init__(Filters.regex(pattern),
|
'RegexHandler is deprecated. See https://git.io/fxJuV for more info',
|
||||||
callback,
|
TelegramDeprecationWarning,
|
||||||
pass_update_queue=pass_update_queue,
|
stacklevel=2,
|
||||||
pass_job_queue=pass_job_queue,
|
)
|
||||||
pass_user_data=pass_user_data,
|
super().__init__(
|
||||||
pass_chat_data=pass_chat_data,
|
Filters.regex(pattern),
|
||||||
message_updates=message_updates,
|
callback,
|
||||||
channel_post_updates=channel_post_updates,
|
pass_update_queue=pass_update_queue,
|
||||||
edited_updates=edited_updates,
|
pass_job_queue=pass_job_queue,
|
||||||
run_async=run_async)
|
pass_user_data=pass_user_data,
|
||||||
|
pass_chat_data=pass_chat_data,
|
||||||
|
message_updates=message_updates,
|
||||||
|
channel_post_updates=channel_post_updates,
|
||||||
|
edited_updates=edited_updates,
|
||||||
|
run_async=run_async,
|
||||||
|
)
|
||||||
self.pass_groups = pass_groups
|
self.pass_groups = pass_groups
|
||||||
self.pass_groupdict = pass_groupdict
|
self.pass_groupdict = pass_groupdict
|
||||||
|
|
||||||
def collect_optional_args(
|
def collect_optional_args(
|
||||||
self,
|
self,
|
||||||
dispatcher: 'Dispatcher',
|
dispatcher: 'Dispatcher',
|
||||||
update: HandlerArg = None,
|
update: HandlerArg = None,
|
||||||
check_result: Optional[Union[bool, Dict[str, Any]]] = None) -> Dict[str, Any]:
|
check_result: Optional[Union[bool, Dict[str, Any]]] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||||
if isinstance(check_result, dict):
|
if isinstance(check_result, dict):
|
||||||
if self.pass_groups:
|
if self.pass_groups:
|
||||||
|
|
|
@ -22,6 +22,7 @@ from .handler import Handler
|
||||||
|
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
from typing import Callable, TYPE_CHECKING, Any, Optional, TypeVar, Dict, List
|
from typing import Callable, TYPE_CHECKING, Any, Optional, TypeVar, Dict, List
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -80,18 +81,21 @@ class StringCommandHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
command: str,
|
self,
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
command: str,
|
||||||
pass_args: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_update_queue: bool = False,
|
pass_args: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
run_async: bool = False):
|
pass_job_queue: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
self.command = command
|
self.command = command
|
||||||
self.pass_args = pass_args
|
self.pass_args = pass_args
|
||||||
|
|
||||||
|
@ -111,18 +115,22 @@ class StringCommandHandler(Handler):
|
||||||
return args[1:]
|
return args[1:]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_optional_args(self,
|
def collect_optional_args(
|
||||||
dispatcher: 'Dispatcher',
|
self,
|
||||||
update: HandlerArg = None,
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Optional[List[str]] = None) -> Dict[str, Any]:
|
update: HandlerArg = None,
|
||||||
|
check_result: Optional[List[str]] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||||
if self.pass_args:
|
if self.pass_args:
|
||||||
optional_args['args'] = check_result
|
optional_args['args'] = check_result
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Optional[List[str]]) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Optional[List[str]],
|
||||||
|
) -> None:
|
||||||
context.args = check_result
|
context.args = check_result
|
||||||
|
|
|
@ -24,6 +24,7 @@ from .handler import Handler
|
||||||
|
|
||||||
from typing import Callable, TYPE_CHECKING, Optional, TypeVar, Match, Dict, Any, Union, Pattern
|
from typing import Callable, TYPE_CHECKING, Optional, TypeVar, Match, Dict, Any, Union, Pattern
|
||||||
from telegram.utils.types import HandlerArg
|
from telegram.utils.types import HandlerArg
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram.ext import CallbackContext, Dispatcher
|
from telegram.ext import CallbackContext, Dispatcher
|
||||||
|
|
||||||
|
@ -90,19 +91,22 @@ class StringRegexHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
pattern: Union[str, Pattern],
|
self,
|
||||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
pattern: Union[str, Pattern],
|
||||||
pass_groups: bool = False,
|
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||||
pass_groupdict: bool = False,
|
pass_groups: bool = False,
|
||||||
pass_update_queue: bool = False,
|
pass_groupdict: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
run_async: bool = False):
|
pass_job_queue: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(pattern, str):
|
if isinstance(pattern, str):
|
||||||
pattern = re.compile(pattern)
|
pattern = re.compile(pattern)
|
||||||
|
@ -127,10 +131,12 @@ class StringRegexHandler(Handler):
|
||||||
return match
|
return match
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def collect_optional_args(self,
|
def collect_optional_args(
|
||||||
dispatcher: 'Dispatcher',
|
self,
|
||||||
update: HandlerArg = None,
|
dispatcher: 'Dispatcher',
|
||||||
check_result: Optional[Match] = None) -> Dict[str, Any]:
|
update: HandlerArg = None,
|
||||||
|
check_result: Optional[Match] = None,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||||
if self.pattern:
|
if self.pattern:
|
||||||
if self.pass_groups and check_result:
|
if self.pass_groups and check_result:
|
||||||
|
@ -139,10 +145,12 @@ class StringRegexHandler(Handler):
|
||||||
optional_args['groupdict'] = check_result.groupdict()
|
optional_args['groupdict'] = check_result.groupdict()
|
||||||
return optional_args
|
return optional_args
|
||||||
|
|
||||||
def collect_additional_context(self,
|
def collect_additional_context(
|
||||||
context: 'CallbackContext',
|
self,
|
||||||
update: HandlerArg,
|
context: 'CallbackContext',
|
||||||
dispatcher: 'Dispatcher',
|
update: HandlerArg,
|
||||||
check_result: Optional[Match]) -> None:
|
dispatcher: 'Dispatcher',
|
||||||
|
check_result: Optional[Match],
|
||||||
|
) -> None:
|
||||||
if self.pattern and check_result:
|
if self.pattern and check_result:
|
||||||
context.matches = [check_result]
|
context.matches = [check_result]
|
||||||
|
|
|
@ -74,18 +74,21 @@ class TypeHandler(Handler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
type: Type,
|
self,
|
||||||
callback: Callable[[Any, 'CallbackContext'], RT],
|
type: Type,
|
||||||
strict: bool = False,
|
callback: Callable[[Any, 'CallbackContext'], RT],
|
||||||
pass_update_queue: bool = False,
|
strict: bool = False,
|
||||||
pass_job_queue: bool = False,
|
pass_update_queue: bool = False,
|
||||||
run_async: bool = False):
|
pass_job_queue: bool = False,
|
||||||
|
run_async: bool = False,
|
||||||
|
):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
callback,
|
callback,
|
||||||
pass_update_queue=pass_update_queue,
|
pass_update_queue=pass_update_queue,
|
||||||
pass_job_queue=pass_job_queue,
|
pass_job_queue=pass_job_queue,
|
||||||
run_async=run_async)
|
run_async=run_async,
|
||||||
|
)
|
||||||
self.type = type
|
self.type = type
|
||||||
self.strict = strict
|
self.strict = strict
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ from telegram.error import Unauthorized, InvalidToken, RetryAfter, TimedOut
|
||||||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||||
from telegram.utils.helpers import get_signal_name
|
from telegram.utils.helpers import get_signal_name
|
||||||
from telegram.utils.request import Request
|
from telegram.utils.request import Request
|
||||||
from telegram.utils.webhookhandler import (WebhookServer, WebhookAppClass)
|
from telegram.utils.webhookhandler import WebhookServer, WebhookAppClass
|
||||||
|
|
||||||
from typing import Callable, Dict, TYPE_CHECKING, Any, List, Union, Tuple, no_type_check, Optional
|
from typing import Callable, Dict, TYPE_CHECKING, Any, List, Union, Tuple, no_type_check, Optional
|
||||||
|
|
||||||
|
@ -108,26 +108,30 @@ class Updater:
|
||||||
|
|
||||||
_request = None
|
_request = None
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
token: str = None,
|
self,
|
||||||
base_url: str = None,
|
token: str = None,
|
||||||
workers: int = 4,
|
base_url: str = None,
|
||||||
bot: Bot = None,
|
workers: int = 4,
|
||||||
private_key: bytes = None,
|
bot: Bot = None,
|
||||||
private_key_password: bytes = None,
|
private_key: bytes = None,
|
||||||
user_sig_handler: Callable = None,
|
private_key_password: bytes = None,
|
||||||
request_kwargs: Dict[str, Any] = None,
|
user_sig_handler: Callable = None,
|
||||||
persistence: 'BasePersistence' = None,
|
request_kwargs: Dict[str, Any] = None,
|
||||||
defaults: 'Defaults' = None,
|
persistence: 'BasePersistence' = None,
|
||||||
use_context: bool = True,
|
defaults: 'Defaults' = None,
|
||||||
dispatcher: Dispatcher = None,
|
use_context: bool = True,
|
||||||
base_file_url: str = None):
|
dispatcher: Dispatcher = None,
|
||||||
|
base_file_url: str = None,
|
||||||
|
):
|
||||||
|
|
||||||
if defaults and bot:
|
if defaults and bot:
|
||||||
warnings.warn('Passing defaults to an Updater has no effect when a Bot is passed '
|
warnings.warn(
|
||||||
'as well. Pass them to the Bot instead.',
|
'Passing defaults to an Updater has no effect when a Bot is passed '
|
||||||
TelegramDeprecationWarning,
|
'as well. Pass them to the Bot instead.',
|
||||||
stacklevel=2)
|
TelegramDeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
if dispatcher is None:
|
if dispatcher is None:
|
||||||
if (token is None) and (bot is None):
|
if (token is None) and (bot is None):
|
||||||
|
@ -156,7 +160,8 @@ class Updater:
|
||||||
if bot.request.con_pool_size < con_pool_size:
|
if bot.request.con_pool_size < con_pool_size:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
'Connection pool of Request object is smaller than optimal value (%s)',
|
||||||
con_pool_size)
|
con_pool_size,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# we need a connection pool the size of:
|
# we need a connection pool the size of:
|
||||||
# * for each of the workers
|
# * for each of the workers
|
||||||
|
@ -169,24 +174,28 @@ class Updater:
|
||||||
if 'con_pool_size' not in request_kwargs:
|
if 'con_pool_size' not in request_kwargs:
|
||||||
request_kwargs['con_pool_size'] = con_pool_size
|
request_kwargs['con_pool_size'] = con_pool_size
|
||||||
self._request = Request(**request_kwargs)
|
self._request = Request(**request_kwargs)
|
||||||
self.bot = Bot(token, # type: ignore[arg-type]
|
self.bot = Bot(
|
||||||
base_url,
|
token, # type: ignore[arg-type]
|
||||||
base_file_url=base_file_url,
|
base_url,
|
||||||
request=self._request,
|
base_file_url=base_file_url,
|
||||||
private_key=private_key,
|
request=self._request,
|
||||||
private_key_password=private_key_password,
|
private_key=private_key,
|
||||||
defaults=defaults)
|
private_key_password=private_key_password,
|
||||||
|
defaults=defaults,
|
||||||
|
)
|
||||||
self.update_queue: Queue = Queue()
|
self.update_queue: Queue = Queue()
|
||||||
self.job_queue = JobQueue()
|
self.job_queue = JobQueue()
|
||||||
self.__exception_event = Event()
|
self.__exception_event = Event()
|
||||||
self.persistence = persistence
|
self.persistence = persistence
|
||||||
self.dispatcher = Dispatcher(self.bot,
|
self.dispatcher = Dispatcher(
|
||||||
self.update_queue,
|
self.bot,
|
||||||
job_queue=self.job_queue,
|
self.update_queue,
|
||||||
workers=workers,
|
job_queue=self.job_queue,
|
||||||
exception_event=self.__exception_event,
|
workers=workers,
|
||||||
persistence=persistence,
|
exception_event=self.__exception_event,
|
||||||
use_context=use_context)
|
persistence=persistence,
|
||||||
|
use_context=use_context,
|
||||||
|
)
|
||||||
self.job_queue.set_dispatcher(self.dispatcher)
|
self.job_queue.set_dispatcher(self.dispatcher)
|
||||||
else:
|
else:
|
||||||
con_pool_size = dispatcher.workers + 4
|
con_pool_size = dispatcher.workers + 4
|
||||||
|
@ -195,7 +204,8 @@ class Updater:
|
||||||
if self.bot.request.con_pool_size < con_pool_size:
|
if self.bot.request.con_pool_size < con_pool_size:
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
'Connection pool of Request object is smaller than optimal value (%s)',
|
||||||
con_pool_size)
|
con_pool_size,
|
||||||
|
)
|
||||||
self.update_queue = dispatcher.update_queue
|
self.update_queue = dispatcher.update_queue
|
||||||
self.__exception_event = dispatcher.exception_event
|
self.__exception_event = dispatcher.exception_event
|
||||||
self.persistence = dispatcher.persistence
|
self.persistence = dispatcher.persistence
|
||||||
|
@ -211,10 +221,12 @@ class Updater:
|
||||||
self.__threads: List[Thread] = []
|
self.__threads: List[Thread] = []
|
||||||
|
|
||||||
def _init_thread(self, target: Callable, name: str, *args: Any, **kwargs: Any) -> None:
|
def _init_thread(self, target: Callable, name: str, *args: Any, **kwargs: Any) -> None:
|
||||||
thr = Thread(target=self._thread_wrapper,
|
thr = Thread(
|
||||||
name="Bot:{}:{}".format(self.bot.id, name),
|
target=self._thread_wrapper,
|
||||||
args=(target,) + args,
|
name="Bot:{}:{}".format(self.bot.id, name),
|
||||||
kwargs=kwargs)
|
args=(target,) + args,
|
||||||
|
kwargs=kwargs,
|
||||||
|
)
|
||||||
thr.start()
|
thr.start()
|
||||||
self.__threads.append(thr)
|
self.__threads.append(thr)
|
||||||
|
|
||||||
|
@ -229,13 +241,15 @@ class Updater:
|
||||||
raise
|
raise
|
||||||
self.logger.debug('{} - ended'.format(thr_name))
|
self.logger.debug('{} - ended'.format(thr_name))
|
||||||
|
|
||||||
def start_polling(self,
|
def start_polling(
|
||||||
poll_interval: float = 0.0,
|
self,
|
||||||
timeout: float = 10,
|
poll_interval: float = 0.0,
|
||||||
clean: bool = False,
|
timeout: float = 10,
|
||||||
bootstrap_retries: int = -1,
|
clean: bool = False,
|
||||||
read_latency: float = 2.,
|
bootstrap_retries: int = -1,
|
||||||
allowed_updates: List[str] = None) -> Optional[Queue]:
|
read_latency: float = 2.0,
|
||||||
|
allowed_updates: List[str] = None,
|
||||||
|
) -> Optional[Queue]:
|
||||||
"""Starts polling updates from Telegram.
|
"""Starts polling updates from Telegram.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -270,9 +284,17 @@ class Updater:
|
||||||
dispatcher_ready = Event()
|
dispatcher_ready = Event()
|
||||||
polling_ready = Event()
|
polling_ready = Event()
|
||||||
self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready)
|
self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready)
|
||||||
self._init_thread(self._start_polling, "updater", poll_interval, timeout,
|
self._init_thread(
|
||||||
read_latency, bootstrap_retries, clean, allowed_updates,
|
self._start_polling,
|
||||||
ready=polling_ready)
|
"updater",
|
||||||
|
poll_interval,
|
||||||
|
timeout,
|
||||||
|
read_latency,
|
||||||
|
bootstrap_retries,
|
||||||
|
clean,
|
||||||
|
allowed_updates,
|
||||||
|
ready=polling_ready,
|
||||||
|
)
|
||||||
|
|
||||||
self.logger.debug('Waiting for Dispatcher and polling to start')
|
self.logger.debug('Waiting for Dispatcher and polling to start')
|
||||||
dispatcher_ready.wait()
|
dispatcher_ready.wait()
|
||||||
|
@ -282,17 +304,19 @@ class Updater:
|
||||||
return self.update_queue
|
return self.update_queue
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def start_webhook(self,
|
def start_webhook(
|
||||||
listen: str = '127.0.0.1',
|
self,
|
||||||
port: int = 80,
|
listen: str = '127.0.0.1',
|
||||||
url_path: str = '',
|
port: int = 80,
|
||||||
cert: str = None,
|
url_path: str = '',
|
||||||
key: str = None,
|
cert: str = None,
|
||||||
clean: bool = False,
|
key: str = None,
|
||||||
bootstrap_retries: int = 0,
|
clean: bool = False,
|
||||||
webhook_url: str = None,
|
bootstrap_retries: int = 0,
|
||||||
allowed_updates: List[str] = None,
|
webhook_url: str = None,
|
||||||
force_event_loop: bool = False) -> Optional[Queue]:
|
allowed_updates: List[str] = None,
|
||||||
|
force_event_loop: bool = False,
|
||||||
|
) -> Optional[Queue]:
|
||||||
"""
|
"""
|
||||||
Starts a small http server to listen for updates via webhook. If cert
|
Starts a small http server to listen for updates via webhook. If cert
|
||||||
and key are not provided, the webhook will be started directly on
|
and key are not provided, the webhook will be started directly on
|
||||||
|
@ -344,9 +368,21 @@ class Updater:
|
||||||
dispatcher_ready = Event()
|
dispatcher_ready = Event()
|
||||||
self.job_queue.start()
|
self.job_queue.start()
|
||||||
self._init_thread(self.dispatcher.start, "dispatcher", dispatcher_ready)
|
self._init_thread(self.dispatcher.start, "dispatcher", dispatcher_ready)
|
||||||
self._init_thread(self._start_webhook, "updater", listen, port, url_path, cert,
|
self._init_thread(
|
||||||
key, bootstrap_retries, clean, webhook_url, allowed_updates,
|
self._start_webhook,
|
||||||
ready=webhook_ready, force_event_loop=force_event_loop)
|
"updater",
|
||||||
|
listen,
|
||||||
|
port,
|
||||||
|
url_path,
|
||||||
|
cert,
|
||||||
|
key,
|
||||||
|
bootstrap_retries,
|
||||||
|
clean,
|
||||||
|
webhook_url,
|
||||||
|
allowed_updates,
|
||||||
|
ready=webhook_ready,
|
||||||
|
force_event_loop=force_event_loop,
|
||||||
|
)
|
||||||
|
|
||||||
self.logger.debug('Waiting for Dispatcher and Webhook to start')
|
self.logger.debug('Waiting for Dispatcher and Webhook to start')
|
||||||
webhook_ready.wait()
|
webhook_ready.wait()
|
||||||
|
@ -357,8 +393,16 @@ class Updater:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _start_polling(self, poll_interval, timeout, read_latency, bootstrap_retries, clean,
|
def _start_polling(
|
||||||
allowed_updates, ready=None): # pragma: no cover
|
self,
|
||||||
|
poll_interval,
|
||||||
|
timeout,
|
||||||
|
read_latency,
|
||||||
|
bootstrap_retries,
|
||||||
|
clean,
|
||||||
|
allowed_updates,
|
||||||
|
ready=None,
|
||||||
|
): # pragma: no cover
|
||||||
# Thread target of thread 'updater'. Runs in background, pulls
|
# Thread target of thread 'updater'. Runs in background, pulls
|
||||||
# updates from Telegram and inserts them in the update queue of the
|
# updates from Telegram and inserts them in the update queue of the
|
||||||
# Dispatcher.
|
# Dispatcher.
|
||||||
|
@ -370,10 +414,12 @@ class Updater:
|
||||||
self.logger.debug('Bootstrap done')
|
self.logger.debug('Bootstrap done')
|
||||||
|
|
||||||
def polling_action_cb():
|
def polling_action_cb():
|
||||||
updates = self.bot.get_updates(self.last_update_id,
|
updates = self.bot.get_updates(
|
||||||
timeout=timeout,
|
self.last_update_id,
|
||||||
read_latency=read_latency,
|
timeout=timeout,
|
||||||
allowed_updates=allowed_updates)
|
read_latency=read_latency,
|
||||||
|
allowed_updates=allowed_updates,
|
||||||
|
)
|
||||||
|
|
||||||
if updates:
|
if updates:
|
||||||
if not self.running:
|
if not self.running:
|
||||||
|
@ -393,8 +439,9 @@ class Updater:
|
||||||
if ready is not None:
|
if ready is not None:
|
||||||
ready.set()
|
ready.set()
|
||||||
|
|
||||||
self._network_loop_retry(polling_action_cb, polling_onerr_cb, 'getting Updates',
|
self._network_loop_retry(
|
||||||
poll_interval)
|
polling_action_cb, polling_onerr_cb, 'getting Updates', poll_interval
|
||||||
|
)
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _network_loop_retry(self, action_cb, onerr_cb, description, interval):
|
def _network_loop_retry(self, action_cb, onerr_cb, description, interval):
|
||||||
|
@ -450,8 +497,20 @@ class Updater:
|
||||||
return current_interval
|
return current_interval
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _start_webhook(self, listen, port, url_path, cert, key, bootstrap_retries, clean,
|
def _start_webhook(
|
||||||
webhook_url, allowed_updates, ready=None, force_event_loop=False):
|
self,
|
||||||
|
listen,
|
||||||
|
port,
|
||||||
|
url_path,
|
||||||
|
cert,
|
||||||
|
key,
|
||||||
|
bootstrap_retries,
|
||||||
|
clean,
|
||||||
|
webhook_url,
|
||||||
|
allowed_updates,
|
||||||
|
ready=None,
|
||||||
|
force_event_loop=False,
|
||||||
|
):
|
||||||
self.logger.debug('Updater thread started (webhook)')
|
self.logger.debug('Updater thread started (webhook)')
|
||||||
use_ssl = cert is not None and key is not None
|
use_ssl = cert is not None and key is not None
|
||||||
if not url_path.startswith('/'):
|
if not url_path.startswith('/'):
|
||||||
|
@ -479,14 +538,18 @@ class Updater:
|
||||||
if not webhook_url:
|
if not webhook_url:
|
||||||
webhook_url = self._gen_webhook_url(listen, port, url_path)
|
webhook_url = self._gen_webhook_url(listen, port, url_path)
|
||||||
|
|
||||||
self._bootstrap(max_retries=bootstrap_retries,
|
self._bootstrap(
|
||||||
clean=clean,
|
max_retries=bootstrap_retries,
|
||||||
webhook_url=webhook_url,
|
clean=clean,
|
||||||
cert=open(cert, 'rb'),
|
webhook_url=webhook_url,
|
||||||
allowed_updates=allowed_updates)
|
cert=open(cert, 'rb'),
|
||||||
|
allowed_updates=allowed_updates,
|
||||||
|
)
|
||||||
elif clean:
|
elif clean:
|
||||||
self.logger.warning("cleaning updates is not supported if "
|
self.logger.warning(
|
||||||
"SSL-termination happens elsewhere; skipping")
|
"cleaning updates is not supported if "
|
||||||
|
"SSL-termination happens elsewhere; skipping"
|
||||||
|
)
|
||||||
|
|
||||||
self.httpd.serve_forever(force_event_loop=force_event_loop, ready=ready)
|
self.httpd.serve_forever(force_event_loop=force_event_loop, ready=ready)
|
||||||
|
|
||||||
|
@ -495,13 +558,9 @@ class Updater:
|
||||||
return 'https://{listen}:{port}{path}'.format(listen=listen, port=port, path=url_path)
|
return 'https://{listen}:{port}{path}'.format(listen=listen, port=port, path=url_path)
|
||||||
|
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _bootstrap(self,
|
def _bootstrap(
|
||||||
max_retries,
|
self, max_retries, clean, webhook_url, allowed_updates, cert=None, bootstrap_interval=5
|
||||||
clean,
|
):
|
||||||
webhook_url,
|
|
||||||
allowed_updates,
|
|
||||||
cert=None,
|
|
||||||
bootstrap_interval=5):
|
|
||||||
retries = [0]
|
retries = [0]
|
||||||
|
|
||||||
def bootstrap_del_webhook():
|
def bootstrap_del_webhook():
|
||||||
|
@ -516,16 +575,17 @@ class Updater:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def bootstrap_set_webhook():
|
def bootstrap_set_webhook():
|
||||||
self.bot.set_webhook(url=webhook_url,
|
self.bot.set_webhook(
|
||||||
certificate=cert,
|
url=webhook_url, certificate=cert, allowed_updates=allowed_updates
|
||||||
allowed_updates=allowed_updates)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def bootstrap_onerr_cb(exc):
|
def bootstrap_onerr_cb(exc):
|
||||||
if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries):
|
if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries):
|
||||||
retries[0] += 1
|
retries[0] += 1
|
||||||
self.logger.warning('Failed bootstrap phase; try=%s max_retries=%s', retries[0],
|
self.logger.warning(
|
||||||
max_retries)
|
'Failed bootstrap phase; try=%s max_retries=%s', retries[0], max_retries
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc)
|
self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc)
|
||||||
raise exc
|
raise exc
|
||||||
|
@ -535,22 +595,34 @@ class Updater:
|
||||||
# We also take this chance to delete pre-configured webhook if this is a polling Updater.
|
# We also take this chance to delete pre-configured webhook if this is a polling Updater.
|
||||||
# NOTE: We don't know ahead if a webhook is configured, so we just delete.
|
# NOTE: We don't know ahead if a webhook is configured, so we just delete.
|
||||||
if clean or not webhook_url:
|
if clean or not webhook_url:
|
||||||
self._network_loop_retry(bootstrap_del_webhook, bootstrap_onerr_cb,
|
self._network_loop_retry(
|
||||||
'bootstrap del webhook', bootstrap_interval)
|
bootstrap_del_webhook,
|
||||||
|
bootstrap_onerr_cb,
|
||||||
|
'bootstrap del webhook',
|
||||||
|
bootstrap_interval,
|
||||||
|
)
|
||||||
retries[0] = 0
|
retries[0] = 0
|
||||||
|
|
||||||
# Clean pending messages, if requested.
|
# Clean pending messages, if requested.
|
||||||
if clean:
|
if clean:
|
||||||
self._network_loop_retry(bootstrap_clean_updates, bootstrap_onerr_cb,
|
self._network_loop_retry(
|
||||||
'bootstrap clean updates', bootstrap_interval)
|
bootstrap_clean_updates,
|
||||||
|
bootstrap_onerr_cb,
|
||||||
|
'bootstrap clean updates',
|
||||||
|
bootstrap_interval,
|
||||||
|
)
|
||||||
retries[0] = 0
|
retries[0] = 0
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
# Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set,
|
# Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set,
|
||||||
# so we set it anyhow.
|
# so we set it anyhow.
|
||||||
if webhook_url:
|
if webhook_url:
|
||||||
self._network_loop_retry(bootstrap_set_webhook, bootstrap_onerr_cb,
|
self._network_loop_retry(
|
||||||
'bootstrap set webhook', bootstrap_interval)
|
bootstrap_set_webhook,
|
||||||
|
bootstrap_onerr_cb,
|
||||||
|
'bootstrap set webhook',
|
||||||
|
bootstrap_interval,
|
||||||
|
)
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
"""Stops the polling/webhook thread, the dispatcher and the job queue."""
|
"""Stops the polling/webhook thread, the dispatcher and the job queue."""
|
||||||
|
@ -573,9 +645,11 @@ class Updater:
|
||||||
@no_type_check
|
@no_type_check
|
||||||
def _stop_httpd(self) -> None:
|
def _stop_httpd(self) -> None:
|
||||||
if self.httpd:
|
if self.httpd:
|
||||||
self.logger.debug('Waiting for current webhook connection to be '
|
self.logger.debug(
|
||||||
'closed... Send a Telegram message to the bot to exit '
|
'Waiting for current webhook connection to be '
|
||||||
'immediately.')
|
'closed... Send a Telegram message to the bot to exit '
|
||||||
|
'immediately.'
|
||||||
|
)
|
||||||
self.httpd.shutdown()
|
self.httpd.shutdown()
|
||||||
self.httpd = None
|
self.httpd = None
|
||||||
|
|
||||||
|
@ -596,8 +670,9 @@ class Updater:
|
||||||
def signal_handler(self, signum, frame) -> None:
|
def signal_handler(self, signum, frame) -> None:
|
||||||
self.is_idle = False
|
self.is_idle = False
|
||||||
if self.running:
|
if self.running:
|
||||||
self.logger.info('Received signal {} ({}), stopping...'.format(
|
self.logger.info(
|
||||||
signum, get_signal_name(signum)))
|
'Received signal {} ({}), stopping...'.format(signum, get_signal_name(signum))
|
||||||
|
)
|
||||||
if self.persistence:
|
if self.persistence:
|
||||||
# Update user_data, chat_data and bot_data before flushing
|
# Update user_data, chat_data and bot_data before flushing
|
||||||
self.dispatcher.update_persistence()
|
self.dispatcher.update_persistence()
|
||||||
|
@ -608,6 +683,7 @@ class Updater:
|
||||||
else:
|
else:
|
||||||
self.logger.warning('Exiting immediately!')
|
self.logger.warning('Exiting immediately!')
|
||||||
import os
|
import os
|
||||||
|
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
def idle(self, stop_signals: Union[List, Tuple] = (SIGINT, SIGTERM, SIGABRT)) -> None:
|
def idle(self, stop_signals: Union[List, Tuple] = (SIGINT, SIGTERM, SIGABRT)) -> None:
|
||||||
|
|
|
@ -22,6 +22,7 @@ from telegram import TelegramObject
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -64,18 +65,20 @@ class Animation(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
width: int,
|
file_unique_id: str,
|
||||||
height: int,
|
width: int,
|
||||||
duration: int,
|
height: int,
|
||||||
thumb: PhotoSize = None,
|
duration: int,
|
||||||
file_name: str = None,
|
thumb: PhotoSize = None,
|
||||||
mime_type: str = None,
|
file_name: str = None,
|
||||||
file_size: int = None,
|
mime_type: str = None,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -22,6 +22,7 @@ from telegram import TelegramObject, PhotoSize
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -65,17 +66,19 @@ class Audio(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
duration: int,
|
file_unique_id: str,
|
||||||
performer: str = None,
|
duration: int,
|
||||||
title: str = None,
|
performer: str = None,
|
||||||
mime_type: str = None,
|
title: str = None,
|
||||||
file_size: int = None,
|
mime_type: str = None,
|
||||||
thumb: PhotoSize = None,
|
file_size: int = None,
|
||||||
bot: 'Bot' = None,
|
thumb: PhotoSize = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
from telegram import TelegramObject
|
from telegram import TelegramObject
|
||||||
|
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -61,13 +62,15 @@ class ChatPhoto(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
small_file_id: str,
|
self,
|
||||||
small_file_unique_id: str,
|
small_file_id: str,
|
||||||
big_file_id: str,
|
small_file_unique_id: str,
|
||||||
big_file_unique_id: str,
|
big_file_id: str,
|
||||||
bot: 'Bot' = None,
|
big_file_unique_id: str,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
self.small_file_id = small_file_id
|
self.small_file_id = small_file_id
|
||||||
self.small_file_unique_id = small_file_unique_id
|
self.small_file_unique_id = small_file_unique_id
|
||||||
self.big_file_id = big_file_id
|
self.big_file_id = big_file_id
|
||||||
|
@ -75,7 +78,10 @@ class ChatPhoto(TelegramObject):
|
||||||
|
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
self._id_attrs = (self.small_file_unique_id, self.big_file_unique_id,)
|
self._id_attrs = (
|
||||||
|
self.small_file_unique_id,
|
||||||
|
self.big_file_unique_id,
|
||||||
|
)
|
||||||
|
|
||||||
def get_small_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
def get_small_file(self, timeout: int = None, **kwargs: Any) -> 'File':
|
||||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||||
|
|
|
@ -45,13 +45,15 @@ class Contact(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
phone_number: str,
|
self,
|
||||||
first_name: str,
|
phone_number: str,
|
||||||
last_name: str = None,
|
first_name: str,
|
||||||
user_id: int = None,
|
last_name: str = None,
|
||||||
vcard: str = None,
|
user_id: int = None,
|
||||||
**kwargs: Any):
|
vcard: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.phone_number = str(phone_number)
|
self.phone_number = str(phone_number)
|
||||||
self.first_name = first_name
|
self.first_name = first_name
|
||||||
|
|
|
@ -22,6 +22,7 @@ from telegram import PhotoSize, TelegramObject
|
||||||
|
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -57,17 +58,20 @@ class Document(TelegramObject):
|
||||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_id_keys = ('file_id',)
|
_id_keys = ('file_id',)
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
thumb: PhotoSize = None,
|
file_unique_id: str,
|
||||||
file_name: str = None,
|
thumb: PhotoSize = None,
|
||||||
mime_type: str = None,
|
file_name: str = None,
|
||||||
file_size: int = None,
|
mime_type: str = None,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -27,6 +27,7 @@ from telegram import TelegramObject
|
||||||
from telegram.passport.credentials import decrypt
|
from telegram.passport.credentials import decrypt
|
||||||
|
|
||||||
from typing import Any, Optional, IO, Union, TYPE_CHECKING
|
from typing import Any, Optional, IO, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, FileCredentials
|
from telegram import Bot, FileCredentials
|
||||||
|
|
||||||
|
@ -68,13 +69,15 @@ class File(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
bot: 'Bot' = None,
|
file_unique_id: str,
|
||||||
file_size: int = None,
|
bot: 'Bot' = None,
|
||||||
file_path: str = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
file_path: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
@ -86,10 +89,9 @@ class File(TelegramObject):
|
||||||
|
|
||||||
self._id_attrs = (self.file_unique_id,)
|
self._id_attrs = (self.file_unique_id,)
|
||||||
|
|
||||||
def download(self,
|
def download(
|
||||||
custom_path: str = None,
|
self, custom_path: str = None, out: IO = None, timeout: int = None
|
||||||
out: IO = None,
|
) -> Union[str, IO]:
|
||||||
timeout: int = None) -> Union[str, IO]:
|
|
||||||
"""
|
"""
|
||||||
Download this file. By default, the file is saved in the current working directory with its
|
Download this file. By default, the file is saved in the current working directory with its
|
||||||
original filename as reported by Telegram. If the file has no filename, it the file ID will
|
original filename as reported by Telegram. If the file has no filename, it the file ID will
|
||||||
|
@ -125,9 +127,9 @@ class File(TelegramObject):
|
||||||
if out:
|
if out:
|
||||||
buf = self.bot.request.retrieve(url)
|
buf = self.bot.request.retrieve(url)
|
||||||
if self._credentials:
|
if self._credentials:
|
||||||
buf = decrypt(b64decode(self._credentials.secret),
|
buf = decrypt(
|
||||||
b64decode(self._credentials.hash),
|
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
|
||||||
buf)
|
)
|
||||||
out.write(buf)
|
out.write(buf)
|
||||||
return out
|
return out
|
||||||
else:
|
else:
|
||||||
|
@ -140,9 +142,9 @@ class File(TelegramObject):
|
||||||
|
|
||||||
buf = self.bot.request.retrieve(url, timeout=timeout)
|
buf = self.bot.request.retrieve(url, timeout=timeout)
|
||||||
if self._credentials:
|
if self._credentials:
|
||||||
buf = decrypt(b64decode(self._credentials.secret),
|
buf = decrypt(
|
||||||
b64decode(self._credentials.hash),
|
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
|
||||||
buf)
|
)
|
||||||
with open(filename, 'wb') as fobj:
|
with open(filename, 'wb') as fobj:
|
||||||
fobj.write(buf)
|
fobj.write(buf)
|
||||||
return filename
|
return filename
|
||||||
|
@ -150,8 +152,11 @@ class File(TelegramObject):
|
||||||
def _get_encoded_url(self) -> str:
|
def _get_encoded_url(self) -> str:
|
||||||
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
|
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
|
||||||
sres = urllib_parse.urlsplit(self.file_path)
|
sres = urllib_parse.urlsplit(self.file_path)
|
||||||
return urllib_parse.urlunsplit(urllib_parse.SplitResult(
|
return urllib_parse.urlunsplit(
|
||||||
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment))
|
urllib_parse.SplitResult(
|
||||||
|
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def download_as_bytearray(self, buf: bytearray = None) -> bytes:
|
def download_as_bytearray(self, buf: bytearray = None) -> bytes:
|
||||||
"""Download this file and return it as a bytearray.
|
"""Download this file and return it as a bytearray.
|
||||||
|
|
|
@ -57,15 +57,14 @@ class InputFile:
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
elif (hasattr(obj, 'name') and not isinstance(obj.name, int)):
|
elif hasattr(obj, 'name') and not isinstance(obj.name, int):
|
||||||
self.filename = os.path.basename(obj.name)
|
self.filename = os.path.basename(obj.name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.mimetype = self.is_image(self.input_file_content)
|
self.mimetype = self.is_image(self.input_file_content)
|
||||||
except TelegramError:
|
except TelegramError:
|
||||||
if self.filename:
|
if self.filename:
|
||||||
self.mimetype = mimetypes.guess_type(
|
self.mimetype = mimetypes.guess_type(self.filename)[0] or DEFAULT_MIME_TYPE
|
||||||
self.filename)[0] or DEFAULT_MIME_TYPE
|
|
||||||
else:
|
else:
|
||||||
self.mimetype = DEFAULT_MIME_TYPE
|
self.mimetype = DEFAULT_MIME_TYPE
|
||||||
if not self.filename:
|
if not self.filename:
|
||||||
|
|
|
@ -34,6 +34,7 @@ class InputMedia(TelegramObject):
|
||||||
:class:`telegram.InputMediaVideo` for detailed use.
|
:class:`telegram.InputMediaVideo` for detailed use.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,14 +77,16 @@ class InputMediaAnimation(InputMedia):
|
||||||
arguments.
|
arguments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
media: Union[str, FileLike, Animation],
|
self,
|
||||||
thumb: FileLike = None,
|
media: Union[str, FileLike, Animation],
|
||||||
caption: str = None,
|
thumb: FileLike = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
caption: str = None,
|
||||||
width: int = None,
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
height: int = None,
|
width: int = None,
|
||||||
duration: int = None):
|
height: int = None,
|
||||||
|
duration: int = None,
|
||||||
|
):
|
||||||
self.type = 'animation'
|
self.type = 'animation'
|
||||||
|
|
||||||
if isinstance(media, Animation):
|
if isinstance(media, Animation):
|
||||||
|
@ -136,10 +139,12 @@ class InputMediaPhoto(InputMedia):
|
||||||
in :class:`telegram.ParseMode` for the available modes.
|
in :class:`telegram.ParseMode` for the available modes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
media: Union[str, FileLike, PhotoSize],
|
self,
|
||||||
caption: str = None,
|
media: Union[str, FileLike, PhotoSize],
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
caption: str = None,
|
||||||
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
):
|
||||||
self.type = 'photo'
|
self.type = 'photo'
|
||||||
|
|
||||||
if isinstance(media, PhotoSize):
|
if isinstance(media, PhotoSize):
|
||||||
|
@ -200,15 +205,17 @@ class InputMediaVideo(InputMedia):
|
||||||
by Telegram.
|
by Telegram.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
media: Union[str, FileLike, Video],
|
self,
|
||||||
caption: str = None,
|
media: Union[str, FileLike, Video],
|
||||||
width: int = None,
|
caption: str = None,
|
||||||
height: int = None,
|
width: int = None,
|
||||||
duration: int = None,
|
height: int = None,
|
||||||
supports_streaming: bool = None,
|
duration: int = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
supports_streaming: bool = None,
|
||||||
thumb: FileLike = None):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
thumb: FileLike = None,
|
||||||
|
):
|
||||||
self.type = 'video'
|
self.type = 'video'
|
||||||
|
|
||||||
if isinstance(media, Video):
|
if isinstance(media, Video):
|
||||||
|
@ -282,14 +289,16 @@ class InputMediaAudio(InputMedia):
|
||||||
optional arguments.
|
optional arguments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
media: Union[str, FileLike, Audio],
|
self,
|
||||||
thumb: FileLike = None,
|
media: Union[str, FileLike, Audio],
|
||||||
caption: str = None,
|
thumb: FileLike = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
caption: str = None,
|
||||||
duration: int = None,
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
performer: str = None,
|
duration: int = None,
|
||||||
title: str = None):
|
performer: str = None,
|
||||||
|
title: str = None,
|
||||||
|
):
|
||||||
self.type = 'audio'
|
self.type = 'audio'
|
||||||
|
|
||||||
if isinstance(media, Audio):
|
if isinstance(media, Audio):
|
||||||
|
@ -348,11 +357,13 @@ class InputMediaDocument(InputMedia):
|
||||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
media: Union[str, FileLike, Document],
|
self,
|
||||||
thumb: FileLike = None,
|
media: Union[str, FileLike, Document],
|
||||||
caption: str = None,
|
thumb: FileLike = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
caption: str = None,
|
||||||
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
):
|
||||||
self.type = 'document'
|
self.type = 'document'
|
||||||
|
|
||||||
if isinstance(media, Document):
|
if isinstance(media, Document):
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import TelegramObject
|
from telegram import TelegramObject
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -55,14 +56,16 @@ class PhotoSize(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
width: int,
|
file_unique_id: str,
|
||||||
height: int,
|
width: int,
|
||||||
file_size: int = None,
|
height: int,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import PhotoSize, TelegramObject
|
from telegram import PhotoSize, TelegramObject
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, List, TYPE_CHECKING
|
from typing import Any, Optional, List, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -71,19 +72,21 @@ class Sticker(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
width: int,
|
file_unique_id: str,
|
||||||
height: int,
|
width: int,
|
||||||
is_animated: bool,
|
height: int,
|
||||||
thumb: PhotoSize = None,
|
is_animated: bool,
|
||||||
emoji: str = None,
|
thumb: PhotoSize = None,
|
||||||
file_size: int = None,
|
emoji: str = None,
|
||||||
set_name: str = None,
|
file_size: int = None,
|
||||||
mask_position: 'MaskPosition' = None,
|
set_name: str = None,
|
||||||
bot: 'Bot' = None,
|
mask_position: 'MaskPosition' = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
@ -158,15 +161,17 @@ class StickerSet(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
name: str,
|
self,
|
||||||
title: str,
|
name: str,
|
||||||
is_animated: bool,
|
title: str,
|
||||||
contains_masks: bool,
|
is_animated: bool,
|
||||||
stickers: List[Sticker],
|
contains_masks: bool,
|
||||||
bot: 'Bot' = None,
|
stickers: List[Sticker],
|
||||||
thumb: PhotoSize = None,
|
bot: 'Bot' = None,
|
||||||
**kwargs: Any):
|
thumb: PhotoSize = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.title = title
|
self.title = title
|
||||||
self.is_animated = is_animated
|
self.is_animated = is_animated
|
||||||
|
@ -227,6 +232,7 @@ class MaskPosition(TelegramObject):
|
||||||
scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size.
|
scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
FOREHEAD: str = 'forehead'
|
FOREHEAD: str = 'forehead'
|
||||||
""":obj:`str`: 'forehead'"""
|
""":obj:`str`: 'forehead'"""
|
||||||
EYES: str = 'eyes'
|
EYES: str = 'eyes'
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import TelegramObject, Location
|
from telegram import TelegramObject, Location
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -50,13 +51,15 @@ class Venue(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
location: Location,
|
self,
|
||||||
title: str,
|
location: Location,
|
||||||
address: str,
|
title: str,
|
||||||
foursquare_id: str = None,
|
address: str,
|
||||||
foursquare_type: str = None,
|
foursquare_id: str = None,
|
||||||
**kwargs: Any):
|
foursquare_type: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.location = location
|
self.location = location
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import PhotoSize, TelegramObject
|
from telegram import PhotoSize, TelegramObject
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -61,17 +62,19 @@ class Video(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
width: int,
|
file_unique_id: str,
|
||||||
height: int,
|
width: int,
|
||||||
duration: int,
|
height: int,
|
||||||
thumb: PhotoSize = None,
|
duration: int,
|
||||||
mime_type: str = None,
|
thumb: PhotoSize = None,
|
||||||
file_size: int = None,
|
mime_type: str = None,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import PhotoSize, TelegramObject
|
from telegram import PhotoSize, TelegramObject
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -58,15 +59,17 @@ class VideoNote(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
length: int,
|
file_unique_id: str,
|
||||||
duration: int,
|
length: int,
|
||||||
thumb: PhotoSize = None,
|
duration: int,
|
||||||
file_size: int = None,
|
thumb: PhotoSize = None,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import TelegramObject
|
from telegram import TelegramObject
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot, File
|
from telegram import Bot, File
|
||||||
|
|
||||||
|
@ -55,14 +56,16 @@ class Voice(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
file_id: str,
|
self,
|
||||||
file_unique_id: str,
|
file_id: str,
|
||||||
duration: int,
|
file_unique_id: str,
|
||||||
mime_type: str = None,
|
duration: int,
|
||||||
file_size: int = None,
|
mime_type: str = None,
|
||||||
bot: 'Bot' = None,
|
file_size: int = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.file_id = str(file_id)
|
self.file_id = str(file_id)
|
||||||
self.file_unique_id = str(file_unique_id)
|
self.file_unique_id = str(file_unique_id)
|
||||||
|
|
|
@ -23,6 +23,7 @@ import sys
|
||||||
from telegram import MessageEntity, TelegramObject, Animation, PhotoSize
|
from telegram import MessageEntity, TelegramObject, Animation, PhotoSize
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import List, Any, Dict, Optional, TYPE_CHECKING
|
from typing import List, Any, Dict, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -66,14 +67,16 @@ class Game(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
title: str,
|
self,
|
||||||
description: str,
|
title: str,
|
||||||
photo: List[PhotoSize],
|
description: str,
|
||||||
text: str = None,
|
photo: List[PhotoSize],
|
||||||
text_entities: List[MessageEntity] = None,
|
text: str = None,
|
||||||
animation: Animation = None,
|
text_entities: List[MessageEntity] = None,
|
||||||
**kwargs: Any):
|
animation: Animation = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.title = title
|
self.title = title
|
||||||
self.description = description
|
self.description = description
|
||||||
|
@ -130,11 +133,11 @@ class Game(TelegramObject):
|
||||||
raise RuntimeError("This Game has no 'text'.")
|
raise RuntimeError("This Game has no 'text'.")
|
||||||
|
|
||||||
# Is it a narrow build, if so we don't need to convert
|
# Is it a narrow build, if so we don't need to convert
|
||||||
if sys.maxunicode == 0xffff:
|
if sys.maxunicode == 0xFFFF:
|
||||||
return self.text[entity.offset:entity.offset + entity.length]
|
return self.text[entity.offset : entity.offset + entity.length]
|
||||||
else:
|
else:
|
||||||
entity_text = self.text.encode('utf-16-le')
|
entity_text = self.text.encode('utf-16-le')
|
||||||
entity_text = entity_text[entity.offset * 2:(entity.offset + entity.length) * 2]
|
entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2]
|
||||||
|
|
||||||
return entity_text.decode('utf-16-le')
|
return entity_text.decode('utf-16-le')
|
||||||
|
|
||||||
|
@ -164,7 +167,8 @@ class Game(TelegramObject):
|
||||||
|
|
||||||
return {
|
return {
|
||||||
entity: self.parse_text_entity(entity)
|
entity: self.parse_text_entity(entity)
|
||||||
for entity in (self.text_entities or []) if entity.type in types
|
for entity in (self.text_entities or [])
|
||||||
|
if entity.type in types
|
||||||
}
|
}
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import TelegramObject, User
|
from telegram import TelegramObject, User
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import TelegramObject
|
from telegram import TelegramObject
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import CallbackGame, LoginUrl
|
from telegram import CallbackGame, LoginUrl
|
||||||
|
|
||||||
|
@ -81,16 +82,18 @@ class InlineKeyboardButton(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
text: str,
|
self,
|
||||||
url: str = None,
|
text: str,
|
||||||
callback_data: str = None,
|
url: str = None,
|
||||||
switch_inline_query: str = None,
|
callback_data: str = None,
|
||||||
switch_inline_query_current_chat: str = None,
|
switch_inline_query: str = None,
|
||||||
callback_game: 'CallbackGame' = None,
|
switch_inline_query_current_chat: str = None,
|
||||||
pay: bool = None,
|
callback_game: 'CallbackGame' = None,
|
||||||
login_url: 'LoginUrl' = None,
|
pay: bool = None,
|
||||||
**kwargs: Any):
|
login_url: 'LoginUrl' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.text = text
|
self.text = text
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import ReplyMarkup, InlineKeyboardButton
|
from telegram import ReplyMarkup, InlineKeyboardButton
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, List, Optional, TYPE_CHECKING
|
from typing import Any, List, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -57,8 +58,7 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def de_json(cls, data: Optional[JSONDict],
|
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineKeyboardMarkup']:
|
||||||
bot: 'Bot') -> Optional['InlineKeyboardMarkup']:
|
|
||||||
data = cls.parse_data(data)
|
data = cls.parse_data(data)
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
|
@ -91,8 +91,9 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
||||||
return cls([[button]], **kwargs)
|
return cls([[button]], **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_row(cls, button_row: List[InlineKeyboardButton],
|
def from_row(
|
||||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
cls, button_row: List[InlineKeyboardButton], **kwargs: Any
|
||||||
|
) -> 'InlineKeyboardMarkup':
|
||||||
"""Shortcut for::
|
"""Shortcut for::
|
||||||
|
|
||||||
InlineKeyboardMarkup([button_row], **kwargs)
|
InlineKeyboardMarkup([button_row], **kwargs)
|
||||||
|
@ -108,8 +109,9 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
||||||
return cls([button_row], **kwargs)
|
return cls([button_row], **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_column(cls, button_column: List[InlineKeyboardButton],
|
def from_column(
|
||||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
cls, button_column: List[InlineKeyboardButton], **kwargs: Any
|
||||||
|
) -> 'InlineKeyboardMarkup':
|
||||||
"""Shortcut for::
|
"""Shortcut for::
|
||||||
|
|
||||||
InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
|
InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
from telegram import TelegramObject, User, Location
|
from telegram import TelegramObject, User, Location
|
||||||
from telegram.utils.types import JSONDict
|
from telegram.utils.types import JSONDict
|
||||||
from typing import Any, Optional, TYPE_CHECKING
|
from typing import Any, Optional, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
|
|
||||||
|
@ -57,14 +58,16 @@ class InlineQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
from_user: User,
|
id: str,
|
||||||
query: str,
|
from_user: User,
|
||||||
offset: str,
|
query: str,
|
||||||
location: Location = None,
|
offset: str,
|
||||||
bot: 'Bot' = None,
|
location: Location = None,
|
||||||
**kwargs: Any):
|
bot: 'Bot' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.id = id
|
self.id = id
|
||||||
self.from_user = from_user
|
self.from_user = from_user
|
||||||
|
@ -125,8 +128,5 @@ class InlineQuery(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.bot.answer_inline_query(
|
return self.bot.answer_inline_query(
|
||||||
self.id,
|
self.id, *args, current_offset=self.offset if auto_pagination else None, **kwargs
|
||||||
*args,
|
|
||||||
current_offset=self.offset if auto_pagination else None,
|
|
||||||
**kwargs
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -61,18 +62,20 @@ class InlineQueryResultArticle(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
title: str,
|
id: str,
|
||||||
input_message_content: 'InputMessageContent',
|
title: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
input_message_content: 'InputMessageContent',
|
||||||
url: str = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
hide_url: bool = None,
|
url: str = None,
|
||||||
description: str = None,
|
hide_url: bool = None,
|
||||||
thumb_url: str = None,
|
description: str = None,
|
||||||
thumb_width: int = None,
|
thumb_url: str = None,
|
||||||
thumb_height: int = None,
|
thumb_width: int = None,
|
||||||
**kwargs: Any):
|
thumb_height: int = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('article', id)
|
super().__init__('article', id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -65,17 +66,19 @@ class InlineQueryResultAudio(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
audio_url: str,
|
id: str,
|
||||||
title: str,
|
audio_url: str,
|
||||||
performer: str = None,
|
title: str,
|
||||||
audio_duration: int = None,
|
performer: str = None,
|
||||||
caption: str = None,
|
audio_duration: int = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('audio', id)
|
super().__init__('audio', id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -59,14 +60,16 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
audio_file_id: str,
|
id: str,
|
||||||
caption: str = None,
|
audio_file_id: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('audio', id)
|
super().__init__('audio', id)
|
||||||
self.audio_file_id = audio_file_id
|
self.audio_file_id = audio_file_id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -65,16 +66,18 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
title: str,
|
id: str,
|
||||||
document_file_id: str,
|
title: str,
|
||||||
description: str = None,
|
document_file_id: str,
|
||||||
caption: str = None,
|
description: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('document', id)
|
super().__init__('document', id)
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -64,15 +65,17 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
gif_file_id: str,
|
id: str,
|
||||||
title: str = None,
|
gif_file_id: str,
|
||||||
caption: str = None,
|
title: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('gif', id)
|
super().__init__('gif', id)
|
||||||
self.gif_file_id = gif_file_id
|
self.gif_file_id = gif_file_id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -64,15 +65,17 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
mpeg4_file_id: str,
|
id: str,
|
||||||
title: str = None,
|
mpeg4_file_id: str,
|
||||||
caption: str = None,
|
title: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('mpeg4_gif', id)
|
super().__init__('mpeg4_gif', id)
|
||||||
self.mpeg4_file_id = mpeg4_file_id
|
self.mpeg4_file_id = mpeg4_file_id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -66,16 +67,18 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
photo_file_id: str,
|
id: str,
|
||||||
title: str = None,
|
photo_file_id: str,
|
||||||
description: str = None,
|
title: str = None,
|
||||||
caption: str = None,
|
description: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('photo', id)
|
super().__init__('photo', id)
|
||||||
self.photo_file_id = photo_file_id
|
self.photo_file_id = photo_file_id
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import ReplyMarkup, InputMessageContent
|
from telegram import ReplyMarkup, InputMessageContent
|
||||||
|
|
||||||
|
@ -50,12 +51,14 @@ class InlineQueryResultCachedSticker(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
sticker_file_id: str,
|
id: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
sticker_file_id: str,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
**kwargs: Any):
|
input_message_content: 'InputMessageContent' = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('sticker', id)
|
super().__init__('sticker', id)
|
||||||
self.sticker_file_id = sticker_file_id
|
self.sticker_file_id = sticker_file_id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -66,16 +67,18 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
video_file_id: str,
|
id: str,
|
||||||
title: str,
|
video_file_id: str,
|
||||||
description: str = None,
|
title: str,
|
||||||
caption: str = None,
|
description: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('video', id)
|
super().__init__('video', id)
|
||||||
self.video_file_id = video_file_id
|
self.video_file_id = video_file_id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -61,15 +62,17 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
voice_file_id: str,
|
id: str,
|
||||||
title: str,
|
voice_file_id: str,
|
||||||
caption: str = None,
|
title: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('voice', id)
|
super().__init__('voice', id)
|
||||||
self.voice_file_id = voice_file_id
|
self.voice_file_id = voice_file_id
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import ReplyMarkup, InputMessageContent
|
from telegram import ReplyMarkup, InputMessageContent
|
||||||
|
|
||||||
|
@ -64,18 +65,20 @@ class InlineQueryResultContact(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
phone_number: str,
|
id: str,
|
||||||
first_name: str,
|
phone_number: str,
|
||||||
last_name: str = None,
|
first_name: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
last_name: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
thumb_url: str = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
thumb_width: int = None,
|
thumb_url: str = None,
|
||||||
thumb_height: int = None,
|
thumb_width: int = None,
|
||||||
vcard: str = None,
|
thumb_height: int = None,
|
||||||
**kwargs: Any):
|
vcard: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('contact', id)
|
super().__init__('contact', id)
|
||||||
self.phone_number = phone_number
|
self.phone_number = phone_number
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -76,20 +77,22 @@ class InlineQueryResultDocument(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
document_url: str,
|
id: str,
|
||||||
title: str,
|
document_url: str,
|
||||||
mime_type: str,
|
title: str,
|
||||||
caption: str = None,
|
mime_type: str,
|
||||||
description: str = None,
|
caption: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
description: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
thumb_url: str = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
thumb_width: int = None,
|
thumb_url: str = None,
|
||||||
thumb_height: int = None,
|
thumb_width: int = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
thumb_height: int = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('document', id)
|
super().__init__('document', id)
|
||||||
self.document_url = document_url
|
self.document_url = document_url
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import ReplyMarkup
|
from telegram import ReplyMarkup
|
||||||
|
|
||||||
|
@ -43,11 +44,9 @@ class InlineQueryResultGame(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self, id: str, game_short_name: str, reply_markup: 'ReplyMarkup' = None, **kwargs: Any
|
||||||
game_short_name: str,
|
):
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
|
||||||
**kwargs: Any):
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('game', id)
|
super().__init__('game', id)
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -76,20 +77,22 @@ class InlineQueryResultGif(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
gif_url: str,
|
id: str,
|
||||||
thumb_url: str,
|
gif_url: str,
|
||||||
gif_width: int = None,
|
thumb_url: str,
|
||||||
gif_height: int = None,
|
gif_width: int = None,
|
||||||
title: str = None,
|
gif_height: int = None,
|
||||||
caption: str = None,
|
title: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
gif_duration: int = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
gif_duration: int = None,
|
||||||
thumb_mime_type: str = None,
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
**kwargs: Any):
|
thumb_mime_type: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('gif', id)
|
super().__init__('gif', id)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import ReplyMarkup, InputMessageContent
|
from telegram import ReplyMarkup, InputMessageContent
|
||||||
|
|
||||||
|
@ -64,18 +65,20 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
latitude: float,
|
id: str,
|
||||||
longitude: float,
|
latitude: float,
|
||||||
title: str,
|
longitude: float,
|
||||||
live_period: int = None,
|
title: str,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
live_period: int = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
thumb_url: str = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
thumb_width: int = None,
|
thumb_url: str = None,
|
||||||
thumb_height: int = None,
|
thumb_width: int = None,
|
||||||
**kwargs: Any):
|
thumb_height: int = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('location', id)
|
super().__init__('location', id)
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -76,20 +77,22 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
mpeg4_url: str,
|
id: str,
|
||||||
thumb_url: str,
|
mpeg4_url: str,
|
||||||
mpeg4_width: int = None,
|
thumb_url: str,
|
||||||
mpeg4_height: int = None,
|
mpeg4_width: int = None,
|
||||||
title: str = None,
|
mpeg4_height: int = None,
|
||||||
caption: str = None,
|
title: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
mpeg4_duration: int = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
mpeg4_duration: int = None,
|
||||||
thumb_mime_type: str = None,
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
**kwargs: Any):
|
thumb_mime_type: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('mpeg4_gif', id)
|
super().__init__('mpeg4_gif', id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -73,26 +74,28 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
photo_url: str,
|
id: str,
|
||||||
thumb_url: str,
|
photo_url: str,
|
||||||
photo_width: int = None,
|
thumb_url: str,
|
||||||
photo_height: int = None,
|
photo_width: int = None,
|
||||||
title: str = None,
|
photo_height: int = None,
|
||||||
description: str = None,
|
title: str = None,
|
||||||
caption: str = None,
|
description: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
super().__init__('photo', id)
|
super().__init__('photo', id)
|
||||||
self.photo_url = photo_url
|
self.photo_url = photo_url
|
||||||
self.thumb_url = thumb_url
|
self.thumb_url = thumb_url
|
||||||
|
|
||||||
# Optionals
|
# Optionals
|
||||||
self.photo_width = int(photo_width)if photo_width is not None else None
|
self.photo_width = int(photo_width) if photo_width is not None else None
|
||||||
self.photo_height = int(photo_height) if photo_height is not None else None
|
self.photo_height = int(photo_height) if photo_height is not None else None
|
||||||
self.title = title
|
self.title = title
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from typing import Any, TYPE_CHECKING
|
from typing import Any, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import ReplyMarkup, InputMessageContent
|
from telegram import ReplyMarkup, InputMessageContent
|
||||||
|
|
||||||
|
@ -70,20 +71,22 @@ class InlineQueryResultVenue(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
latitude: float,
|
id: str,
|
||||||
longitude: float,
|
latitude: float,
|
||||||
title: str,
|
longitude: float,
|
||||||
address: str,
|
title: str,
|
||||||
foursquare_id: str = None,
|
address: str,
|
||||||
foursquare_type: str = None,
|
foursquare_id: str = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
foursquare_type: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
thumb_url: str = None,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
thumb_width: int = None,
|
thumb_url: str = None,
|
||||||
thumb_height: int = None,
|
thumb_width: int = None,
|
||||||
**kwargs: Any):
|
thumb_height: int = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('venue', id)
|
super().__init__('venue', id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -83,21 +84,23 @@ class InlineQueryResultVideo(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
video_url: str,
|
id: str,
|
||||||
mime_type: str,
|
video_url: str,
|
||||||
thumb_url: str,
|
mime_type: str,
|
||||||
title: str,
|
thumb_url: str,
|
||||||
caption: str = None,
|
title: str,
|
||||||
video_width: int = None,
|
caption: str = None,
|
||||||
video_height: int = None,
|
video_width: int = None,
|
||||||
video_duration: int = None,
|
video_height: int = None,
|
||||||
description: str = None,
|
video_duration: int = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
description: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('video', id)
|
super().__init__('video', id)
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
from telegram import InlineQueryResult
|
from telegram import InlineQueryResult
|
||||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||||
from typing import Any, Union, TYPE_CHECKING
|
from typing import Any, Union, TYPE_CHECKING
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from telegram import InputMessageContent, ReplyMarkup
|
from telegram import InputMessageContent, ReplyMarkup
|
||||||
|
|
||||||
|
@ -64,16 +65,18 @@ class InlineQueryResultVoice(InlineQueryResult):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
id: str,
|
self,
|
||||||
voice_url: str,
|
id: str,
|
||||||
title: str,
|
voice_url: str,
|
||||||
voice_duration: int = None,
|
title: str,
|
||||||
caption: str = None,
|
voice_duration: int = None,
|
||||||
reply_markup: 'ReplyMarkup' = None,
|
caption: str = None,
|
||||||
input_message_content: 'InputMessageContent' = None,
|
reply_markup: 'ReplyMarkup' = None,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
input_message_content: 'InputMessageContent' = None,
|
||||||
**kwargs: Any):
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
|
|
||||||
# Required
|
# Required
|
||||||
super().__init__('voice', id)
|
super().__init__('voice', id)
|
||||||
|
|
|
@ -45,12 +45,14 @@ class InputContactMessageContent(InputMessageContent):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
phone_number: str,
|
self,
|
||||||
first_name: str,
|
phone_number: str,
|
||||||
last_name: str = None,
|
first_name: str,
|
||||||
vcard: str = None,
|
last_name: str = None,
|
||||||
**kwargs: Any):
|
vcard: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.phone_number = phone_number
|
self.phone_number = phone_number
|
||||||
self.first_name = first_name
|
self.first_name = first_name
|
||||||
|
|
|
@ -23,6 +23,7 @@ from typing import Any
|
||||||
|
|
||||||
|
|
||||||
class InputLocationMessageContent(InputMessageContent):
|
class InputLocationMessageContent(InputMessageContent):
|
||||||
|
# fmt: off
|
||||||
"""
|
"""
|
||||||
Represents the content of a location message to be sent as the result of an inline query.
|
Represents the content of a location message to be sent as the result of an inline query.
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ class InputLocationMessageContent(InputMessageContent):
|
||||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
def __init__(self, latitude: float, longitude: float, live_period: int = None, **kwargs: Any):
|
def __init__(self, latitude: float, longitude: float, live_period: int = None, **kwargs: Any):
|
||||||
# Required
|
# Required
|
||||||
|
|
|
@ -29,6 +29,7 @@ class InputMessageContent(TelegramObject):
|
||||||
:class:`telegram.InputVenueMessageContent` for more details.
|
:class:`telegram.InputVenueMessageContent` for more details.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _has_parse_mode(self) -> bool:
|
def _has_parse_mode(self) -> bool:
|
||||||
return hasattr(self, 'parse_mode')
|
return hasattr(self, 'parse_mode')
|
||||||
|
|
|
@ -51,11 +51,13 @@ class InputTextMessageContent(InputMessageContent):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
message_text: str,
|
self,
|
||||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
message_text: str,
|
||||||
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
|
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||||
**kwargs: Any):
|
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.message_text = message_text
|
self.message_text = message_text
|
||||||
# Optionals
|
# Optionals
|
||||||
|
|
|
@ -52,14 +52,16 @@ class InputVenueMessageContent(InputMessageContent):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
latitude: float,
|
self,
|
||||||
longitude: float,
|
latitude: float,
|
||||||
title: str,
|
longitude: float,
|
||||||
address: str,
|
title: str,
|
||||||
foursquare_id: str = None,
|
address: str,
|
||||||
foursquare_type: str = None,
|
foursquare_id: str = None,
|
||||||
**kwargs: Any):
|
foursquare_type: str = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
self.longitude = longitude
|
self.longitude = longitude
|
||||||
|
|
|
@ -60,12 +60,14 @@ class KeyboardButton(TelegramObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(
|
||||||
text: str,
|
self,
|
||||||
request_contact: bool = None,
|
text: str,
|
||||||
request_location: bool = None,
|
request_contact: bool = None,
|
||||||
request_poll: bool = None,
|
request_location: bool = None,
|
||||||
**kwargs: Any):
|
request_poll: bool = None,
|
||||||
|
**kwargs: Any,
|
||||||
|
):
|
||||||
# Required
|
# Required
|
||||||
self.text = text
|
self.text = text
|
||||||
# Optionals
|
# Optionals
|
||||||
|
@ -73,5 +75,9 @@ class KeyboardButton(TelegramObject):
|
||||||
self.request_location = request_location
|
self.request_location = request_location
|
||||||
self.request_poll = request_poll
|
self.request_poll = request_poll
|
||||||
|
|
||||||
self._id_attrs = (self.text, self.request_contact, self.request_location,
|
self._id_attrs = (
|
||||||
self.request_poll)
|
self.text,
|
||||||
|
self.request_contact,
|
||||||
|
self.request_location,
|
||||||
|
self.request_poll,
|
||||||
|
)
|
||||||
|
|
|
@ -35,6 +35,7 @@ class KeyboardButtonPollType(TelegramObject):
|
||||||
passed, only regular polls will be allowed. Otherwise, the user will be allowed to
|
passed, only regular polls will be allowed. Otherwise, the user will be allowed to
|
||||||
create a poll of any type.
|
create a poll of any type.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, type: str = None, **kwargs: Any):
|
def __init__(self, type: str = None, **kwargs: Any):
|
||||||
self.type = type
|
self.type = type
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue