mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +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.
|
||||
|
||||
- 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:
|
||||
|
||||
- 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.
|
||||
|
||||
- Don’t break backward compatibility.
|
||||
|
@ -189,11 +191,6 @@ Here's how to make a one-off code change.
|
|||
Style commandments
|
||||
------------------
|
||||
|
||||
Specific commandments
|
||||
#####################
|
||||
|
||||
- Avoid using "double quotes" where you can reasonably use 'single quotes'.
|
||||
|
||||
Assert comparison order
|
||||
#######################
|
||||
|
||||
|
@ -255,3 +252,5 @@ break the API classes. For example:
|
|||
.. _AUTHORS.rst: ../AUTHORS.rst
|
||||
.. _`MyPy`: https://mypy.readthedocs.io/en/stable/index.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:
|
||||
- repo: git://github.com/python-telegram-bot/mirrors-yapf
|
||||
rev: 5769e088ef6e0a0d1eb63bd6d0c1fe9f3606d6c8
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
hooks:
|
||||
- id: yapf
|
||||
files: ^(telegram|tests)/.*\.py$
|
||||
- id: black
|
||||
args:
|
||||
- --diff
|
||||
- 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
|
||||
: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
|
||||
:target: https://telegram.me/pythontelegrambotgroup
|
||||
:alt: Telegram Group
|
||||
|
|
|
@ -16,13 +16,13 @@ bot.
|
|||
|
||||
import logging
|
||||
|
||||
from telegram import (ReplyKeyboardMarkup, ReplyKeyboardRemove)
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
||||
ConversationHandler)
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove
|
||||
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
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. '
|
||||
'Send /cancel to stop talking to me.\n\n'
|
||||
'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
|
||||
|
||||
|
@ -44,9 +45,11 @@ def start(update, context):
|
|||
def gender(update, context):
|
||||
user = update.message.from_user
|
||||
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, '
|
||||
'so I know what you look like, or send /skip if you don\'t want to.',
|
||||
reply_markup=ReplyKeyboardRemove())
|
||||
update.message.reply_text(
|
||||
'I see! Please send me a photo of yourself, '
|
||||
'so I know what you look like, or send /skip if you don\'t want to.',
|
||||
reply_markup=ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
return PHOTO
|
||||
|
||||
|
@ -56,8 +59,9 @@ def photo(update, context):
|
|||
photo_file = update.message.photo[-1].get_file()
|
||||
photo_file.download('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, '
|
||||
'or send /skip if you don\'t want to.')
|
||||
update.message.reply_text(
|
||||
'Gorgeous! Now, send me your location please, ' 'or send /skip if you don\'t want to.'
|
||||
)
|
||||
|
||||
return LOCATION
|
||||
|
||||
|
@ -65,8 +69,9 @@ def photo(update, context):
|
|||
def skip_photo(update, context):
|
||||
user = update.message.from_user
|
||||
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, '
|
||||
'or send /skip.')
|
||||
update.message.reply_text(
|
||||
'I bet you look great! Now, send me your location please, ' 'or send /skip.'
|
||||
)
|
||||
|
||||
return LOCATION
|
||||
|
||||
|
@ -74,10 +79,12 @@ def skip_photo(update, context):
|
|||
def location(update, context):
|
||||
user = update.message.from_user
|
||||
user_location = update.message.location
|
||||
logger.info("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.')
|
||||
logger.info(
|
||||
"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.'
|
||||
)
|
||||
|
||||
return BIO
|
||||
|
||||
|
@ -85,8 +92,9 @@ def location(update, context):
|
|||
def skip_location(update, context):
|
||||
user = update.message.from_user
|
||||
logger.info("User %s did not send a location.", user.first_name)
|
||||
update.message.reply_text('You seem a bit paranoid! '
|
||||
'At last, tell me something about yourself.')
|
||||
update.message.reply_text(
|
||||
'You seem a bit paranoid! ' 'At last, tell me something about yourself.'
|
||||
)
|
||||
|
||||
return BIO
|
||||
|
||||
|
@ -102,8 +110,9 @@ def bio(update, context):
|
|||
def cancel(update, context):
|
||||
user = update.message.from_user
|
||||
logger.info("User %s canceled the conversation.", user.first_name)
|
||||
update.message.reply_text('Bye! I hope we can talk again some day.',
|
||||
reply_markup=ReplyKeyboardRemove())
|
||||
update.message.reply_text(
|
||||
'Bye! I hope we can talk again some day.', reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
|
||||
return ConversationHandler.END
|
||||
|
||||
|
@ -120,20 +129,16 @@ def main():
|
|||
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('start', start)],
|
||||
|
||||
states={
|
||||
GENDER: [MessageHandler(Filters.regex('^(Boy|Girl|Other)$'), gender)],
|
||||
|
||||
PHOTO: [MessageHandler(Filters.photo, photo),
|
||||
CommandHandler('skip', skip_photo)],
|
||||
|
||||
LOCATION: [MessageHandler(Filters.location, location),
|
||||
CommandHandler('skip', skip_location)],
|
||||
|
||||
BIO: [MessageHandler(Filters.text & ~Filters.command, bio)]
|
||||
PHOTO: [MessageHandler(Filters.photo, photo), CommandHandler('skip', skip_photo)],
|
||||
LOCATION: [
|
||||
MessageHandler(Filters.location, location),
|
||||
CommandHandler('skip', skip_location),
|
||||
],
|
||||
BIO: [MessageHandler(Filters.text & ~Filters.command, bio)],
|
||||
},
|
||||
|
||||
fallbacks=[CommandHandler('cancel', cancel)]
|
||||
fallbacks=[CommandHandler('cancel', cancel)],
|
||||
)
|
||||
|
||||
dp.add_handler(conv_handler)
|
||||
|
|
|
@ -17,20 +17,22 @@ bot.
|
|||
import logging
|
||||
|
||||
from telegram import ReplyKeyboardMarkup
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
||||
ConversationHandler)
|
||||
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
||||
|
||||
reply_keyboard = [['Age', 'Favourite colour'],
|
||||
['Number of siblings', 'Something else...'],
|
||||
['Done']]
|
||||
reply_keyboard = [
|
||||
['Age', 'Favourite colour'],
|
||||
['Number of siblings', 'Something else...'],
|
||||
['Done'],
|
||||
]
|
||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||
|
||||
|
||||
|
@ -47,7 +49,8 @@ def start(update, context):
|
|||
update.message.reply_text(
|
||||
"Hi! My name is Doctor Botter. I will hold a more complex conversation with you. "
|
||||
"Why don't you tell me something about yourself?",
|
||||
reply_markup=markup)
|
||||
reply_markup=markup,
|
||||
)
|
||||
|
||||
return CHOOSING
|
||||
|
||||
|
@ -56,14 +59,16 @@ def regular_choice(update, context):
|
|||
text = update.message.text
|
||||
context.user_data['choice'] = 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
|
||||
|
||||
|
||||
def custom_choice(update, context):
|
||||
update.message.reply_text('Alright, please send me the category first, '
|
||||
'for example "Most impressive skill"')
|
||||
update.message.reply_text(
|
||||
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||
)
|
||||
|
||||
return TYPING_CHOICE
|
||||
|
||||
|
@ -75,10 +80,12 @@ def received_information(update, context):
|
|||
user_data[category] = text
|
||||
del user_data['choice']
|
||||
|
||||
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(user_data)),
|
||||
reply_markup=markup)
|
||||
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(user_data)),
|
||||
reply_markup=markup,
|
||||
)
|
||||
|
||||
return CHOOSING
|
||||
|
||||
|
@ -88,9 +95,9 @@ def done(update, context):
|
|||
if 'choice' in user_data:
|
||||
del user_data['choice']
|
||||
|
||||
update.message.reply_text("I learned these facts about you:"
|
||||
"{}"
|
||||
"Until next time!".format(facts_to_str(user_data)))
|
||||
update.message.reply_text(
|
||||
"I learned these facts about you:" "{}" "Until next time!".format(facts_to_str(user_data))
|
||||
)
|
||||
|
||||
user_data.clear()
|
||||
return ConversationHandler.END
|
||||
|
@ -108,24 +115,26 @@ def main():
|
|||
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('start', start)],
|
||||
|
||||
states={
|
||||
CHOOSING: [MessageHandler(Filters.regex('^(Age|Favourite colour|Number of siblings)$'),
|
||||
regular_choice),
|
||||
MessageHandler(Filters.regex('^Something else...$'),
|
||||
custom_choice)
|
||||
],
|
||||
|
||||
CHOOSING: [
|
||||
MessageHandler(
|
||||
Filters.regex('^(Age|Favourite colour|Number of siblings)$'), regular_choice
|
||||
),
|
||||
MessageHandler(Filters.regex('^Something else...$'), custom_choice),
|
||||
],
|
||||
TYPING_CHOICE: [
|
||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||
regular_choice)],
|
||||
|
||||
MessageHandler(
|
||||
Filters.text & ~(Filters.command | Filters.regex('^Done$')), regular_choice
|
||||
)
|
||||
],
|
||||
TYPING_REPLY: [
|
||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||
received_information)],
|
||||
MessageHandler(
|
||||
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)
|
||||
|
|
|
@ -25,8 +25,9 @@ from telegram.ext import Updater, CommandHandler, Filters
|
|||
# Enable logging
|
||||
from telegram.utils import helpers
|
||||
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -48,8 +49,10 @@ def deep_linked_level_1(update, context):
|
|||
"""Reached through the CHECK_THIS_OUT payload"""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.get_me().username, SO_COOL)
|
||||
text = "Awesome, you just accessed hidden functionality! " \
|
||||
" Now let's get back to the private chat."
|
||||
text = (
|
||||
"Awesome, you just accessed hidden functionality! "
|
||||
" Now let's get back to the private chat."
|
||||
)
|
||||
keyboard = InlineKeyboardMarkup.from_button(
|
||||
InlineKeyboardButton(text='Continue here!', url=url)
|
||||
)
|
||||
|
@ -60,16 +63,16 @@ def deep_linked_level_2(update, context):
|
|||
"""Reached through the SO_COOL payload"""
|
||||
bot = context.bot
|
||||
url = helpers.create_deep_linked_url(bot.get_me().username, USING_ENTITIES)
|
||||
text = "You can also mask the deep-linked URLs as links: " \
|
||||
"[▶️ CLICK HERE]({}).".format(url)
|
||||
text = "You can also mask the deep-linked URLs as links: " "[▶️ CLICK HERE]({}).".format(url)
|
||||
update.message.reply_text(text, parse_mode=ParseMode.MARKDOWN, disable_web_page_preview=True)
|
||||
|
||||
|
||||
def deep_linked_level_3(update, context):
|
||||
"""Reached through the USING_ENTITIES payload"""
|
||||
payload = context.args
|
||||
update.message.reply_text("Congratulations! This is as deep as it gets 👏🏻\n\n"
|
||||
"The payload was: {}".format(payload))
|
||||
update.message.reply_text(
|
||||
"Congratulations! This is as deep as it gets 👏🏻\n\n" "The payload was: {}".format(payload)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
|
@ -90,10 +93,9 @@ def main():
|
|||
dp.add_handler(CommandHandler("start", deep_linked_level_2, Filters.regex(SO_COOL)))
|
||||
|
||||
# We can also pass on the deep-linking payload
|
||||
dp.add_handler(CommandHandler("start",
|
||||
deep_linked_level_3,
|
||||
Filters.regex(USING_ENTITIES),
|
||||
pass_args=True))
|
||||
dp.add_handler(
|
||||
CommandHandler("start", deep_linked_level_3, Filters.regex(USING_ENTITIES), pass_args=True)
|
||||
)
|
||||
|
||||
# Make sure the deep-linking handlers occur *before* the normal /start handler.
|
||||
dp.add_handler(CommandHandler("start", start))
|
||||
|
|
|
@ -20,8 +20,9 @@ import logging
|
|||
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -13,8 +13,9 @@ import traceback
|
|||
from telegram import Update, ParseMode
|
||||
from telegram.ext import Updater, CallbackContext, CommandHandler
|
||||
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
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(str(context.chat_data)),
|
||||
html.escape(str(context.user_data)),
|
||||
html.escape(tb)
|
||||
html.escape(tb),
|
||||
)
|
||||
|
||||
# Finally, send the message
|
||||
|
@ -61,9 +62,10 @@ def bad_command(update: Update, context: CallbackContext):
|
|||
|
||||
|
||||
def start(update: Update, context: CallbackContext):
|
||||
update.effective_message.reply_html('Use /bad_command to cause an error.\n'
|
||||
'Your chat id is <code>{}</code>.'
|
||||
.format(update.effective_chat.id))
|
||||
update.effective_message.reply_html(
|
||||
'Use /bad_command to cause an error.\n'
|
||||
'Your chat id is <code>{}</code>.'.format(update.effective_chat.id)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -15,14 +15,14 @@ bot.
|
|||
import logging
|
||||
from uuid import uuid4
|
||||
|
||||
from telegram import InlineQueryResultArticle, ParseMode, \
|
||||
InputTextMessageContent
|
||||
from telegram import InlineQueryResultArticle, ParseMode, InputTextMessageContent
|
||||
from telegram.ext import Updater, InlineQueryHandler, CommandHandler
|
||||
from telegram.utils.helpers import escape_markdown
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -44,22 +44,23 @@ def inlinequery(update, context):
|
|||
query = update.inline_query.query
|
||||
results = [
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Caps",
|
||||
input_message_content=InputTextMessageContent(
|
||||
query.upper())),
|
||||
id=uuid4(), title="Caps", input_message_content=InputTextMessageContent(query.upper())
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Bold",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"*{}*".format(escape_markdown(query)),
|
||||
parse_mode=ParseMode.MARKDOWN)),
|
||||
"*{}*".format(escape_markdown(query)), parse_mode=ParseMode.MARKDOWN
|
||||
),
|
||||
),
|
||||
InlineQueryResultArticle(
|
||||
id=uuid4(),
|
||||
title="Italic",
|
||||
input_message_content=InputTextMessageContent(
|
||||
"_{}_".format(escape_markdown(query)),
|
||||
parse_mode=ParseMode.MARKDOWN))]
|
||||
"_{}_".format(escape_markdown(query)), parse_mode=ParseMode.MARKDOWN
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
update.inline_query.answer(results)
|
||||
|
||||
|
|
|
@ -10,16 +10,20 @@ import logging
|
|||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
|
||||
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(update, context):
|
||||
keyboard = [[InlineKeyboardButton("Option 1", callback_data='1'),
|
||||
InlineKeyboardButton("Option 2", callback_data='2')],
|
||||
|
||||
[InlineKeyboardButton("Option 3", callback_data='3')]]
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("Option 1", callback_data='1'),
|
||||
InlineKeyboardButton("Option 2", callback_data='2'),
|
||||
],
|
||||
[InlineKeyboardButton("Option 3", callback_data='3')],
|
||||
]
|
||||
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
|
|
|
@ -17,8 +17,9 @@ from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, Conversa
|
|||
import logging
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
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
|
||||
# a list (hence `[[...]]`).
|
||||
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)
|
||||
# Send message with text and appended InlineKeyboard
|
||||
update.message.reply_text(
|
||||
"Start handler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
update.message.reply_text("Start handler, Choose a route", reply_markup=reply_markup)
|
||||
# Tell ConversationHandler that we're in state `FIRST` now
|
||||
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
|
||||
query.answer()
|
||||
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)
|
||||
# Instead of sending a new message, edit the message that
|
||||
# originated the CallbackQuery. This gives the feeling of an
|
||||
# interactive menu.
|
||||
query.edit_message_text(
|
||||
text="Start handler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
query.edit_message_text(text="Start handler, Choose a route", reply_markup=reply_markup)
|
||||
return FIRST
|
||||
|
||||
|
||||
|
@ -78,13 +77,14 @@ def one(update, context):
|
|||
query = update.callback_query
|
||||
query.answer()
|
||||
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)
|
||||
query.edit_message_text(
|
||||
text="First CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
text="First CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||
)
|
||||
return FIRST
|
||||
|
||||
|
@ -94,13 +94,14 @@ def two(update, context):
|
|||
query = update.callback_query
|
||||
query.answer()
|
||||
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)
|
||||
query.edit_message_text(
|
||||
text="Second CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
text="Second CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||
)
|
||||
return FIRST
|
||||
|
||||
|
@ -110,13 +111,14 @@ def three(update, context):
|
|||
query = update.callback_query
|
||||
query.answer()
|
||||
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)
|
||||
query.edit_message_text(
|
||||
text="Third CallbackQueryHandler. Do want to start over?",
|
||||
reply_markup=reply_markup
|
||||
text="Third CallbackQueryHandler. Do want to start over?", reply_markup=reply_markup
|
||||
)
|
||||
# Transfer to conversation state `SECOND`
|
||||
return SECOND
|
||||
|
@ -127,13 +129,14 @@ def four(update, context):
|
|||
query = update.callback_query
|
||||
query.answer()
|
||||
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)
|
||||
query.edit_message_text(
|
||||
text="Fourth CallbackQueryHandler, Choose a route",
|
||||
reply_markup=reply_markup
|
||||
text="Fourth CallbackQueryHandler, Choose a route", reply_markup=reply_markup
|
||||
)
|
||||
return FIRST
|
||||
|
||||
|
@ -143,9 +146,7 @@ def end(update, context):
|
|||
ConversationHandler that the conversation is over"""
|
||||
query = update.callback_query
|
||||
query.answer()
|
||||
query.edit_message_text(
|
||||
text="See you next time!"
|
||||
)
|
||||
query.edit_message_text(text="See you next time!")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
@ -165,14 +166,18 @@ def main():
|
|||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('start', start)],
|
||||
states={
|
||||
FIRST: [CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'),
|
||||
CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'),
|
||||
CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'),
|
||||
CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$')],
|
||||
SECOND: [CallbackQueryHandler(start_over, pattern='^' + str(ONE) + '$'),
|
||||
CallbackQueryHandler(end, pattern='^' + str(TWO) + '$')]
|
||||
FIRST: [
|
||||
CallbackQueryHandler(one, pattern='^' + str(ONE) + '$'),
|
||||
CallbackQueryHandler(two, pattern='^' + str(TWO) + '$'),
|
||||
CallbackQueryHandler(three, pattern='^' + str(THREE) + '$'),
|
||||
CallbackQueryHandler(four, pattern='^' + str(FOUR) + '$'),
|
||||
],
|
||||
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
|
||||
|
|
|
@ -16,13 +16,20 @@ bot.
|
|||
|
||||
import logging
|
||||
|
||||
from telegram import (InlineKeyboardMarkup, InlineKeyboardButton)
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
||||
ConversationHandler, CallbackQueryHandler)
|
||||
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from telegram.ext import (
|
||||
Updater,
|
||||
CommandHandler,
|
||||
MessageHandler,
|
||||
Filters,
|
||||
ConversationHandler,
|
||||
CallbackQueryHandler,
|
||||
)
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -38,8 +45,20 @@ STOPPING, SHOWING = map(chr, range(8, 10))
|
|||
END = ConversationHandler.END
|
||||
|
||||
# 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
|
||||
|
@ -53,15 +72,20 @@ def _name_switcher(level):
|
|||
# Top level conversation callbacks
|
||||
def start(update, context):
|
||||
"""Select an action: Adding parent/child or show data."""
|
||||
text = 'You may add a familiy member, yourself show the gathered data or end the ' \
|
||||
'conversation. To abort, simply type /stop.'
|
||||
buttons = [[
|
||||
InlineKeyboardButton(text='Add family member', callback_data=str(ADDING_MEMBER)),
|
||||
InlineKeyboardButton(text='Add yourself', callback_data=str(ADDING_SELF))
|
||||
], [
|
||||
InlineKeyboardButton(text='Show data', callback_data=str(SHOWING)),
|
||||
InlineKeyboardButton(text='Done', callback_data=str(END))
|
||||
]]
|
||||
text = (
|
||||
'You may add a familiy member, yourself show the gathered data or end the '
|
||||
'conversation. To abort, simply type /stop.'
|
||||
)
|
||||
buttons = [
|
||||
[
|
||||
InlineKeyboardButton(text='Add family member', callback_data=str(ADDING_MEMBER)),
|
||||
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)
|
||||
|
||||
# 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.edit_message_text(text=text, reply_markup=keyboard)
|
||||
else:
|
||||
update.message.reply_text('Hi, I\'m FamiliyBot and here to help you gather information'
|
||||
'about your family.')
|
||||
update.message.reply_text(
|
||||
'Hi, I\'m FamiliyBot and here to help you gather information' 'about your family.'
|
||||
)
|
||||
update.message.reply_text(text=text, reply_markup=keyboard)
|
||||
|
||||
context.user_data[START_OVER] = False
|
||||
|
@ -92,6 +117,7 @@ def adding_self(update, context):
|
|||
|
||||
def show_data(update, context):
|
||||
"""Pretty print gathered data."""
|
||||
|
||||
def prettyprint(user_data, level):
|
||||
people = user_data.get(level)
|
||||
if not people:
|
||||
|
@ -106,8 +132,9 @@ def show_data(update, context):
|
|||
|
||||
for person in user_data[level]:
|
||||
gender = female if person[GENDER] == FEMALE else male
|
||||
text += '\n{}: Name: {}, Age: {}'.format(gender, person.get(NAME, '-'),
|
||||
person.get(AGE, '-'))
|
||||
text += '\n{}: Name: {}, Age: {}'.format(
|
||||
gender, person.get(NAME, '-'), person.get(AGE, '-')
|
||||
)
|
||||
return text
|
||||
|
||||
ud = context.user_data
|
||||
|
@ -115,9 +142,7 @@ def show_data(update, context):
|
|||
text += '\n\nParents:' + prettyprint(ud, PARENTS)
|
||||
text += '\n\nChildren:' + prettyprint(ud, CHILDREN)
|
||||
|
||||
buttons = [[
|
||||
InlineKeyboardButton(text='Back', callback_data=str(END))
|
||||
]]
|
||||
buttons = [[InlineKeyboardButton(text='Back', callback_data=str(END))]]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
|
@ -148,13 +173,16 @@ def end(update, context):
|
|||
def select_level(update, context):
|
||||
"""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.'
|
||||
buttons = [[
|
||||
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))
|
||||
]]
|
||||
buttons = [
|
||||
[
|
||||
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)),
|
||||
],
|
||||
]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
|
@ -172,13 +200,16 @@ def select_gender(update, context):
|
|||
|
||||
male, female = _name_switcher(level)
|
||||
|
||||
buttons = [[
|
||||
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))
|
||||
]]
|
||||
buttons = [
|
||||
[
|
||||
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)),
|
||||
],
|
||||
]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
update.callback_query.answer()
|
||||
|
@ -198,11 +229,13 @@ def end_second_level(update, context):
|
|||
# Third level callbacks
|
||||
def select_feature(update, context):
|
||||
"""Select a feature to update for the person."""
|
||||
buttons = [[
|
||||
InlineKeyboardButton(text='Name', callback_data=str(NAME)),
|
||||
InlineKeyboardButton(text='Age', callback_data=str(AGE)),
|
||||
InlineKeyboardButton(text='Done', callback_data=str(END)),
|
||||
]]
|
||||
buttons = [
|
||||
[
|
||||
InlineKeyboardButton(text='Name', callback_data=str(NAME)),
|
||||
InlineKeyboardButton(text='Age', callback_data=str(AGE)),
|
||||
InlineKeyboardButton(text='Done', callback_data=str(END)),
|
||||
]
|
||||
]
|
||||
keyboard = InlineKeyboardMarkup(buttons)
|
||||
|
||||
# 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)
|
||||
description_conv = ConversationHandler(
|
||||
entry_points=[CallbackQueryHandler(select_feature,
|
||||
pattern='^' + str(MALE) + '$|^' + str(FEMALE) + '$')],
|
||||
|
||||
entry_points=[
|
||||
CallbackQueryHandler(
|
||||
select_feature, pattern='^' + str(MALE) + '$|^' + str(FEMALE) + '$'
|
||||
)
|
||||
],
|
||||
states={
|
||||
SELECTING_FEATURE: [CallbackQueryHandler(ask_for_input,
|
||||
pattern='^(?!' + str(END) + ').*$')],
|
||||
SELECTING_FEATURE: [
|
||||
CallbackQueryHandler(ask_for_input, pattern='^(?!' + str(END) + ').*$')
|
||||
],
|
||||
TYPING: [MessageHandler(Filters.text & ~Filters.command, save_input)],
|
||||
},
|
||||
|
||||
fallbacks=[
|
||||
CallbackQueryHandler(end_describing, pattern='^' + str(END) + '$'),
|
||||
CommandHandler('stop', stop_nested)
|
||||
CommandHandler('stop', stop_nested),
|
||||
],
|
||||
|
||||
map_to_parent={
|
||||
# Return to second level menu
|
||||
END: SELECTING_LEVEL,
|
||||
# End conversation alltogether
|
||||
STOPPING: STOPPING,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Set up second level ConversationHandler (adding a person)
|
||||
add_member_conv = ConversationHandler(
|
||||
entry_points=[CallbackQueryHandler(select_level,
|
||||
pattern='^' + str(ADDING_MEMBER) + '$')],
|
||||
|
||||
entry_points=[CallbackQueryHandler(select_level, pattern='^' + str(ADDING_MEMBER) + '$')],
|
||||
states={
|
||||
SELECTING_LEVEL: [CallbackQueryHandler(select_gender,
|
||||
pattern='^{}$|^{}$'.format(str(PARENTS),
|
||||
str(CHILDREN)))],
|
||||
SELECTING_GENDER: [description_conv]
|
||||
SELECTING_LEVEL: [
|
||||
CallbackQueryHandler(
|
||||
select_gender, pattern='^{}$|^{}$'.format(str(PARENTS), str(CHILDREN))
|
||||
)
|
||||
],
|
||||
SELECTING_GENDER: [description_conv],
|
||||
},
|
||||
|
||||
fallbacks=[
|
||||
CallbackQueryHandler(show_data, pattern='^' + str(SHOWING) + '$'),
|
||||
CallbackQueryHandler(end_second_level, pattern='^' + str(END) + '$'),
|
||||
CommandHandler('stop', stop_nested)
|
||||
CommandHandler('stop', stop_nested),
|
||||
],
|
||||
|
||||
map_to_parent={
|
||||
# After showing data return to top level menu
|
||||
SHOWING: SHOWING,
|
||||
|
@ -325,7 +357,7 @@ def main():
|
|||
END: SELECTING_ACTION,
|
||||
# End conversation alltogether
|
||||
STOPPING: END,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# Set up top level ConversationHandler (selecting action)
|
||||
|
@ -339,7 +371,6 @@ def main():
|
|||
]
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('start', start)],
|
||||
|
||||
states={
|
||||
SHOWING: [CallbackQueryHandler(start, pattern='^' + str(END) + '$')],
|
||||
SELECTING_ACTION: selection_handlers,
|
||||
|
@ -347,7 +378,6 @@ def main():
|
|||
DESCRIBING_SELF: [description_conv],
|
||||
STOPPING: [CommandHandler('start', start)],
|
||||
},
|
||||
|
||||
fallbacks=[CommandHandler('stop', stop)],
|
||||
)
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ import logging
|
|||
from telegram.ext import Updater, MessageHandler, Filters
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.DEBUG)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.DEBUG
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -39,18 +40,28 @@ def msg(update, context):
|
|||
print('Phone: ', data.phone_number)
|
||||
elif data.type == 'email':
|
||||
print('Email: ', data.email)
|
||||
if data.type in ('personal_details', 'passport', 'driver_license', 'identity_card',
|
||||
'internal_passport', 'address'):
|
||||
if data.type in (
|
||||
'personal_details',
|
||||
'passport',
|
||||
'driver_license',
|
||||
'identity_card',
|
||||
'internal_passport',
|
||||
'address',
|
||||
):
|
||||
print(data.type, data.data)
|
||||
if data.type in ('utility_bill', 'bank_statement', 'rental_agreement',
|
||||
'passport_registration', 'temporary_registration'):
|
||||
if data.type in (
|
||||
'utility_bill',
|
||||
'bank_statement',
|
||||
'rental_agreement',
|
||||
'passport_registration',
|
||||
'temporary_registration',
|
||||
):
|
||||
print(data.type, len(data.files), 'files')
|
||||
for file in data.files:
|
||||
actual_file = file.get_file()
|
||||
print(actual_file)
|
||||
actual_file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
||||
'internal_passport'):
|
||||
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||
if data.front_side:
|
||||
file = data.front_side.get_file()
|
||||
print(data.type, file)
|
||||
|
@ -60,16 +71,22 @@ def msg(update, context):
|
|||
file = data.reverse_side.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
||||
'internal_passport'):
|
||||
if data.type in ('passport', 'driver_license', 'identity_card', 'internal_passport'):
|
||||
if data.selfie:
|
||||
file = data.selfie.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
||||
'internal_passport', 'utility_bill', 'bank_statement',
|
||||
'rental_agreement', 'passport_registration',
|
||||
'temporary_registration'):
|
||||
if data.type in (
|
||||
'passport',
|
||||
'driver_license',
|
||||
'identity_card',
|
||||
'internal_passport',
|
||||
'utility_bill',
|
||||
'bank_statement',
|
||||
'rental_agreement',
|
||||
'passport_registration',
|
||||
'temporary_registration',
|
||||
):
|
||||
print(data.type, len(data.translation), 'translation')
|
||||
for file in data.translation:
|
||||
actual_file = file.get_file()
|
||||
|
|
|
@ -8,13 +8,20 @@ Basic example for a bot that can receive payment from user.
|
|||
|
||||
import logging
|
||||
|
||||
from telegram import (LabeledPrice, ShippingOption)
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler,
|
||||
Filters, PreCheckoutQueryHandler, ShippingQueryHandler)
|
||||
from telegram import LabeledPrice, ShippingOption
|
||||
from telegram.ext import (
|
||||
Updater,
|
||||
CommandHandler,
|
||||
MessageHandler,
|
||||
Filters,
|
||||
PreCheckoutQueryHandler,
|
||||
ShippingQueryHandler,
|
||||
)
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -43,10 +50,21 @@ def start_with_shipping_callback(update, context):
|
|||
|
||||
# optionally pass need_name=True, need_phone_number=True,
|
||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||
context.bot.send_invoice(chat_id, title, 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)
|
||||
context.bot.send_invoice(
|
||||
chat_id,
|
||||
title,
|
||||
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):
|
||||
|
@ -66,8 +84,9 @@ def start_without_shipping_callback(update, context):
|
|||
|
||||
# optionally pass need_name=True, need_phone_number=True,
|
||||
# need_email=True, need_shipping_address=True, is_flexible=True
|
||||
context.bot.send_invoice(chat_id, title, description, payload,
|
||||
provider_token, start_parameter, currency, prices)
|
||||
context.bot.send_invoice(
|
||||
chat_id, title, description, payload, provider_token, start_parameter, currency, prices
|
||||
)
|
||||
|
||||
|
||||
def shipping_callback(update, context):
|
||||
|
|
|
@ -15,22 +15,31 @@ bot.
|
|||
"""
|
||||
|
||||
from telegram import ReplyKeyboardMarkup
|
||||
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters,
|
||||
ConversationHandler, PicklePersistence)
|
||||
from telegram.ext import (
|
||||
Updater,
|
||||
CommandHandler,
|
||||
MessageHandler,
|
||||
Filters,
|
||||
ConversationHandler,
|
||||
PicklePersistence,
|
||||
)
|
||||
|
||||
import logging
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CHOOSING, TYPING_REPLY, TYPING_CHOICE = range(3)
|
||||
|
||||
reply_keyboard = [['Age', 'Favourite colour'],
|
||||
['Number of siblings', 'Something else...'],
|
||||
['Done']]
|
||||
reply_keyboard = [
|
||||
['Age', 'Favourite colour'],
|
||||
['Number of siblings', 'Something else...'],
|
||||
['Done'],
|
||||
]
|
||||
markup = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)
|
||||
|
||||
|
||||
|
@ -46,12 +55,16 @@ def facts_to_str(user_data):
|
|||
def start(update, context):
|
||||
reply_text = "Hi! My name is Doctor Botter."
|
||||
if context.user_data:
|
||||
reply_text += " You already told me your {}. Why don't you tell me something more " \
|
||||
"about yourself? Or change anything I " \
|
||||
"already know.".format(", ".join(context.user_data.keys()))
|
||||
reply_text += (
|
||||
" You already told me your {}. Why don't you tell me something more "
|
||||
"about yourself? Or change anything I "
|
||||
"already know.".format(", ".join(context.user_data.keys()))
|
||||
)
|
||||
else:
|
||||
reply_text += " I will hold a more complex conversation with you. Why don't you tell me " \
|
||||
"something about yourself?"
|
||||
reply_text += (
|
||||
" 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)
|
||||
|
||||
return CHOOSING
|
||||
|
@ -61,8 +74,9 @@ def regular_choice(update, context):
|
|||
text = update.message.text.lower()
|
||||
context.user_data['choice'] = text
|
||||
if context.user_data.get(text):
|
||||
reply_text = 'Your {}, I already know the following ' \
|
||||
'about that: {}'.format(text, context.user_data[text])
|
||||
reply_text = 'Your {}, I already know the following ' 'about that: {}'.format(
|
||||
text, context.user_data[text]
|
||||
)
|
||||
else:
|
||||
reply_text = 'Your {}? Yes, I would love to hear about that!'.format(text)
|
||||
update.message.reply_text(reply_text)
|
||||
|
@ -71,8 +85,9 @@ def regular_choice(update, context):
|
|||
|
||||
|
||||
def custom_choice(update, context):
|
||||
update.message.reply_text('Alright, please send me the category first, '
|
||||
'for example "Most impressive skill"')
|
||||
update.message.reply_text(
|
||||
'Alright, please send me the category first, ' 'for example "Most impressive skill"'
|
||||
)
|
||||
|
||||
return TYPING_CHOICE
|
||||
|
||||
|
@ -83,27 +98,32 @@ def received_information(update, context):
|
|||
context.user_data[category] = text.lower()
|
||||
del context.user_data['choice']
|
||||
|
||||
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)),
|
||||
reply_markup=markup)
|
||||
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)),
|
||||
reply_markup=markup,
|
||||
)
|
||||
|
||||
return CHOOSING
|
||||
|
||||
|
||||
def show_data(update, context):
|
||||
update.message.reply_text("This is what you already told me:"
|
||||
"{}".format(facts_to_str(context.user_data)))
|
||||
update.message.reply_text(
|
||||
"This is what you already told me:" "{}".format(facts_to_str(context.user_data))
|
||||
)
|
||||
|
||||
|
||||
def done(update, context):
|
||||
if 'choice' in context.user_data:
|
||||
del context.user_data['choice']
|
||||
|
||||
update.message.reply_text("I learned these facts about you:"
|
||||
"{}"
|
||||
"Until next time!".format(facts_to_str(context.user_data)))
|
||||
update.message.reply_text(
|
||||
"I learned these facts about you:"
|
||||
"{}"
|
||||
"Until next time!".format(facts_to_str(context.user_data))
|
||||
)
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
|
@ -118,26 +138,28 @@ def main():
|
|||
# Add conversation handler with the states CHOOSING, TYPING_CHOICE and TYPING_REPLY
|
||||
conv_handler = ConversationHandler(
|
||||
entry_points=[CommandHandler('start', start)],
|
||||
|
||||
states={
|
||||
CHOOSING: [MessageHandler(Filters.regex('^(Age|Favourite colour|Number of siblings)$'),
|
||||
regular_choice),
|
||||
MessageHandler(Filters.regex('^Something else...$'),
|
||||
custom_choice),
|
||||
],
|
||||
|
||||
CHOOSING: [
|
||||
MessageHandler(
|
||||
Filters.regex('^(Age|Favourite colour|Number of siblings)$'), regular_choice
|
||||
),
|
||||
MessageHandler(Filters.regex('^Something else...$'), custom_choice),
|
||||
],
|
||||
TYPING_CHOICE: [
|
||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||
regular_choice)],
|
||||
|
||||
MessageHandler(
|
||||
Filters.text & ~(Filters.command | Filters.regex('^Done$')), regular_choice
|
||||
)
|
||||
],
|
||||
TYPING_REPLY: [
|
||||
MessageHandler(Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||
received_information)],
|
||||
MessageHandler(
|
||||
Filters.text & ~(Filters.command | Filters.regex('^Done$')),
|
||||
received_information,
|
||||
)
|
||||
],
|
||||
},
|
||||
|
||||
fallbacks=[MessageHandler(Filters.regex('^Done$'), done)],
|
||||
name="my_conversation",
|
||||
persistent=True
|
||||
persistent=True,
|
||||
)
|
||||
|
||||
dp.add_handler(conv_handler)
|
||||
|
|
|
@ -9,30 +9,56 @@ one the user sends the bot
|
|||
"""
|
||||
import logging
|
||||
|
||||
from telegram import (Poll, ParseMode, KeyboardButton, KeyboardButtonPollType,
|
||||
ReplyKeyboardMarkup, ReplyKeyboardRemove)
|
||||
from telegram.ext import (Updater, CommandHandler, PollAnswerHandler, PollHandler, MessageHandler,
|
||||
Filters)
|
||||
from telegram import (
|
||||
Poll,
|
||||
ParseMode,
|
||||
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',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def start(update, context):
|
||||
"""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'
|
||||
' to generate a preview for your poll')
|
||||
update.message.reply_text(
|
||||
'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):
|
||||
"""Sends a predefined poll"""
|
||||
questions = ["Good", "Really good", "Fantastic", "Great"]
|
||||
message = context.bot.send_poll(update.effective_chat.id, "How are you?", questions,
|
||||
is_anonymous=False, allows_multiple_answers=True)
|
||||
message = context.bot.send_poll(
|
||||
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
|
||||
payload = {message.poll.id: {"questions": questions, "message_id": message.message_id,
|
||||
"chat_id": update.effective_chat.id, "answers": 0}}
|
||||
payload = {
|
||||
message.poll.id: {
|
||||
"questions": questions,
|
||||
"message_id": message.message_id,
|
||||
"chat_id": update.effective_chat.id,
|
||||
"answers": 0,
|
||||
}
|
||||
}
|
||||
context.bot_data.update(payload)
|
||||
|
||||
|
||||
|
@ -52,25 +78,29 @@ def receive_poll_answer(update, context):
|
|||
answer_string += questions[question_id] + " and "
|
||||
else:
|
||||
answer_string += questions[question_id]
|
||||
context.bot.send_message(context.bot_data[poll_id]["chat_id"],
|
||||
"{} feels {}!".format(update.effective_user.mention_html(),
|
||||
answer_string),
|
||||
parse_mode=ParseMode.HTML)
|
||||
context.bot.send_message(
|
||||
context.bot_data[poll_id]["chat_id"],
|
||||
"{} feels {}!".format(update.effective_user.mention_html(), answer_string),
|
||||
parse_mode=ParseMode.HTML,
|
||||
)
|
||||
context.bot_data[poll_id]["answers"] += 1
|
||||
# Close poll after three participants voted
|
||||
if context.bot_data[poll_id]["answers"] == 3:
|
||||
context.bot.stop_poll(context.bot_data[poll_id]["chat_id"],
|
||||
context.bot_data[poll_id]["message_id"])
|
||||
context.bot.stop_poll(
|
||||
context.bot_data[poll_id]["chat_id"], context.bot_data[poll_id]["message_id"]
|
||||
)
|
||||
|
||||
|
||||
def quiz(update, context):
|
||||
"""Send a predefined poll"""
|
||||
questions = ["1", "2", "4", "20"]
|
||||
message = update.effective_message.reply_poll("How many eggs do you need for a cake?",
|
||||
questions, type=Poll.QUIZ, correct_option_id=2)
|
||||
message = update.effective_message.reply_poll(
|
||||
"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
|
||||
payload = {message.poll.id: {"chat_id": update.effective_chat.id,
|
||||
"message_id": message.message_id}}
|
||||
payload = {
|
||||
message.poll.id: {"chat_id": update.effective_chat.id, "message_id": message.message_id}
|
||||
}
|
||||
context.bot_data.update(payload)
|
||||
|
||||
|
||||
|
@ -94,9 +124,9 @@ def preview(update, context):
|
|||
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
|
||||
message = "Press the button to let the bot generate a preview for your poll"
|
||||
# using one_time_keyboard to hide the keyboard
|
||||
update.effective_message.reply_text(message,
|
||||
reply_markup=ReplyKeyboardMarkup(button,
|
||||
one_time_keyboard=True))
|
||||
update.effective_message.reply_text(
|
||||
message, reply_markup=ReplyKeyboardMarkup(button, one_time_keyboard=True)
|
||||
)
|
||||
|
||||
|
||||
def receive_poll(update, context):
|
||||
|
@ -109,14 +139,13 @@ def receive_poll(update, context):
|
|||
options=[o.text for o in actual_poll.options],
|
||||
# with is_closed true, the poll/quiz is immediately closed
|
||||
is_closed=True,
|
||||
reply_markup=ReplyKeyboardRemove()
|
||||
reply_markup=ReplyKeyboardRemove(),
|
||||
)
|
||||
|
||||
|
||||
def help_handler(update, context):
|
||||
"""Display a help message"""
|
||||
update.message.reply_text("Use /quiz, /poll or /preview to test this "
|
||||
"bot.")
|
||||
update.message.reply_text("Use /quiz, /poll or /preview to test this " "bot.")
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
@ -23,8 +23,9 @@ import logging
|
|||
from telegram.ext import Updater, CommandHandler
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
level=logging.INFO)
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -90,10 +91,9 @@ def main():
|
|||
# on different commands - answer in Telegram
|
||||
dp.add_handler(CommandHandler("start", start))
|
||||
dp.add_handler(CommandHandler("help", start))
|
||||
dp.add_handler(CommandHandler("set", set_timer,
|
||||
pass_args=True,
|
||||
pass_job_queue=True,
|
||||
pass_chat_data=True))
|
||||
dp.add_handler(
|
||||
CommandHandler("set", set_timer, pass_args=True, pass_job_queue=True, pass_chat_data=True)
|
||||
)
|
||||
dp.add_handler(CommandHandler("unset", unset, pass_chat_data=True))
|
||||
|
||||
# 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]
|
||||
max-line-length = 99
|
||||
ignore = W503, W605
|
||||
extend-ignore = E203
|
||||
exclude = setup.py, docs/source/conf.py
|
||||
|
||||
[yapf]
|
||||
based_on_style = google
|
||||
split_before_logical_operator = True
|
||||
column_limit = 99
|
||||
|
||||
[tool:pytest]
|
||||
testpaths = tests
|
||||
addopts = --no-success-flaky-report -rsxX
|
||||
|
|
|
@ -102,63 +102,170 @@ from .payment.shippingquery import ShippingQuery
|
|||
from .webhookinfo import WebhookInfo
|
||||
from .games.gamehighscore import GameHighScore
|
||||
from .update import Update
|
||||
from .files.inputmedia import (InputMedia, InputMediaVideo, InputMediaPhoto, InputMediaAnimation,
|
||||
InputMediaAudio, InputMediaDocument)
|
||||
from .constants import (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)
|
||||
from .passport.passportelementerrors import (PassportElementError,
|
||||
PassportElementErrorDataField,
|
||||
PassportElementErrorFile,
|
||||
PassportElementErrorFiles,
|
||||
PassportElementErrorFrontSide,
|
||||
PassportElementErrorReverseSide,
|
||||
PassportElementErrorSelfie,
|
||||
PassportElementErrorTranslationFile,
|
||||
PassportElementErrorTranslationFiles,
|
||||
PassportElementErrorUnspecified)
|
||||
from .passport.credentials import (Credentials,
|
||||
DataCredentials,
|
||||
SecureData,
|
||||
FileCredentials,
|
||||
TelegramDecryptionError)
|
||||
from .files.inputmedia import (
|
||||
InputMedia,
|
||||
InputMediaVideo,
|
||||
InputMediaPhoto,
|
||||
InputMediaAnimation,
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
)
|
||||
from .constants import (
|
||||
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,
|
||||
)
|
||||
from .passport.passportelementerrors import (
|
||||
PassportElementError,
|
||||
PassportElementErrorDataField,
|
||||
PassportElementErrorFile,
|
||||
PassportElementErrorFiles,
|
||||
PassportElementErrorFrontSide,
|
||||
PassportElementErrorReverseSide,
|
||||
PassportElementErrorSelfie,
|
||||
PassportElementErrorTranslationFile,
|
||||
PassportElementErrorTranslationFiles,
|
||||
PassportElementErrorUnspecified,
|
||||
)
|
||||
from .passport.credentials import (
|
||||
Credentials,
|
||||
DataCredentials,
|
||||
SecureData,
|
||||
FileCredentials,
|
||||
TelegramDecryptionError,
|
||||
)
|
||||
from .bot import Bot
|
||||
from .version import __version__ # noqa: F401
|
||||
|
||||
__author__ = 'devs@python-telegram-bot.org'
|
||||
|
||||
__all__ = [
|
||||
'Audio', 'Bot', 'Chat', 'ChatMember', 'ChatPermissions', 'ChatAction', 'ChosenInlineResult',
|
||||
'CallbackQuery', 'Contact', 'Document', 'File', 'ForceReply', 'InlineKeyboardButton',
|
||||
'InlineKeyboardMarkup', 'InlineQuery', 'InlineQueryResult', 'InlineQueryResult',
|
||||
'InlineQueryResultArticle', 'InlineQueryResultAudio', 'InlineQueryResultCachedAudio',
|
||||
'InlineQueryResultCachedDocument', 'InlineQueryResultCachedGif',
|
||||
'InlineQueryResultCachedMpeg4Gif', 'InlineQueryResultCachedPhoto',
|
||||
'InlineQueryResultCachedSticker', 'InlineQueryResultCachedVideo',
|
||||
'InlineQueryResultCachedVoice', 'InlineQueryResultContact', 'InlineQueryResultDocument',
|
||||
'InlineQueryResultGif', 'InlineQueryResultLocation', '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'
|
||||
'Audio',
|
||||
'Bot',
|
||||
'Chat',
|
||||
'ChatMember',
|
||||
'ChatPermissions',
|
||||
'ChatAction',
|
||||
'ChosenInlineResult',
|
||||
'CallbackQuery',
|
||||
'Contact',
|
||||
'Document',
|
||||
'File',
|
||||
'ForceReply',
|
||||
'InlineKeyboardButton',
|
||||
'InlineKeyboardMarkup',
|
||||
'InlineQuery',
|
||||
'InlineQueryResult',
|
||||
'InlineQueryResult',
|
||||
'InlineQueryResultArticle',
|
||||
'InlineQueryResultAudio',
|
||||
'InlineQueryResultCachedAudio',
|
||||
'InlineQueryResultCachedDocument',
|
||||
'InlineQueryResultCachedGif',
|
||||
'InlineQueryResultCachedMpeg4Gif',
|
||||
'InlineQueryResultCachedPhoto',
|
||||
'InlineQueryResultCachedSticker',
|
||||
'InlineQueryResultCachedVideo',
|
||||
'InlineQueryResultCachedVoice',
|
||||
'InlineQueryResultContact',
|
||||
'InlineQueryResultDocument',
|
||||
'InlineQueryResultGif',
|
||||
'InlineQueryResultLocation',
|
||||
'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]:
|
||||
try:
|
||||
output = subprocess.check_output(["git", "describe", "--long", "--tags"],
|
||||
stderr=subprocess.STDOUT)
|
||||
output = subprocess.check_output(
|
||||
["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT
|
||||
)
|
||||
except (subprocess.SubprocessError, OSError):
|
||||
return None
|
||||
return output.decode().strip()
|
||||
|
@ -37,8 +38,10 @@ def _git_revision() -> Optional[str]:
|
|||
|
||||
def print_ver_info() -> None:
|
||||
git_revision = _git_revision()
|
||||
print('python-telegram-bot {}'.format(telegram_ver) + (' ({})'.format(git_revision)
|
||||
if git_revision else ''))
|
||||
print(
|
||||
'python-telegram-bot {}'.format(telegram_ver)
|
||||
+ (' ({})'.format(git_revision) if git_revision else '')
|
||||
)
|
||||
print('certifi {}'.format(certifi.__version__)) # type: ignore[attr-defined]
|
||||
print('Python {}'.format(sys.version.replace('\n', ' ')))
|
||||
|
||||
|
|
|
@ -66,9 +66,7 @@ class TelegramObject:
|
|||
return cls(bot=bot, **data) # type: ignore[call-arg]
|
||||
|
||||
@classmethod
|
||||
def de_list(cls: Type[TO],
|
||||
data: Optional[List[JSONDict]],
|
||||
bot: 'Bot') -> List[Optional[TO]]:
|
||||
def de_list(cls: Type[TO], data: Optional[List[JSONDict]], bot: 'Bot') -> List[Optional[TO]]:
|
||||
if not data:
|
||||
return []
|
||||
|
||||
|
@ -104,11 +102,15 @@ class TelegramObject:
|
|||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, self.__class__):
|
||||
if self._id_attrs == ():
|
||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(self.__class__.__name__))
|
||||
warnings.warn(
|
||||
"Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(self.__class__.__name__)
|
||||
)
|
||||
if other._id_attrs == ():
|
||||
warnings.warn("Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(other.__class__.__name__))
|
||||
warnings.warn(
|
||||
"Objects of type {} can not be meaningfully tested for "
|
||||
"equivalence.".format(other.__class__.__name__)
|
||||
)
|
||||
return self._id_attrs == other._id_attrs
|
||||
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.
|
||||
description (:obj:`str`): Description of the command, 3-256 characters.
|
||||
"""
|
||||
|
||||
def __init__(self, command: str, description: str, **kwargs: Any):
|
||||
self.command = command
|
||||
self.description = description
|
||||
|
|
|
@ -78,16 +78,18 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
from_user: User,
|
||||
chat_instance: str,
|
||||
message: Message = None,
|
||||
data: str = None,
|
||||
inline_message_id: str = None,
|
||||
game_short_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
from_user: User,
|
||||
chat_instance: str,
|
||||
message: Message = None,
|
||||
data: str = None,
|
||||
inline_message_id: str = None,
|
||||
game_short_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
|
@ -143,14 +145,21 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_text(text, inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_text(
|
||||
text, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.edit_message_text(text, chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id, *args, **kwargs)
|
||||
return self.bot.edit_message_text(
|
||||
text,
|
||||
chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def edit_message_caption(self, caption: str, *args: Any,
|
||||
**kwargs: Any) -> Union[Message, bool]:
|
||||
def edit_message_caption(
|
||||
self, caption: str, *args: Any, **kwargs: Any
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
bot.edit_message_caption(caption=caption,
|
||||
|
@ -170,16 +179,21 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_caption(caption=caption,
|
||||
inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_caption(
|
||||
caption=caption, inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.edit_message_caption(caption=caption, chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_caption(
|
||||
caption=caption,
|
||||
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,
|
||||
**kwargs: Any) -> Union[Message, bool]:
|
||||
def edit_message_reply_markup(
|
||||
self, reply_markup: 'InlineKeyboardMarkup', *args: Any, **kwargs: Any
|
||||
) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
||||
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:
|
||||
return self.bot.edit_message_reply_markup(reply_markup=reply_markup,
|
||||
inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_reply_markup(
|
||||
reply_markup=reply_markup,
|
||||
inline_message_id=self.inline_message_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
else:
|
||||
return self.bot.edit_message_reply_markup(reply_markup=reply_markup,
|
||||
chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_reply_markup(
|
||||
reply_markup=reply_markup,
|
||||
chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def edit_message_media(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
@ -228,12 +248,13 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_media(inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_media(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.edit_message_media(chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_media(
|
||||
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||
)
|
||||
|
||||
def edit_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
@ -257,12 +278,13 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.edit_message_live_location(inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_live_location(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.edit_message_live_location(chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.edit_message_live_location(
|
||||
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||
)
|
||||
|
||||
def stop_message_live_location(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
@ -286,12 +308,13 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.stop_message_live_location(inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.stop_message_live_location(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.stop_message_live_location(chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.stop_message_live_location(
|
||||
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||
)
|
||||
|
||||
def set_game_score(self, *args: Any, **kwargs: Any) -> Union[Message, bool]:
|
||||
"""Shortcut for either::
|
||||
|
@ -313,12 +336,13 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.set_game_score(inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.set_game_score(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.set_game_score(chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.set_game_score(
|
||||
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||
)
|
||||
|
||||
def get_game_high_scores(self, *args: Any, **kwargs: Any) -> List['GameHighScore']:
|
||||
"""Shortcut for either::
|
||||
|
@ -339,9 +363,10 @@ class CallbackQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
if self.inline_message_id:
|
||||
return self.bot.get_game_high_scores(inline_message_id=self.inline_message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.get_game_high_scores(
|
||||
inline_message_id=self.inline_message_id, *args, **kwargs
|
||||
)
|
||||
else:
|
||||
return self.bot.get_game_high_scores(chat_id=self.message.chat_id,
|
||||
message_id=self.message.message_id,
|
||||
*args, **kwargs)
|
||||
return self.bot.get_game_high_scores(
|
||||
chat_id=self.message.chat_id, message_id=self.message.message_id, *args, **kwargs
|
||||
)
|
||||
|
|
|
@ -24,6 +24,7 @@ from .chatpermissions import ChatPermissions
|
|||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, List, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Message, ChatMember
|
||||
|
||||
|
@ -100,23 +101,25 @@ class Chat(TelegramObject):
|
|||
CHANNEL: str = 'channel'
|
||||
""":obj:`str`: 'channel'"""
|
||||
|
||||
def __init__(self,
|
||||
id: int,
|
||||
type: str,
|
||||
title: str = None,
|
||||
username: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
photo: ChatPhoto = None,
|
||||
description: str = None,
|
||||
invite_link: str = None,
|
||||
pinned_message: 'Message' = None,
|
||||
permissions: ChatPermissions = None,
|
||||
sticker_set_name: str = None,
|
||||
can_set_sticker_set: bool = None,
|
||||
slow_mode_delay: int = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: int,
|
||||
type: str,
|
||||
title: str = None,
|
||||
username: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
bot: 'Bot' = None,
|
||||
photo: ChatPhoto = None,
|
||||
description: str = None,
|
||||
invite_link: str = None,
|
||||
pinned_message: 'Message' = None,
|
||||
permissions: ChatPermissions = None,
|
||||
sticker_set_name: str = None,
|
||||
can_set_sticker_set: bool = None,
|
||||
slow_mode_delay: int = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
self.type = type
|
||||
|
@ -156,6 +159,7 @@ class Chat(TelegramObject):
|
|||
|
||||
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
|
||||
from telegram import Message
|
||||
|
||||
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
|
||||
data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot)
|
||||
|
||||
|
@ -243,7 +247,7 @@ class Chat(TelegramObject):
|
|||
Returns:
|
||||
:obj:`bool`: If the action was sent successfully.
|
||||
|
||||
"""
|
||||
"""
|
||||
return self.bot.set_chat_permissions(self.id, *args, **kwargs)
|
||||
|
||||
def set_administrator_custom_title(self, *args: Any, **kwargs: Any) -> bool:
|
||||
|
@ -254,7 +258,7 @@ class Chat(TelegramObject):
|
|||
Returns:
|
||||
:obj:`bool`: If the action was sent successfully.
|
||||
|
||||
"""
|
||||
"""
|
||||
return self.bot.set_chat_administrator_custom_title(self.id, *args, **kwargs)
|
||||
|
||||
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 typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -110,6 +111,7 @@ class ChatMember(TelegramObject):
|
|||
may add web page previews to his messages.
|
||||
|
||||
"""
|
||||
|
||||
ADMINISTRATOR: str = 'administrator'
|
||||
""":obj:`str`: 'administrator'"""
|
||||
CREATOR: str = 'creator'
|
||||
|
@ -123,27 +125,29 @@ class ChatMember(TelegramObject):
|
|||
RESTRICTED: str = 'restricted'
|
||||
""":obj:`str`: 'restricted'"""
|
||||
|
||||
def __init__(self,
|
||||
user: User,
|
||||
status: str,
|
||||
until_date: datetime.datetime = None,
|
||||
can_be_edited: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_post_messages: bool = None,
|
||||
can_edit_messages: bool = None,
|
||||
can_delete_messages: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_restrict_members: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
can_promote_members: bool = None,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
is_member: bool = None,
|
||||
custom_title: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
user: User,
|
||||
status: str,
|
||||
until_date: datetime.datetime = None,
|
||||
can_be_edited: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_post_messages: bool = None,
|
||||
can_edit_messages: bool = None,
|
||||
can_delete_messages: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_restrict_members: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
can_promote_members: bool = None,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
is_member: bool = None,
|
||||
custom_title: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.user = user
|
||||
self.status = status
|
||||
|
|
|
@ -77,16 +77,18 @@ class ChatPermissions(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
can_send_messages: bool = None,
|
||||
can_send_media_messages: bool = None,
|
||||
can_send_polls: bool = None,
|
||||
can_send_other_messages: bool = None,
|
||||
can_add_web_page_previews: bool = None,
|
||||
can_change_info: bool = None,
|
||||
can_invite_users: bool = None,
|
||||
can_pin_messages: bool = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.can_send_messages = can_send_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_change_info,
|
||||
self.can_invite_users,
|
||||
self.can_pin_messages
|
||||
self.can_pin_messages,
|
||||
)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
from telegram import TelegramObject, User, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -61,13 +62,15 @@ class ChosenInlineResult(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
result_id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
location: Location = None,
|
||||
inline_message_id: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
result_id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
location: Location = None,
|
||||
inline_message_id: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.result_id = result_id
|
||||
self.from_user = from_user
|
||||
|
|
|
@ -48,9 +48,9 @@ MAX_CAPTION_LENGTH: int = 1024
|
|||
# constants above this line are tested
|
||||
|
||||
SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443]
|
||||
MAX_FILESIZE_DOWNLOAD: int = int(20E6) # (20MB)
|
||||
MAX_FILESIZE_UPLOAD: int = int(50E6) # (50MB)
|
||||
MAX_PHOTOSIZE_UPLOAD: int = int(10E6) # (10MB)
|
||||
MAX_FILESIZE_DOWNLOAD: int = int(20e6) # (20MB)
|
||||
MAX_FILESIZE_UPLOAD: int = int(50e6) # (50MB)
|
||||
MAX_PHOTOSIZE_UPLOAD: int = int(10e6) # (10MB)
|
||||
MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1
|
||||
MAX_MESSAGES_PER_SECOND: int = 30
|
||||
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.
|
||||
emoji (:obj:`str`): Emoji on which the dice throw animation is based.
|
||||
"""
|
||||
|
||||
def __init__(self, value: int, emoji: str, **kwargs: Any):
|
||||
self.value = value
|
||||
self.emoji = emoji
|
||||
|
|
|
@ -31,7 +31,7 @@ def _lstrip_str(in_s: str, lstr: str) -> str:
|
|||
|
||||
"""
|
||||
if in_s.startswith(lstr):
|
||||
res = in_s[len(lstr):]
|
||||
res = in_s[len(lstr) :]
|
||||
else:
|
||||
res = in_s
|
||||
return res
|
||||
|
@ -116,10 +116,10 @@ class RetryAfter(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:
|
||||
msg (:obj:`str`): The message from telegrams server.
|
||||
Args:
|
||||
msg (:obj:`str`): The message from telegrams server.
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -45,11 +45,38 @@ from .pollanswerhandler import PollAnswerHandler
|
|||
from .pollhandler import PollHandler
|
||||
from .defaults import Defaults
|
||||
|
||||
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
|
||||
'ChosenInlineResultHandler', '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')
|
||||
__all__ = (
|
||||
'Dispatcher',
|
||||
'JobQueue',
|
||||
'Job',
|
||||
'Updater',
|
||||
'CallbackQueryHandler',
|
||||
'ChosenInlineResultHandler',
|
||||
'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
|
||||
return instance
|
||||
|
||||
def __init__(self,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True):
|
||||
def __init__(
|
||||
self,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
):
|
||||
self.store_user_data = store_user_data
|
||||
self.store_chat_data = store_chat_data
|
||||
self.store_bot_data = store_bot_data
|
||||
|
@ -157,8 +159,11 @@ class BasePersistence(ABC):
|
|||
return new_obj
|
||||
if hasattr(obj, '__slots__'):
|
||||
for attr_name in new_obj.__slots__:
|
||||
setattr(new_obj, attr_name,
|
||||
cls.replace_bot(cls.replace_bot(getattr(new_obj, attr_name))))
|
||||
setattr(
|
||||
new_obj,
|
||||
attr_name,
|
||||
cls.replace_bot(cls.replace_bot(getattr(new_obj, attr_name))),
|
||||
)
|
||||
return new_obj
|
||||
|
||||
return obj
|
||||
|
@ -196,14 +201,17 @@ class BasePersistence(ABC):
|
|||
return new_obj
|
||||
if hasattr(obj, '__slots__'):
|
||||
for attr_name in obj.__slots__:
|
||||
setattr(new_obj, attr_name,
|
||||
self.insert_bot(self.insert_bot(getattr(new_obj, attr_name))))
|
||||
setattr(
|
||||
new_obj,
|
||||
attr_name,
|
||||
self.insert_bot(self.insert_bot(getattr(new_obj, attr_name))),
|
||||
)
|
||||
return new_obj
|
||||
return obj
|
||||
|
||||
@abstractmethod
|
||||
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
|
||||
``defaultdict(dict)``.
|
||||
|
||||
|
@ -213,7 +221,7 @@ class BasePersistence(ABC):
|
|||
|
||||
@abstractmethod
|
||||
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
|
||||
``defaultdict(dict)``.
|
||||
|
||||
|
@ -223,7 +231,7 @@ class BasePersistence(ABC):
|
|||
|
||||
@abstractmethod
|
||||
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
|
||||
:obj:`dict`.
|
||||
|
||||
|
@ -233,7 +241,7 @@ class BasePersistence(ABC):
|
|||
|
||||
@abstractmethod
|
||||
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
|
||||
:attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`.
|
||||
It should return the conversations for the handler with `name` or an empty :obj:`dict`
|
||||
|
@ -246,9 +254,9 @@ class BasePersistence(ABC):
|
|||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
def update_conversation(
|
||||
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||
) -> None:
|
||||
"""Will be called when a :attr:`telegram.ext.ConversationHandler.update_state`
|
||||
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 telegram import Update
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
from telegram.ext import Dispatcher, Job, JobQueue
|
||||
|
@ -91,8 +92,9 @@ class CallbackContext:
|
|||
dispatcher (:class:`telegram.ext.Dispatcher`):
|
||||
"""
|
||||
if not dispatcher.use_context:
|
||||
raise ValueError('CallbackContext should not be used with a non context aware '
|
||||
'dispatcher!')
|
||||
raise ValueError(
|
||||
'CallbackContext should not be used with a non context aware ' 'dispatcher!'
|
||||
)
|
||||
self._dispatcher = dispatcher
|
||||
self._bot_data = dispatcher.bot_data
|
||||
self._chat_data: Optional[Dict[Any, Any]] = None
|
||||
|
@ -115,8 +117,9 @@ class CallbackContext:
|
|||
|
||||
@bot_data.setter
|
||||
def bot_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to bot_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to bot_data, see " "https://git.io/fjxKe"
|
||||
)
|
||||
|
||||
@property
|
||||
def chat_data(self) -> Optional[Dict]:
|
||||
|
@ -124,8 +127,9 @@ class CallbackContext:
|
|||
|
||||
@chat_data.setter
|
||||
def chat_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to chat_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to chat_data, see " "https://git.io/fjxKe"
|
||||
)
|
||||
|
||||
@property
|
||||
def user_data(self) -> Optional[Dict]:
|
||||
|
@ -133,16 +137,19 @@ class CallbackContext:
|
|||
|
||||
@user_data.setter
|
||||
def user_data(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to user_data, see "
|
||||
"https://git.io/fjxKe")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to user_data, see " "https://git.io/fjxKe"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_error(cls,
|
||||
update: object,
|
||||
error: Exception,
|
||||
dispatcher: 'Dispatcher',
|
||||
async_args: Union[List, Tuple] = None,
|
||||
async_kwargs: Dict[str, Any] = None) -> 'CallbackContext':
|
||||
def from_error(
|
||||
cls,
|
||||
update: object,
|
||||
error: Exception,
|
||||
dispatcher: 'Dispatcher',
|
||||
async_args: Union[List, Tuple] = None,
|
||||
async_kwargs: Dict[str, Any] = None,
|
||||
) -> 'CallbackContext':
|
||||
self = cls.from_update(update, dispatcher)
|
||||
self.error = error
|
||||
self.async_args = async_args
|
||||
|
|
|
@ -24,8 +24,18 @@ from telegram import Update
|
|||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Pattern, Match, Dict, \
|
||||
cast
|
||||
from typing import (
|
||||
Callable,
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Optional,
|
||||
Union,
|
||||
TypeVar,
|
||||
Pattern,
|
||||
Match,
|
||||
Dict,
|
||||
cast,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
@ -110,23 +120,26 @@ class CallbackQueryHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
if isinstance(pattern, str):
|
||||
pattern = re.compile(pattern)
|
||||
|
@ -155,10 +168,12 @@ class CallbackQueryHandler(Handler):
|
|||
return True
|
||||
return None
|
||||
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Union[bool, Match] = None) -> Dict[str, Any]:
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Union[bool, Match] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
|
@ -168,11 +183,13 @@ class CallbackQueryHandler(Handler):
|
|||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Union[bool, Match]) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Union[bool, Match],
|
||||
) -> None:
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
context.matches = [check_result]
|
||||
|
|
|
@ -23,6 +23,7 @@ from .handler import Handler
|
|||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Optional, Union, TypeVar
|
||||
|
||||
RT = TypeVar('RT')
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ from .handler import Handler
|
|||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, List, Tuple
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -130,24 +131,27 @@ class CommandHandler(Handler):
|
|||
ValueError - when command is too long or has illegal chars.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
allow_edited: bool = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
allow_edited: bool = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
if isinstance(command, str):
|
||||
self.command = [command.lower()]
|
||||
|
@ -163,17 +167,18 @@ class CommandHandler(Handler):
|
|||
self.filters = Filters.update.messages
|
||||
|
||||
if allow_edited is not None:
|
||||
warnings.warn('allow_edited is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.warn(
|
||||
'allow_edited is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if not allow_edited:
|
||||
self.filters &= ~Filters.update.edited_message
|
||||
self.pass_args = pass_args
|
||||
|
||||
def check_update(
|
||||
self,
|
||||
update: HandlerArg) -> Optional[Union[bool, Tuple[List[str],
|
||||
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`.
|
||||
|
||||
Args:
|
||||
|
@ -186,15 +191,22 @@ class CommandHandler(Handler):
|
|||
if isinstance(update, Update) and update.effective_message:
|
||||
message = update.effective_message
|
||||
|
||||
if (message.entities 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]
|
||||
if (
|
||||
message.entities
|
||||
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:]
|
||||
command_parts = command.split('@')
|
||||
command_parts.append(message.bot.username)
|
||||
|
||||
if not (command_parts[0].lower() in self.command
|
||||
and command_parts[1].lower() == message.bot.username.lower()):
|
||||
if not (
|
||||
command_parts[0].lower() in self.command
|
||||
and command_parts[1].lower() == message.bot.username.lower()
|
||||
):
|
||||
return None
|
||||
|
||||
filter_result = self.filters(update)
|
||||
|
@ -205,22 +217,23 @@ class CommandHandler(Handler):
|
|||
return None
|
||||
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Tuple[List[str],
|
||||
Optional[bool]]]] = None) -> Dict[str, Any]:
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update)
|
||||
if self.pass_args and isinstance(check_result, tuple):
|
||||
optional_args['args'] = check_result[0]
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
if isinstance(check_result, tuple):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
|
@ -330,29 +343,36 @@ class PrefixHandler(CommandHandler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
prefix: Union[str, List[str]],
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
prefix: Union[str, List[str]],
|
||||
command: Union[str, List[str]],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
filters: BaseFilter = None,
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
|
||||
self._prefix: List[str] = list()
|
||||
self._command: List[str] = list()
|
||||
self._commands: List[str] = list()
|
||||
|
||||
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_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
self.prefix = prefix # type: ignore[assignment]
|
||||
self.command = command # type: ignore[assignment]
|
||||
|
@ -385,8 +405,9 @@ class PrefixHandler(CommandHandler):
|
|||
def _build_commands(self) -> None:
|
||||
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],
|
||||
Optional[Union[bool, Dict]]]]]:
|
||||
def check_update(
|
||||
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`.
|
||||
|
||||
Args:
|
||||
|
@ -411,11 +432,12 @@ class PrefixHandler(CommandHandler):
|
|||
return None
|
||||
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]]) -> None:
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]],
|
||||
) -> None:
|
||||
if isinstance(check_result, tuple):
|
||||
context.args = check_result[0]
|
||||
if isinstance(check_result[1], dict):
|
||||
|
|
|
@ -23,9 +23,15 @@ import warnings
|
|||
from threading import Lock
|
||||
|
||||
from telegram import Update
|
||||
from telegram.ext import (Handler, CallbackQueryHandler, InlineQueryHandler,
|
||||
ChosenInlineResultHandler, CallbackContext, BasePersistence,
|
||||
DispatcherHandlerStop)
|
||||
from telegram.ext import (
|
||||
Handler,
|
||||
CallbackQueryHandler,
|
||||
InlineQueryHandler,
|
||||
ChosenInlineResultHandler,
|
||||
CallbackContext,
|
||||
BasePersistence,
|
||||
DispatcherHandlerStop,
|
||||
)
|
||||
from telegram.utils.promise import Promise
|
||||
|
||||
from telegram.utils.types import ConversationDict, HandlerArg
|
||||
|
@ -37,11 +43,13 @@ CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]]
|
|||
|
||||
|
||||
class _ConversationTimeoutContext:
|
||||
def __init__(self,
|
||||
conversation_key: Tuple[int, ...],
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
callback_context: Optional[CallbackContext]):
|
||||
def __init__(
|
||||
self,
|
||||
conversation_key: Tuple[int, ...],
|
||||
update: Update,
|
||||
dispatcher: 'Dispatcher',
|
||||
callback_context: Optional[CallbackContext],
|
||||
):
|
||||
self.conversation_key = conversation_key
|
||||
self.update = update
|
||||
self.dispatcher = dispatcher
|
||||
|
@ -160,6 +168,7 @@ class ConversationHandler(Handler):
|
|||
ValueError
|
||||
|
||||
"""
|
||||
|
||||
END = -1
|
||||
""":obj:`int`: Used as a constant to return when a conversation is ended."""
|
||||
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
|
||||
previous ``@run_sync`` decorated running handler to finish."""
|
||||
|
||||
def __init__(self,
|
||||
entry_points: List[Handler],
|
||||
states: Dict[object, List[Handler]],
|
||||
fallbacks: List[Handler],
|
||||
allow_reentry: bool = False,
|
||||
per_chat: bool = True,
|
||||
per_user: bool = True,
|
||||
per_message: bool = False,
|
||||
conversation_timeout: int = None,
|
||||
name: str = None,
|
||||
persistent: bool = False,
|
||||
map_to_parent: Dict[object, object] = None):
|
||||
def __init__(
|
||||
self,
|
||||
entry_points: List[Handler],
|
||||
states: Dict[object, List[Handler]],
|
||||
fallbacks: List[Handler],
|
||||
allow_reentry: bool = False,
|
||||
per_chat: bool = True,
|
||||
per_user: bool = True,
|
||||
per_message: bool = False,
|
||||
conversation_timeout: int = None,
|
||||
name: str = None,
|
||||
persistent: bool = False,
|
||||
map_to_parent: Dict[object, object] = None,
|
||||
):
|
||||
self.run_async = False
|
||||
|
||||
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'")
|
||||
|
||||
if self.per_message and not self.per_chat:
|
||||
warnings.warn("If 'per_message=True' is used, 'per_chat=True' should also be used, "
|
||||
"since message IDs are not globally unique.")
|
||||
warnings.warn(
|
||||
"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.extend(entry_points)
|
||||
|
@ -224,22 +237,28 @@ class ConversationHandler(Handler):
|
|||
if self.per_message:
|
||||
for handler in all_handlers:
|
||||
if not isinstance(handler, CallbackQueryHandler):
|
||||
warnings.warn("If 'per_message=True', all entry points and state handlers"
|
||||
" must be 'CallbackQueryHandler', since no other handlers "
|
||||
"have a message context.")
|
||||
warnings.warn(
|
||||
"If 'per_message=True', all entry points and state handlers"
|
||||
" must be 'CallbackQueryHandler', since no other handlers "
|
||||
"have a message context."
|
||||
)
|
||||
break
|
||||
else:
|
||||
for handler in all_handlers:
|
||||
if isinstance(handler, CallbackQueryHandler):
|
||||
warnings.warn("If 'per_message=False', 'CallbackQueryHandler' will not be "
|
||||
"tracked for every message.")
|
||||
warnings.warn(
|
||||
"If 'per_message=False', 'CallbackQueryHandler' will not be "
|
||||
"tracked for every message."
|
||||
)
|
||||
break
|
||||
|
||||
if self.per_chat:
|
||||
for handler in all_handlers:
|
||||
if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)):
|
||||
warnings.warn("If 'per_chat=True', 'InlineQueryHandler' can not be used, "
|
||||
"since inline queries have no chat context.")
|
||||
warnings.warn(
|
||||
"If 'per_chat=True', 'InlineQueryHandler' can not be used, "
|
||||
"since inline queries have no chat context."
|
||||
)
|
||||
break
|
||||
|
||||
@property
|
||||
|
@ -304,8 +323,9 @@ class ConversationHandler(Handler):
|
|||
|
||||
@conversation_timeout.setter
|
||||
def conversation_timeout(self, value: Any) -> NoReturn:
|
||||
raise ValueError('You can not assign a new value to conversation_timeout after '
|
||||
'initialization.')
|
||||
raise ValueError(
|
||||
'You can not assign a new value to conversation_timeout after ' 'initialization.'
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self) -> Optional[str]:
|
||||
|
@ -362,8 +382,10 @@ class ConversationHandler(Handler):
|
|||
key.append(user.id)
|
||||
|
||||
if self.per_message:
|
||||
key.append(update.callback_query.inline_message_id # type: ignore[union-attr]
|
||||
or update.callback_query.message.message_id) # type: ignore[union-attr]
|
||||
key.append(
|
||||
update.callback_query.inline_message_id # type: ignore[union-attr]
|
||||
or update.callback_query.message.message_id # type: ignore[union-attr]
|
||||
)
|
||||
|
||||
return tuple(key)
|
||||
|
||||
|
@ -380,11 +402,17 @@ class ConversationHandler(Handler):
|
|||
|
||||
"""
|
||||
# Ignore messages in channels
|
||||
if (not isinstance(update, Update)
|
||||
or update.channel_post
|
||||
or self.per_chat 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):
|
||||
if (
|
||||
not isinstance(update, Update)
|
||||
or update.channel_post
|
||||
or self.per_chat
|
||||
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
|
||||
|
||||
key = self._get_key(update)
|
||||
|
@ -438,7 +466,7 @@ class ConversationHandler(Handler):
|
|||
if state is not None and not handler:
|
||||
handlers = self.states.get(state)
|
||||
|
||||
for candidate in (handlers or []):
|
||||
for candidate in handlers or []:
|
||||
check = candidate.check_update(update)
|
||||
if check is not None and check is not False:
|
||||
handler = candidate
|
||||
|
@ -457,11 +485,13 @@ class ConversationHandler(Handler):
|
|||
|
||||
return key, handler, check # type: ignore[return-value]
|
||||
|
||||
def handle_update(self, # type: ignore[override]
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: CheckUpdateType,
|
||||
context: CallbackContext = None) -> Optional[object]:
|
||||
def handle_update( # type: ignore[override]
|
||||
self,
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: CheckUpdateType,
|
||||
context: CallbackContext = None,
|
||||
) -> Optional[object]:
|
||||
"""Send the update to the callback for the current state and Handler
|
||||
|
||||
Args:
|
||||
|
@ -492,9 +522,12 @@ class ConversationHandler(Handler):
|
|||
if self.conversation_timeout and new_state != self.END and dispatcher.job_queue:
|
||||
# Add the new timeout job
|
||||
self.timeout_jobs[conversation_key] = dispatcher.job_queue.run_once(
|
||||
self._trigger_timeout, self.conversation_timeout, # type: ignore[arg-type]
|
||||
context=_ConversationTimeoutContext(conversation_key, update,
|
||||
dispatcher, context))
|
||||
self._trigger_timeout, # type: ignore[arg-type]
|
||||
self.conversation_timeout,
|
||||
context=_ConversationTimeoutContext(
|
||||
conversation_key, update, dispatcher, context
|
||||
),
|
||||
)
|
||||
|
||||
if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent:
|
||||
self.update_state(self.END, conversation_key)
|
||||
|
@ -510,9 +543,7 @@ class ConversationHandler(Handler):
|
|||
raise DispatcherHandlerStop()
|
||||
return None
|
||||
|
||||
def update_state(self,
|
||||
new_state: object,
|
||||
key: Tuple[int, ...]) -> None:
|
||||
def update_state(self, new_state: object, key: Tuple[int, ...]) -> None:
|
||||
if new_state == self.END:
|
||||
with self._conversations_lock:
|
||||
if key in self.conversations:
|
||||
|
@ -525,8 +556,9 @@ class ConversationHandler(Handler):
|
|||
with self._conversations_lock:
|
||||
self.conversations[key] = (self.conversations.get(key), new_state)
|
||||
if self.persistent and self.persistence and self.name:
|
||||
self.persistence.update_conversation(self.name, key,
|
||||
(self.conversations.get(key), new_state))
|
||||
self.persistence.update_conversation(
|
||||
self.name, key, (self.conversations.get(key), new_state)
|
||||
)
|
||||
|
||||
elif new_state is not None:
|
||||
with self._conversations_lock:
|
||||
|
@ -534,9 +566,7 @@ class ConversationHandler(Handler):
|
|||
if self.persistent and self.persistence and self.name:
|
||||
self.persistence.update_conversation(self.name, key, new_state)
|
||||
|
||||
def _trigger_timeout(self,
|
||||
context: _ConversationTimeoutContext,
|
||||
job: 'Job' = None) -> None:
|
||||
def _trigger_timeout(self, context: _ConversationTimeoutContext, job: 'Job' = None) -> None:
|
||||
self.logger.debug('conversation timeout was triggered!')
|
||||
|
||||
# Backward compatibility with bots that do not use CallbackContext
|
||||
|
@ -559,9 +589,12 @@ class ConversationHandler(Handler):
|
|||
check = handler.check_update(context.update)
|
||||
if check is not None and check is not False:
|
||||
try:
|
||||
handler.handle_update(context.update, context.dispatcher, check,
|
||||
callback_context)
|
||||
handler.handle_update(
|
||||
context.update, context.dispatcher, check, callback_context
|
||||
)
|
||||
except DispatcherHandlerStop:
|
||||
self.logger.warning('DispatcherHandlerStop in TIMEOUT state of '
|
||||
'ConversationHandler has no effect. Ignoring.')
|
||||
self.logger.warning(
|
||||
'DispatcherHandlerStop in TIMEOUT state of '
|
||||
'ConversationHandler has no effect. Ignoring.'
|
||||
)
|
||||
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
|
||||
``pytz`` module. Defaults to UTC.
|
||||
"""
|
||||
def __init__(self,
|
||||
parse_mode: str = None,
|
||||
disable_notification: bool = None,
|
||||
disable_web_page_preview: bool = None,
|
||||
# Timeout needs special treatment, since the bot methods have two different
|
||||
# default values for timeout (None and 20s)
|
||||
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
||||
quote: bool = None,
|
||||
tzinfo: pytz.BaseTzInfo = pytz.utc):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parse_mode: str = None,
|
||||
disable_notification: bool = None,
|
||||
disable_web_page_preview: bool = None,
|
||||
# Timeout needs special treatment, since the bot methods have two different
|
||||
# default values for timeout (None and 20s)
|
||||
timeout: Union[float, DefaultValue] = DEFAULT_NONE,
|
||||
quote: bool = None,
|
||||
tzinfo: pytz.BaseTzInfo = pytz.utc,
|
||||
):
|
||||
self._parse_mode = parse_mode
|
||||
self._disable_notification = disable_notification
|
||||
self._disable_web_page_preview = disable_web_page_preview
|
||||
|
@ -82,8 +85,10 @@ class Defaults:
|
|||
|
||||
@parse_mode.setter
|
||||
def parse_mode(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def disable_notification(self) -> Optional[bool]:
|
||||
|
@ -91,8 +96,10 @@ class Defaults:
|
|||
|
||||
@disable_notification.setter
|
||||
def disable_notification(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def disable_web_page_preview(self) -> Optional[bool]:
|
||||
|
@ -100,8 +107,10 @@ class Defaults:
|
|||
|
||||
@disable_web_page_preview.setter
|
||||
def disable_web_page_preview(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def timeout(self) -> Union[float, DefaultValue]:
|
||||
|
@ -109,8 +118,10 @@ class Defaults:
|
|||
|
||||
@timeout.setter
|
||||
def timeout(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def quote(self) -> Optional[bool]:
|
||||
|
@ -118,8 +129,10 @@ class Defaults:
|
|||
|
||||
@quote.setter
|
||||
def quote(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
@property
|
||||
def tzinfo(self) -> pytz.BaseTzInfo:
|
||||
|
@ -127,16 +140,22 @@ class Defaults:
|
|||
|
||||
@tzinfo.setter
|
||||
def tzinfo(self, value: Any) -> NoReturn:
|
||||
raise AttributeError("You can not assign a new value to defaults after because it would "
|
||||
"not have any effect.")
|
||||
raise AttributeError(
|
||||
"You can not assign a new value to defaults after because it would "
|
||||
"not have any effect."
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self._parse_mode,
|
||||
self._disable_notification,
|
||||
self._disable_web_page_preview,
|
||||
self._timeout,
|
||||
self._quote,
|
||||
self._tzinfo))
|
||||
return hash(
|
||||
(
|
||||
self._parse_mode,
|
||||
self._disable_notification,
|
||||
self._disable_web_page_preview,
|
||||
self._timeout,
|
||||
self._quote,
|
||||
self._tzinfo,
|
||||
)
|
||||
)
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
if isinstance(other, Defaults):
|
||||
|
|
|
@ -19,8 +19,11 @@
|
|||
"""This module contains the DictPersistence class."""
|
||||
from copy import deepcopy
|
||||
|
||||
from telegram.utils.helpers import decode_user_chat_data_from_json,\
|
||||
decode_conversations_from_json, encode_conversations_to_json
|
||||
from telegram.utils.helpers import (
|
||||
decode_user_chat_data_from_json,
|
||||
decode_conversations_from_json,
|
||||
encode_conversations_to_json,
|
||||
)
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
|
@ -76,17 +79,21 @@ class DictPersistence(BasePersistence):
|
|||
conversation on creating this persistence. Default is ``""``.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
user_data_json: str = '',
|
||||
chat_data_json: str = '',
|
||||
bot_data_json: str = '',
|
||||
conversations_json: str = ''):
|
||||
super().__init__(store_user_data=store_user_data,
|
||||
store_chat_data=store_chat_data,
|
||||
store_bot_data=store_bot_data)
|
||||
def __init__(
|
||||
self,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
user_data_json: str = '',
|
||||
chat_data_json: str = '',
|
||||
bot_data_json: str = '',
|
||||
conversations_json: str = '',
|
||||
):
|
||||
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._chat_data = None
|
||||
self._bot_data = None
|
||||
|
@ -226,9 +233,9 @@ class DictPersistence(BasePersistence):
|
|||
self._conversations = {}
|
||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
def update_conversation(
|
||||
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||
) -> None:
|
||||
"""Will update the conversations for the given handler.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -47,8 +47,9 @@ if TYPE_CHECKING:
|
|||
DEFAULT_GROUP = 0
|
||||
|
||||
|
||||
def run_async(func: Callable[[Update, CallbackContext],
|
||||
Any]) -> Callable[[Update, CallbackContext], Any]:
|
||||
def run_async(
|
||||
func: Callable[[Update, CallbackContext], Any]
|
||||
) -> Callable[[Update, CallbackContext], Any]:
|
||||
"""
|
||||
Function decorator that will run the function in a new thread.
|
||||
|
||||
|
@ -67,12 +68,15 @@ def run_async(func: Callable[[Update, CallbackContext],
|
|||
|
||||
@wraps(func)
|
||||
def async_func(*args: Any, **kwargs: Any) -> Any:
|
||||
warnings.warn('The @run_async decorator is deprecated. Use the `run_async` parameter of'
|
||||
'`Dispatcher.add_handler` or `Dispatcher.run_async` instead.',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
return Dispatcher.get_instance()._run_async(func, *args, update=None, error_handling=False,
|
||||
**kwargs)
|
||||
warnings.warn(
|
||||
'The @run_async decorator is deprecated. Use the `run_async` parameter of'
|
||||
'`Dispatcher.add_handler` or `Dispatcher.run_async` instead.',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return Dispatcher.get_instance()._run_async(
|
||||
func, *args, update=None, error_handling=False, **kwargs
|
||||
)
|
||||
|
||||
return async_func
|
||||
|
||||
|
@ -96,6 +100,7 @@ class DispatcherHandlerStop(Exception):
|
|||
Args:
|
||||
state (:obj:`object`, optional): The next state of the conversation.
|
||||
"""
|
||||
|
||||
def __init__(self, state: object = None) -> None:
|
||||
super().__init__()
|
||||
self.state = state
|
||||
|
@ -137,14 +142,16 @@ class Dispatcher:
|
|||
__singleton = None
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def __init__(self,
|
||||
bot: 'Bot',
|
||||
update_queue: Queue,
|
||||
workers: int = 4,
|
||||
exception_event: Event = None,
|
||||
job_queue: 'JobQueue' = None,
|
||||
persistence: BasePersistence = None,
|
||||
use_context: bool = True):
|
||||
def __init__(
|
||||
self,
|
||||
bot: 'Bot',
|
||||
update_queue: Queue,
|
||||
workers: int = 4,
|
||||
exception_event: Event = None,
|
||||
job_queue: 'JobQueue' = None,
|
||||
persistence: BasePersistence = None,
|
||||
use_context: bool = True,
|
||||
):
|
||||
self.bot = bot
|
||||
self.update_queue = update_queue
|
||||
self.job_queue = job_queue
|
||||
|
@ -152,8 +159,11 @@ class Dispatcher:
|
|||
self.use_context = use_context
|
||||
|
||||
if not use_context:
|
||||
warnings.warn('Old Handler API is deprecated - see https://git.io/fxJuV for details',
|
||||
TelegramDeprecationWarning, stacklevel=3)
|
||||
warnings.warn(
|
||||
'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.chat_data: DefaultDict[int, Dict[Any, Any]] = defaultdict(dict)
|
||||
|
@ -211,8 +221,9 @@ class Dispatcher:
|
|||
base_name = '{}_'.format(base_name) if base_name else ''
|
||||
|
||||
for i in range(workers):
|
||||
thread = Thread(target=self._pooled, name='Bot:{}:worker:{}{}'.format(self.bot.id,
|
||||
base_name, i))
|
||||
thread = Thread(
|
||||
target=self._pooled, name='Bot:{}:worker:{}{}'.format(self.bot.id, base_name, i)
|
||||
)
|
||||
self.__async_threads.add(thread)
|
||||
thread.start()
|
||||
|
||||
|
@ -235,8 +246,9 @@ class Dispatcher:
|
|||
if cls.__singleton is not None:
|
||||
return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable
|
||||
else:
|
||||
raise RuntimeError('{} not initialized or multiple instances exist'.format(
|
||||
cls.__name__))
|
||||
raise RuntimeError(
|
||||
'{} not initialized or multiple instances exist'.format(cls.__name__)
|
||||
)
|
||||
|
||||
def _pooled(self) -> None:
|
||||
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 not isinstance(promise, Promise):
|
||||
self.logger.debug("Closing run_async thread %s/%d", thr_name,
|
||||
len(self.__async_threads))
|
||||
self.logger.debug(
|
||||
"Closing run_async thread %s/%d", thr_name, len(self.__async_threads)
|
||||
)
|
||||
break
|
||||
|
||||
promise.run()
|
||||
|
@ -258,7 +271,8 @@ class Dispatcher:
|
|||
if isinstance(promise.exception, DispatcherHandlerStop):
|
||||
self.logger.warning(
|
||||
'DispatcherHandlerStop is not supported with async functions; func: %s',
|
||||
promise.pooled_function.__name__)
|
||||
promise.pooled_function.__name__,
|
||||
)
|
||||
continue
|
||||
|
||||
# Avoid infinite recursion of error handlers.
|
||||
|
@ -280,11 +294,9 @@ class Dispatcher:
|
|||
except Exception:
|
||||
self.logger.exception('An uncaught error was raised while handling the error.')
|
||||
|
||||
def run_async(self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
**kwargs: Any) -> Promise:
|
||||
def run_async(
|
||||
self, func: Callable[..., Any], *args: Any, update: HandlerArg = None, **kwargs: Any
|
||||
) -> Promise:
|
||||
"""
|
||||
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
|
||||
|
@ -310,12 +322,14 @@ class Dispatcher:
|
|||
"""
|
||||
return self._run_async(func, *args, update=update, error_handling=True, **kwargs)
|
||||
|
||||
def _run_async(self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
error_handling: bool = True,
|
||||
**kwargs: Any) -> Promise:
|
||||
def _run_async(
|
||||
self,
|
||||
func: Callable[..., Any],
|
||||
*args: Any,
|
||||
update: HandlerArg = None,
|
||||
error_handling: bool = True,
|
||||
**kwargs: Any,
|
||||
) -> Promise:
|
||||
# TODO: Remove error_handling parameter once we drop the @run_async decorator
|
||||
promise = Promise(func, args, kwargs, update=update, error_handling=error_handling)
|
||||
self.__async_queue.put(promise)
|
||||
|
@ -482,7 +496,8 @@ class Dispatcher:
|
|||
if not self.persistence:
|
||||
raise ValueError(
|
||||
"ConversationHandler {} can not be persistent if dispatcher has no "
|
||||
"persistence".format(handler.name))
|
||||
"persistence".format(handler.name)
|
||||
)
|
||||
handler.persistence = self.persistence
|
||||
handler.conversations = self.persistence.get_conversations(handler.name)
|
||||
|
||||
|
@ -541,9 +556,11 @@ class Dispatcher:
|
|||
try:
|
||||
self.dispatch_error(update, e)
|
||||
except Exception:
|
||||
message = 'Saving bot data raised an error and an ' \
|
||||
'uncaught error was raised while handling ' \
|
||||
'the error with an error_handler'
|
||||
message = (
|
||||
'Saving bot data raised an error and an '
|
||||
'uncaught error was raised while handling '
|
||||
'the error with an error_handler'
|
||||
)
|
||||
self.logger.exception(message)
|
||||
if self.persistence.store_chat_data:
|
||||
for chat_id in chat_ids:
|
||||
|
@ -553,9 +570,11 @@ class Dispatcher:
|
|||
try:
|
||||
self.dispatch_error(update, e)
|
||||
except Exception:
|
||||
message = 'Saving chat data raised an error and an ' \
|
||||
'uncaught error was raised while handling ' \
|
||||
'the error with an error_handler'
|
||||
message = (
|
||||
'Saving chat data raised an error and an '
|
||||
'uncaught error was raised while handling '
|
||||
'the error with an error_handler'
|
||||
)
|
||||
self.logger.exception(message)
|
||||
if self.persistence.store_user_data:
|
||||
for user_id in user_ids:
|
||||
|
@ -565,14 +584,16 @@ class Dispatcher:
|
|||
try:
|
||||
self.dispatch_error(update, e)
|
||||
except Exception:
|
||||
message = 'Saving user data raised an error and an ' \
|
||||
'uncaught error was raised while handling ' \
|
||||
'the error with an error_handler'
|
||||
message = (
|
||||
'Saving user data raised an error and an '
|
||||
'uncaught error was raised while handling '
|
||||
'the error with an error_handler'
|
||||
)
|
||||
self.logger.exception(message)
|
||||
|
||||
def add_error_handler(self,
|
||||
callback: Callable[[Any, CallbackContext], None],
|
||||
run_async: bool = False) -> None:
|
||||
def add_error_handler(
|
||||
self, callback: Callable[[Any, CallbackContext], None], run_async: bool = False
|
||||
) -> None:
|
||||
"""Registers an error handler in the Dispatcher. This handler will receive every error
|
||||
which happens in your bot.
|
||||
|
||||
|
@ -610,10 +631,9 @@ class Dispatcher:
|
|||
"""
|
||||
self.error_handlers.pop(callback, None)
|
||||
|
||||
def dispatch_error(self,
|
||||
update: Optional[HandlerArg],
|
||||
error: Exception,
|
||||
promise: Promise = None) -> None:
|
||||
def dispatch_error(
|
||||
self, update: Optional[HandlerArg], error: Exception, promise: Promise = None
|
||||
) -> None:
|
||||
"""Dispatches an error.
|
||||
|
||||
Args:
|
||||
|
@ -629,9 +649,9 @@ class Dispatcher:
|
|||
if self.error_handlers:
|
||||
for callback, run_async in self.error_handlers.items():
|
||||
if self.use_context:
|
||||
context = CallbackContext.from_error(update, error, self,
|
||||
async_args=async_args,
|
||||
async_kwargs=async_kwargs)
|
||||
context = CallbackContext.from_error(
|
||||
update, error, self, async_args=async_args, async_kwargs=async_kwargs
|
||||
)
|
||||
if run_async:
|
||||
self.run_async(callback, update, context, update=update)
|
||||
else:
|
||||
|
@ -644,4 +664,5 @@ class Dispatcher:
|
|||
|
||||
else:
|
||||
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
|
||||
|
||||
__all__ = ['Filters', 'BaseFilter', 'MessageFilter', 'UpdateFilter', 'InvertedFilter',
|
||||
'MergedFilter']
|
||||
__all__ = [
|
||||
'Filters',
|
||||
'BaseFilter',
|
||||
'MessageFilter',
|
||||
'UpdateFilter',
|
||||
'InvertedFilter',
|
||||
'MergedFilter',
|
||||
]
|
||||
|
||||
|
||||
class BaseFilter(ABC):
|
||||
|
@ -120,6 +126,7 @@ class MessageFilter(BaseFilter, ABC):
|
|||
(depends on the handler).
|
||||
|
||||
"""
|
||||
|
||||
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||
return self.filter(update.effective_message)
|
||||
|
||||
|
@ -151,12 +158,12 @@ class UpdateFilter(BaseFilter, ABC):
|
|||
(depends on the handler).
|
||||
|
||||
"""
|
||||
|
||||
def __call__(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||
return self.filter(update)
|
||||
|
||||
@abstractmethod
|
||||
def filter(self,
|
||||
update: Update) -> Optional[Union[bool, Dict]]:
|
||||
def filter(self, update: Update) -> Optional[Union[bool, Dict]]:
|
||||
"""This method must be overwritten.
|
||||
|
||||
Args:
|
||||
|
@ -175,6 +182,7 @@ class InvertedFilter(UpdateFilter):
|
|||
f: The filter to invert.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, f: BaseFilter):
|
||||
self.f = f
|
||||
|
||||
|
@ -194,22 +202,22 @@ class MergedFilter(UpdateFilter):
|
|||
or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter.
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
base_filter: BaseFilter,
|
||||
and_filter: BaseFilter = None,
|
||||
or_filter: BaseFilter = None):
|
||||
|
||||
def __init__(
|
||||
self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None
|
||||
):
|
||||
self.base_filter = base_filter
|
||||
if self.base_filter.data_filter:
|
||||
self.data_filter = True
|
||||
self.and_filter = and_filter
|
||||
if (self.and_filter
|
||||
and not isinstance(self.and_filter, bool)
|
||||
and self.and_filter.data_filter):
|
||||
if (
|
||||
self.and_filter
|
||||
and not isinstance(self.and_filter, bool)
|
||||
and self.and_filter.data_filter
|
||||
):
|
||||
self.data_filter = True
|
||||
self.or_filter = or_filter
|
||||
if (self.or_filter
|
||||
and not isinstance(self.and_filter, bool)
|
||||
and self.or_filter.data_filter):
|
||||
if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter:
|
||||
self.data_filter = True
|
||||
|
||||
def _merge(self, base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> Dict:
|
||||
|
@ -257,18 +265,17 @@ class MergedFilter(UpdateFilter):
|
|||
return False
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<{} {} {}>".format(self.base_filter, "and" if self.and_filter else "or",
|
||||
self.and_filter or self.or_filter)
|
||||
return "<{} {} {}>".format(
|
||||
self.base_filter, "and" if self.and_filter else "or", self.and_filter or self.or_filter
|
||||
)
|
||||
|
||||
|
||||
class _DiceEmoji(MessageFilter):
|
||||
|
||||
def __init__(self, emoji: str = None, name: str = None):
|
||||
self.name = 'Filters.dice.{}'.format(name) if name else 'Filters.dice'
|
||||
self.emoji = emoji
|
||||
|
||||
class _DiceValues(MessageFilter):
|
||||
|
||||
def __init__(self, values: Union[int, List[int]], name: str, emoji: str = None):
|
||||
self.values = [values] if isinstance(values, int) else values
|
||||
self.emoji = emoji
|
||||
|
@ -281,8 +288,9 @@ class _DiceEmoji(MessageFilter):
|
|||
return True
|
||||
return False
|
||||
|
||||
def __call__(self, # type: ignore[override]
|
||||
update: Union[Update, List[int]]) -> Union[bool, '_DiceValues']:
|
||||
def __call__( # type: ignore[override]
|
||||
self, update: Union[Update, List[int]]
|
||||
) -> Union[bool, '_DiceValues']:
|
||||
if isinstance(update, Update):
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
|
@ -319,7 +327,6 @@ class Filters:
|
|||
name = 'Filters.text'
|
||||
|
||||
class _TextStrings(MessageFilter):
|
||||
|
||||
def __init__(self, strings: List[str]):
|
||||
self.strings = strings
|
||||
self.name = 'Filters.text({})'.format(strings)
|
||||
|
@ -329,8 +336,9 @@ class Filters:
|
|||
return message.text in self.strings
|
||||
return False
|
||||
|
||||
def __call__(self, # type: ignore[override]
|
||||
update: Union[Update, List[str]]) -> Union[bool, '_TextStrings']:
|
||||
def __call__( # type: ignore[override]
|
||||
self, update: Union[Update, List[str]]
|
||||
) -> Union[bool, '_TextStrings']:
|
||||
if isinstance(update, Update):
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
|
@ -371,7 +379,6 @@ class Filters:
|
|||
name = 'Filters.caption'
|
||||
|
||||
class _CaptionStrings(MessageFilter):
|
||||
|
||||
def __init__(self, strings: List[str]):
|
||||
self.strings = strings
|
||||
self.name = 'Filters.caption({})'.format(strings)
|
||||
|
@ -381,8 +388,9 @@ class Filters:
|
|||
return message.caption in self.strings
|
||||
return False
|
||||
|
||||
def __call__(self, # type: ignore[override]
|
||||
update: Union[Update, List[str]]) -> Union[bool, '_CaptionStrings']:
|
||||
def __call__( # type: ignore[override]
|
||||
self, update: Union[Update, List[str]]
|
||||
) -> Union[bool, '_CaptionStrings']:
|
||||
if isinstance(update, Update):
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
|
@ -407,26 +415,30 @@ class Filters:
|
|||
name = 'Filters.command'
|
||||
|
||||
class _CommandOnlyStart(MessageFilter):
|
||||
|
||||
def __init__(self, only_start: bool):
|
||||
self.only_start = only_start
|
||||
self.name = 'Filters.command({})'.format(only_start)
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.entities
|
||||
and any([e.type == MessageEntity.BOT_COMMAND
|
||||
for e in message.entities]))
|
||||
return bool(
|
||||
message.entities
|
||||
and any([e.type == MessageEntity.BOT_COMMAND for e in message.entities])
|
||||
)
|
||||
|
||||
def __call__(self, # type: ignore[override]
|
||||
update: Union[bool, Update]) -> Union[bool, '_CommandOnlyStart']:
|
||||
def __call__( # type: ignore[override]
|
||||
self, update: Union[bool, Update]
|
||||
) -> Union[bool, '_CommandOnlyStart']:
|
||||
if isinstance(update, Update):
|
||||
return self.filter(update.effective_message)
|
||||
else:
|
||||
return self._CommandOnlyStart(update)
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.entities and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||
and message.entities[0].offset == 0)
|
||||
return bool(
|
||||
message.entities
|
||||
and message.entities[0].type == MessageEntity.BOT_COMMAND
|
||||
and message.entities[0].offset == 0
|
||||
)
|
||||
|
||||
command = _Command()
|
||||
"""
|
||||
|
@ -485,8 +497,7 @@ class Filters:
|
|||
self.pattern: Pattern = pattern
|
||||
self.name = 'Filters.regex({})'.format(self.pattern)
|
||||
|
||||
def filter(self,
|
||||
message: Message) -> Optional[Dict[str, List[Match]]]:
|
||||
def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]:
|
||||
"""""" # remove method from docs
|
||||
if message.text:
|
||||
match = self.pattern.search(message.text)
|
||||
|
@ -739,6 +750,7 @@ officedocument.wordprocessingml.document")``-
|
|||
``Filters.status_update`` for all status update messages.
|
||||
|
||||
"""
|
||||
|
||||
class _NewChatMembers(MessageFilter):
|
||||
name = 'Filters.status_update.new_chat_members'
|
||||
|
||||
|
@ -788,8 +800,11 @@ officedocument.wordprocessingml.document")``-
|
|||
name = 'Filters.status_update.chat_created'
|
||||
|
||||
def filter(self, message: Message) -> bool:
|
||||
return bool(message.group_chat_created or message.supergroup_chat_created
|
||||
or message.channel_chat_created)
|
||||
return bool(
|
||||
message.group_chat_created
|
||||
or message.supergroup_chat_created
|
||||
or message.channel_chat_created
|
||||
)
|
||||
|
||||
chat_created = _ChatCreated()
|
||||
"""Messages that contain :attr:`telegram.Message.group_chat_created`,
|
||||
|
@ -827,11 +842,17 @@ officedocument.wordprocessingml.document")``-
|
|||
name = 'Filters.status_update'
|
||||
|
||||
def filter(self, message: Update) -> bool:
|
||||
return bool(self.new_chat_members(message) or self.left_chat_member(message)
|
||||
or self.new_chat_title(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))
|
||||
return bool(
|
||||
self.new_chat_members(message)
|
||||
or self.left_chat_member(message)
|
||||
or self.new_chat_title(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()
|
||||
"""Subset for messages containing a status update.
|
||||
|
@ -976,10 +997,13 @@ officedocument.wordprocessingml.document")``-
|
|||
RuntimeError: If user_id and username are both present.
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
user_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
user_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False,
|
||||
):
|
||||
self.allow_empty = allow_empty
|
||||
self.__lock = Lock()
|
||||
|
||||
|
@ -1008,15 +1032,17 @@ officedocument.wordprocessingml.document")``-
|
|||
def _set_user_ids(self, user_id: Union[int, List[int]]) -> None:
|
||||
with self.__lock:
|
||||
if user_id and self._usernames:
|
||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
self._user_ids = self._parse_user_id(user_id)
|
||||
|
||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||
with self.__lock:
|
||||
if username and self._user_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"user_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "user_ids."
|
||||
)
|
||||
self._usernames = self._parse_username(username)
|
||||
|
||||
@property
|
||||
|
@ -1047,8 +1073,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._user_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"user_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "user_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames |= parsed_username
|
||||
|
@ -1063,8 +1090,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
|
||||
parsed_user_id = self._parse_user_id(user_id)
|
||||
|
||||
|
@ -1080,8 +1108,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._user_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"user_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "user_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames -= parsed_username
|
||||
|
@ -1096,8 +1125,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set user_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set user_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
parsed_user_id = self._parse_user_id(user_id)
|
||||
self._user_ids -= parsed_user_id
|
||||
|
||||
|
@ -1107,8 +1137,9 @@ officedocument.wordprocessingml.document")``-
|
|||
if self.user_ids:
|
||||
return message.from_user.id in self.user_ids
|
||||
if self.usernames:
|
||||
return bool(message.from_user.username
|
||||
and message.from_user.username in self.usernames)
|
||||
return bool(
|
||||
message.from_user.username and message.from_user.username in self.usernames
|
||||
)
|
||||
return self.allow_empty
|
||||
return False
|
||||
|
||||
|
@ -1145,10 +1176,13 @@ officedocument.wordprocessingml.document")``-
|
|||
Raises:
|
||||
RuntimeError: If bot_id and username are both present.
|
||||
"""
|
||||
def __init__(self,
|
||||
bot_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bot_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False,
|
||||
):
|
||||
self.allow_empty = allow_empty
|
||||
self.__lock = Lock()
|
||||
|
||||
|
@ -1177,15 +1211,17 @@ officedocument.wordprocessingml.document")``-
|
|||
def _set_bot_ids(self, bot_id: Union[int, List[int]]) -> None:
|
||||
with self.__lock:
|
||||
if bot_id and self._usernames:
|
||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
self._bot_ids = self._parse_bot_id(bot_id)
|
||||
|
||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||
with self.__lock:
|
||||
if username and self._bot_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"bot_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||
)
|
||||
self._usernames = self._parse_username(username)
|
||||
|
||||
@property
|
||||
|
@ -1216,8 +1252,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._bot_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"bot_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames |= parsed_username
|
||||
|
@ -1233,8 +1270,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
|
||||
parsed_bot_id = self._parse_bot_id(bot_id)
|
||||
|
||||
|
@ -1250,8 +1288,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._bot_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"bot_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "bot_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames -= parsed_username
|
||||
|
@ -1266,8 +1305,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set bot_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set bot_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
parsed_bot_id = self._parse_bot_id(bot_id)
|
||||
self._bot_ids -= parsed_bot_id
|
||||
|
||||
|
@ -1277,8 +1317,9 @@ officedocument.wordprocessingml.document")``-
|
|||
if self.bot_ids:
|
||||
return message.via_bot.id in self.bot_ids
|
||||
if self.usernames:
|
||||
return bool(message.via_bot.username
|
||||
and message.via_bot.username in self.usernames)
|
||||
return bool(
|
||||
message.via_bot.username and message.via_bot.username in self.usernames
|
||||
)
|
||||
return self.allow_empty
|
||||
return False
|
||||
|
||||
|
@ -1316,10 +1357,12 @@ officedocument.wordprocessingml.document")``-
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
chat_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
chat_id: Union[int, List[int]] = None,
|
||||
username: Union[str, List[str]] = None,
|
||||
allow_empty: bool = False,
|
||||
):
|
||||
self.allow_empty = allow_empty
|
||||
self.__lock = Lock()
|
||||
|
||||
|
@ -1348,15 +1391,17 @@ officedocument.wordprocessingml.document")``-
|
|||
def _set_chat_ids(self, chat_id: Union[int, List[int]]) -> None:
|
||||
with self.__lock:
|
||||
if chat_id and self._usernames:
|
||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
self._chat_ids = self._parse_chat_id(chat_id)
|
||||
|
||||
def _set_usernames(self, username: Union[str, List[str]]) -> None:
|
||||
with self.__lock:
|
||||
if username and self._chat_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"chat_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||
)
|
||||
self._usernames = self._parse_username(username)
|
||||
|
||||
@property
|
||||
|
@ -1387,8 +1432,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._chat_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"chat_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames |= parsed_username
|
||||
|
@ -1403,8 +1449,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
|
||||
parsed_chat_id = self._parse_chat_id(chat_id)
|
||||
|
||||
|
@ -1420,8 +1467,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._chat_ids:
|
||||
raise RuntimeError("Can't set username in conjunction with (already set) "
|
||||
"chat_ids.")
|
||||
raise RuntimeError(
|
||||
"Can't set username in conjunction with (already set) " "chat_ids."
|
||||
)
|
||||
|
||||
parsed_username = self._parse_username(username)
|
||||
self._usernames -= parsed_username
|
||||
|
@ -1436,8 +1484,9 @@ officedocument.wordprocessingml.document")``-
|
|||
"""
|
||||
with self.__lock:
|
||||
if self._usernames:
|
||||
raise RuntimeError("Can't set chat_id in conjunction with (already set) "
|
||||
"usernames.")
|
||||
raise RuntimeError(
|
||||
"Can't set chat_id in conjunction with (already set) " "usernames."
|
||||
)
|
||||
parsed_chat_id = self._parse_chat_id(chat_id)
|
||||
self._chat_ids -= parsed_chat_id
|
||||
|
||||
|
@ -1447,8 +1496,7 @@ officedocument.wordprocessingml.document")``-
|
|||
if self.chat_ids:
|
||||
return message.chat.id in self.chat_ids
|
||||
if self.usernames:
|
||||
return bool(message.chat.username
|
||||
and message.chat.username in self.usernames)
|
||||
return bool(message.chat.username and message.chat.username in self.usernames)
|
||||
return self.allow_empty
|
||||
return False
|
||||
|
||||
|
@ -1550,8 +1598,10 @@ officedocument.wordprocessingml.document")``-
|
|||
|
||||
def filter(self, message: Message) -> bool:
|
||||
"""""" # remove method from docs
|
||||
return bool(message.from_user.language_code and any(
|
||||
[message.from_user.language_code.startswith(x) for x in self.lang]))
|
||||
return bool(
|
||||
message.from_user.language_code
|
||||
and any([message.from_user.language_code.startswith(x) for x in self.lang])
|
||||
)
|
||||
|
||||
class _UpdateType(UpdateFilter):
|
||||
name = 'Filters.update'
|
||||
|
|
|
@ -24,6 +24,7 @@ from telegram.utils.promise import Promise
|
|||
from telegram.utils.types import HandlerArg
|
||||
from telegram import Update
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -87,13 +88,16 @@ class Handler(ABC):
|
|||
Defaults to :obj:`False`.
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
self.callback: Callable[[HandlerArg, 'CallbackContext'], RT] = callback
|
||||
self.pass_update_queue = pass_update_queue
|
||||
self.pass_job_queue = pass_job_queue
|
||||
|
@ -117,11 +121,13 @@ class Handler(ABC):
|
|||
|
||||
"""
|
||||
|
||||
def handle_update(self,
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: object,
|
||||
context: 'CallbackContext' = None) -> Union[RT, Promise]:
|
||||
def handle_update(
|
||||
self,
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: object,
|
||||
context: 'CallbackContext' = None,
|
||||
) -> Union[RT, Promise]:
|
||||
"""
|
||||
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
|
||||
|
@ -146,16 +152,19 @@ class Handler(ABC):
|
|||
else:
|
||||
optional_args = self.collect_optional_args(dispatcher, update, check_result)
|
||||
if self.run_async:
|
||||
return dispatcher.run_async(self.callback, dispatcher.bot, update, update=update,
|
||||
**optional_args)
|
||||
return dispatcher.run_async(
|
||||
self.callback, dispatcher.bot, update, update=update, **optional_args
|
||||
)
|
||||
else:
|
||||
return self.callback(dispatcher.bot, update, **optional_args) # type: ignore
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Any) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Any,
|
||||
) -> None:
|
||||
"""Prepares additional arguments for the context. Override if needed.
|
||||
|
||||
Args:
|
||||
|
@ -167,10 +176,9 @@ class Handler(ABC):
|
|||
"""
|
||||
pass
|
||||
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Any = None) -> Dict[str, Any]:
|
||||
def collect_optional_args(
|
||||
self, dispatcher: 'Dispatcher', update: HandlerArg = None, check_result: Any = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Prepares the optional arguments. If the handler has additional optional args,
|
||||
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):
|
||||
user = update.effective_user
|
||||
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):
|
||||
chat = update.effective_chat
|
||||
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
|
||||
|
|
|
@ -24,8 +24,18 @@ from telegram import Update
|
|||
from .handler import Handler
|
||||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern, Match, \
|
||||
cast
|
||||
from typing import (
|
||||
Callable,
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Optional,
|
||||
Union,
|
||||
TypeVar,
|
||||
Dict,
|
||||
Pattern,
|
||||
Match,
|
||||
cast,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
@ -110,23 +120,26 @@ class InlineQueryHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pattern: Union[str, Pattern] = None,
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
if isinstance(pattern, str):
|
||||
pattern = re.compile(pattern)
|
||||
|
@ -157,10 +170,12 @@ class InlineQueryHandler(Handler):
|
|||
return True
|
||||
return None
|
||||
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Match]] = None) -> Dict[str, Any]:
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Match]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
check_result = cast(Match, check_result)
|
||||
|
@ -170,11 +185,13 @@ class InlineQueryHandler(Handler):
|
|||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Match]]) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Match]],
|
||||
) -> None:
|
||||
if self.pattern:
|
||||
check_result = cast(Match, 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 telegram.utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import Dispatcher
|
||||
from telegram import Bot
|
||||
|
@ -56,8 +57,9 @@ class JobQueue:
|
|||
self._dispatcher: 'Dispatcher' = None # type: ignore[assignment]
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
self.scheduler = BackgroundScheduler(timezone=pytz.utc)
|
||||
self.scheduler.add_listener(self._update_persistence,
|
||||
mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR)
|
||||
self.scheduler.add_listener(
|
||||
self._update_persistence, mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR
|
||||
)
|
||||
|
||||
# Dispatch errors and don't log them in the APS logger
|
||||
def aps_log_filter(record): # type: ignore
|
||||
|
@ -82,25 +84,29 @@ class JobQueue:
|
|||
self._dispatcher.dispatch_error(None, event.exception)
|
||||
# Errors should not stop the thread.
|
||||
except Exception:
|
||||
self.logger.exception('An error was raised while processing the job and an '
|
||||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.')
|
||||
self.logger.exception(
|
||||
'An error was raised while processing the job and an '
|
||||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.'
|
||||
)
|
||||
|
||||
@overload
|
||||
def _parse_time_input(self, time: None, shift_day: bool = False) -> None:
|
||||
...
|
||||
|
||||
@overload
|
||||
def _parse_time_input(self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
||||
datetime.time],
|
||||
shift_day: bool = False) -> datetime.datetime:
|
||||
def _parse_time_input(
|
||||
self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
shift_day: bool = False,
|
||||
) -> datetime.datetime:
|
||||
...
|
||||
|
||||
def _parse_time_input(self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime,
|
||||
datetime.time, None],
|
||||
shift_day: bool = False) -> Optional[datetime.datetime]:
|
||||
def _parse_time_input(
|
||||
self,
|
||||
time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time, None],
|
||||
shift_day: bool = False,
|
||||
) -> Optional[datetime.datetime]:
|
||||
if time is None:
|
||||
return None
|
||||
if isinstance(time, (int, float)):
|
||||
|
@ -109,7 +115,8 @@ class JobQueue:
|
|||
return self._tz_now() + time
|
||||
if isinstance(time, datetime.time):
|
||||
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:
|
||||
dt = self.scheduler.timezone.localize(dt)
|
||||
if shift_day and dt <= datetime.datetime.now(pytz.utc):
|
||||
|
@ -131,12 +138,14 @@ class JobQueue:
|
|||
if dispatcher.bot.defaults:
|
||||
self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc)
|
||||
|
||||
def run_once(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
def run_once(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: Union[float, datetime.timedelta, datetime.datetime, datetime.time],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None,
|
||||
) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs once and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -183,27 +192,29 @@ class JobQueue:
|
|||
job = Job(callback, context, name, self)
|
||||
dt = self._parse_time_input(when, shift_day=True)
|
||||
|
||||
j = self.scheduler.add_job(callback,
|
||||
name=name,
|
||||
trigger='date',
|
||||
run_date=dt,
|
||||
args=self._build_args(job),
|
||||
timezone=dt.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs)
|
||||
j = self.scheduler.add_job(
|
||||
callback,
|
||||
name=name,
|
||||
trigger='date',
|
||||
run_date=dt,
|
||||
args=self._build_args(job),
|
||||
timezone=dt.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs,
|
||||
)
|
||||
|
||||
job.job = j
|
||||
return job
|
||||
|
||||
def run_repeating(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
interval: Union[float, datetime.timedelta],
|
||||
first: Union[float, datetime.timedelta, datetime.datetime,
|
||||
datetime.time] = None,
|
||||
last: Union[float, datetime.timedelta, datetime.datetime,
|
||||
datetime.time] = None,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
def run_repeating(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
interval: Union[float, datetime.timedelta],
|
||||
first: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None,
|
||||
last: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None,
|
||||
) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs at specified intervals and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -277,26 +288,30 @@ class JobQueue:
|
|||
if isinstance(interval, datetime.timedelta):
|
||||
interval = interval.total_seconds()
|
||||
|
||||
j = self.scheduler.add_job(callback,
|
||||
trigger='interval',
|
||||
args=self._build_args(job),
|
||||
start_date=dt_first,
|
||||
end_date=dt_last,
|
||||
seconds=interval,
|
||||
name=name,
|
||||
**job_kwargs)
|
||||
j = self.scheduler.add_job(
|
||||
callback,
|
||||
trigger='interval',
|
||||
args=self._build_args(job),
|
||||
start_date=dt_first,
|
||||
end_date=dt_last,
|
||||
seconds=interval,
|
||||
name=name,
|
||||
**job_kwargs,
|
||||
)
|
||||
|
||||
job.job = j
|
||||
return job
|
||||
|
||||
def run_monthly(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: datetime.time,
|
||||
day: int,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
day_is_strict: bool = True,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
def run_monthly(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
when: datetime.time,
|
||||
day: int,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
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.
|
||||
|
||||
Args:
|
||||
|
@ -332,45 +347,55 @@ class JobQueue:
|
|||
job = Job(callback, context, name, self)
|
||||
|
||||
if day_is_strict:
|
||||
j = self.scheduler.add_job(callback,
|
||||
trigger='cron',
|
||||
args=self._build_args(job),
|
||||
name=name,
|
||||
day=day,
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs)
|
||||
j = self.scheduler.add_job(
|
||||
callback,
|
||||
trigger='cron',
|
||||
args=self._build_args(job),
|
||||
name=name,
|
||||
day=day,
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs,
|
||||
)
|
||||
else:
|
||||
trigger = OrTrigger([CronTrigger(day=day,
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo,
|
||||
**job_kwargs),
|
||||
CronTrigger(day='last',
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs)])
|
||||
j = self.scheduler.add_job(callback,
|
||||
trigger=trigger,
|
||||
args=self._build_args(job),
|
||||
name=name,
|
||||
**job_kwargs)
|
||||
trigger = OrTrigger(
|
||||
[
|
||||
CronTrigger(
|
||||
day=day,
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo,
|
||||
**job_kwargs,
|
||||
),
|
||||
CronTrigger(
|
||||
day='last',
|
||||
hour=when.hour,
|
||||
minute=when.minute,
|
||||
second=when.second,
|
||||
timezone=when.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs,
|
||||
),
|
||||
]
|
||||
)
|
||||
j = self.scheduler.add_job(
|
||||
callback, trigger=trigger, args=self._build_args(job), name=name, **job_kwargs
|
||||
)
|
||||
|
||||
job.job = j
|
||||
return job
|
||||
|
||||
def run_daily(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
time: datetime.time,
|
||||
days: Tuple[int, ...] = Days.EVERY_DAY,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None) -> 'Job':
|
||||
def run_daily(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
time: datetime.time,
|
||||
days: Tuple[int, ...] = Days.EVERY_DAY,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_kwargs: JSONDict = None,
|
||||
) -> 'Job':
|
||||
"""Creates a new ``Job`` that runs on a daily basis and adds it to the queue.
|
||||
|
||||
Args:
|
||||
|
@ -409,25 +434,29 @@ class JobQueue:
|
|||
name = name or callback.__name__
|
||||
job = Job(callback, context, name, self)
|
||||
|
||||
j = self.scheduler.add_job(callback,
|
||||
name=name,
|
||||
args=self._build_args(job),
|
||||
trigger='cron',
|
||||
day_of_week=','.join([str(d) for d in days]),
|
||||
hour=time.hour,
|
||||
minute=time.minute,
|
||||
second=time.second,
|
||||
timezone=time.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs)
|
||||
j = self.scheduler.add_job(
|
||||
callback,
|
||||
name=name,
|
||||
args=self._build_args(job),
|
||||
trigger='cron',
|
||||
day_of_week=','.join([str(d) for d in days]),
|
||||
hour=time.hour,
|
||||
minute=time.minute,
|
||||
second=time.second,
|
||||
timezone=time.tzinfo or self.scheduler.timezone,
|
||||
**job_kwargs,
|
||||
)
|
||||
|
||||
job.job = j
|
||||
return job
|
||||
|
||||
def run_custom(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
job_kwargs: JSONDict,
|
||||
context: object = None,
|
||||
name: str = None) -> 'Job':
|
||||
def run_custom(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
job_kwargs: JSONDict,
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
) -> 'Job':
|
||||
"""Creates a new customly defined ``Job``.
|
||||
|
||||
Args:
|
||||
|
@ -453,10 +482,7 @@ class JobQueue:
|
|||
name = name or callback.__name__
|
||||
job = Job(callback, context, name, self)
|
||||
|
||||
j = self.scheduler.add_job(callback,
|
||||
args=self._build_args(job),
|
||||
name=name,
|
||||
**job_kwargs)
|
||||
j = self.scheduler.add_job(callback, args=self._build_args(job), name=name, **job_kwargs)
|
||||
|
||||
job.job = j
|
||||
return job
|
||||
|
@ -516,12 +542,14 @@ class Job:
|
|||
job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_queue: JobQueue = None,
|
||||
job: 'Job' = None):
|
||||
def __init__(
|
||||
self,
|
||||
callback: Callable[['CallbackContext'], None],
|
||||
context: object = None,
|
||||
name: str = None,
|
||||
job_queue: JobQueue = None,
|
||||
job: 'Job' = None,
|
||||
):
|
||||
|
||||
self.callback = callback
|
||||
self.context = context
|
||||
|
@ -545,9 +573,11 @@ class Job:
|
|||
dispatcher.dispatch_error(None, e)
|
||||
# Errors should not stop the thread.
|
||||
except Exception:
|
||||
dispatcher.logger.exception('An error was raised while processing the job and an '
|
||||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.')
|
||||
dispatcher.logger.exception(
|
||||
'An error was raised while processing the job and an '
|
||||
'uncaught error was raised while handling the error '
|
||||
'with an error_handler.'
|
||||
)
|
||||
|
||||
def schedule_removal(self) -> None:
|
||||
"""
|
||||
|
|
|
@ -28,6 +28,7 @@ from .handler import Handler
|
|||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -120,17 +121,19 @@ class MessageHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
filters: BaseFilter,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
message_updates: bool = None,
|
||||
channel_post_updates: bool = None,
|
||||
edited_updates: bool = None,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
filters: BaseFilter,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
message_updates: bool = None,
|
||||
channel_post_updates: bool = None,
|
||||
edited_updates: bool = None,
|
||||
run_async: bool = False,
|
||||
):
|
||||
|
||||
super().__init__(
|
||||
callback,
|
||||
|
@ -138,36 +141,44 @@ class MessageHandler(Handler):
|
|||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_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:
|
||||
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:
|
||||
self.filters = Filters.update & filters
|
||||
else:
|
||||
self.filters = Filters.update
|
||||
if message_updates is not None:
|
||||
warnings.warn('message_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.warn(
|
||||
'message_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if message_updates is False:
|
||||
self.filters &= ~Filters.update.message
|
||||
|
||||
if channel_post_updates is not None:
|
||||
warnings.warn('channel_post_updates is deprecated. See https://git.io/fxJuV '
|
||||
'for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.warn(
|
||||
'channel_post_updates is deprecated. See https://git.io/fxJuV ' 'for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if channel_post_updates is False:
|
||||
self.filters &= ~Filters.update.channel_post
|
||||
|
||||
if edited_updates is not None:
|
||||
warnings.warn('edited_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.warn(
|
||||
'edited_updates is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
if edited_updates is False:
|
||||
self.filters &= ~(Filters.update.edited_message
|
||||
| Filters.update.edited_channel_post)
|
||||
self.filters &= ~(
|
||||
Filters.update.edited_message | Filters.update.edited_channel_post
|
||||
)
|
||||
|
||||
def check_update(self, update: HandlerArg) -> Optional[Union[bool, Dict[str, Any]]]:
|
||||
"""Determines whether an update should be passed to this handlers :attr:`callback`.
|
||||
|
@ -183,10 +194,12 @@ class MessageHandler(Handler):
|
|||
return self.filters(update)
|
||||
return None
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]]) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]],
|
||||
) -> None:
|
||||
if isinstance(check_result, dict):
|
||||
context.update(check_result)
|
||||
|
|
|
@ -38,6 +38,7 @@ curtime = time.perf_counter
|
|||
|
||||
class DelayQueueError(RuntimeError):
|
||||
"""Indicates processing errors."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -75,17 +76,19 @@ class DelayQueue(threading.Thread):
|
|||
|
||||
_instcnt = 0 # instance counter
|
||||
|
||||
def __init__(self,
|
||||
queue: q.Queue = None,
|
||||
burst_limit: int = 30,
|
||||
time_limit_ms: int = 1000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True,
|
||||
name: str = None):
|
||||
def __init__(
|
||||
self,
|
||||
queue: q.Queue = None,
|
||||
burst_limit: int = 30,
|
||||
time_limit_ms: int = 1000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True,
|
||||
name: str = None,
|
||||
):
|
||||
self._queue = queue if queue is not None else q.Queue()
|
||||
self.burst_limit = burst_limit
|
||||
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.__class__._instcnt += 1
|
||||
if name is None:
|
||||
|
@ -201,24 +204,28 @@ class MessageQueue:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
all_burst_limit: int = 30,
|
||||
all_time_limit_ms: int = 1000,
|
||||
group_burst_limit: int = 20,
|
||||
group_time_limit_ms: int = 60000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True):
|
||||
def __init__(
|
||||
self,
|
||||
all_burst_limit: int = 30,
|
||||
all_time_limit_ms: int = 1000,
|
||||
group_burst_limit: int = 20,
|
||||
group_time_limit_ms: int = 60000,
|
||||
exc_route: Callable[[Exception], None] = None,
|
||||
autostart: bool = True,
|
||||
):
|
||||
# create according delay queues, use composition
|
||||
self._all_delayq = DelayQueue(
|
||||
burst_limit=all_burst_limit,
|
||||
time_limit_ms=all_time_limit_ms,
|
||||
exc_route=exc_route,
|
||||
autostart=autostart)
|
||||
autostart=autostart,
|
||||
)
|
||||
self._group_delayq = DelayQueue(
|
||||
burst_limit=group_burst_limit,
|
||||
time_limit_ms=group_time_limit_ms,
|
||||
exc_route=exc_route,
|
||||
autostart=autostart)
|
||||
autostart=autostart,
|
||||
)
|
||||
|
||||
def start(self) -> None:
|
||||
"""Method is used to manually start the ``MessageQueue`` processing."""
|
||||
|
@ -297,11 +304,12 @@ def queuedmessage(method: Callable) -> Callable:
|
|||
|
||||
@functools.wraps(method)
|
||||
def wrapped(self: 'Bot', *args: Any, **kwargs: Any) -> Any:
|
||||
queued = kwargs.pop('queued',
|
||||
self._is_messages_queued_default) # type: ignore[attr-defined]
|
||||
queued = kwargs.pop(
|
||||
'queued', self._is_messages_queued_default # type: ignore[attr-defined]
|
||||
)
|
||||
isgroup = kwargs.pop('isgroup', False)
|
||||
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 method(self, *args, **kwargs)
|
||||
|
||||
|
|
|
@ -74,16 +74,20 @@ class PicklePersistence(BasePersistence):
|
|||
Default is :obj:`False`.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
filename: str,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
single_file: bool = True,
|
||||
on_flush: bool = False):
|
||||
super().__init__(store_user_data=store_user_data,
|
||||
store_chat_data=store_chat_data,
|
||||
store_bot_data=store_bot_data)
|
||||
def __init__(
|
||||
self,
|
||||
filename: str,
|
||||
store_user_data: bool = True,
|
||||
store_chat_data: bool = True,
|
||||
store_bot_data: bool = True,
|
||||
single_file: bool = True,
|
||||
on_flush: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
store_user_data=store_user_data,
|
||||
store_chat_data=store_chat_data,
|
||||
store_bot_data=store_bot_data,
|
||||
)
|
||||
self.filename = filename
|
||||
self.single_file = single_file
|
||||
self.on_flush = on_flush
|
||||
|
@ -125,8 +129,12 @@ class PicklePersistence(BasePersistence):
|
|||
|
||||
def dump_singlefile(self) -> None:
|
||||
with open(self.filename, "wb") as f:
|
||||
data = {'conversations': self.conversations, 'user_data': self.user_data,
|
||||
'chat_data': self.chat_data, 'bot_data': self.bot_data}
|
||||
data = {
|
||||
'conversations': self.conversations,
|
||||
'user_data': self.user_data,
|
||||
'chat_data': self.chat_data,
|
||||
'bot_data': self.bot_data,
|
||||
}
|
||||
pickle.dump(data, f)
|
||||
|
||||
def dump_file(self, filename: str, data: Any) -> None:
|
||||
|
@ -212,9 +220,9 @@ class PicklePersistence(BasePersistence):
|
|||
self.load_singlefile()
|
||||
return self.conversations.get(name, {}).copy() # type: ignore[union-attr]
|
||||
|
||||
def update_conversation(self,
|
||||
name: str, key: Tuple[int, ...],
|
||||
new_state: Optional[object]) -> None:
|
||||
def update_conversation(
|
||||
self, name: str, key: Tuple[int, ...], new_state: Optional[object]
|
||||
) -> None:
|
||||
"""Will update the conversations for the given handler and depending on :attr:`on_flush`
|
||||
save the pickle file.
|
||||
|
||||
|
@ -290,8 +298,7 @@ class PicklePersistence(BasePersistence):
|
|||
self.dump_singlefile()
|
||||
|
||||
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.user_data or self.chat_data or self.bot_data or self.conversations:
|
||||
self.dump_singlefile()
|
||||
|
|
|
@ -27,6 +27,7 @@ from telegram.ext import MessageHandler, Filters
|
|||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, Union, TypeVar, Dict, Pattern
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -108,41 +109,48 @@ class RegexHandler(MessageHandler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
allow_edited: bool = False,
|
||||
message_updates: bool = True,
|
||||
channel_post_updates: bool = False,
|
||||
edited_updates: bool = False,
|
||||
run_async: bool = False):
|
||||
warnings.warn('RegexHandler is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
super().__init__(Filters.regex(pattern),
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
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)
|
||||
def __init__(
|
||||
self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
pass_user_data: bool = False,
|
||||
pass_chat_data: bool = False,
|
||||
allow_edited: bool = False,
|
||||
message_updates: bool = True,
|
||||
channel_post_updates: bool = False,
|
||||
edited_updates: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
warnings.warn(
|
||||
'RegexHandler is deprecated. See https://git.io/fxJuV for more info',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
super().__init__(
|
||||
Filters.regex(pattern),
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
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_groupdict = pass_groupdict
|
||||
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]] = None) -> Dict[str, Any]:
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Union[bool, Dict[str, Any]]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if isinstance(check_result, dict):
|
||||
if self.pass_groups:
|
||||
|
|
|
@ -22,6 +22,7 @@ from .handler import Handler
|
|||
|
||||
from telegram.utils.types import HandlerArg
|
||||
from typing import Callable, TYPE_CHECKING, Any, Optional, TypeVar, Dict, List
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -80,18 +81,21 @@ class StringCommandHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
command: str,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
command: str,
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_args: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
self.command = command
|
||||
self.pass_args = pass_args
|
||||
|
||||
|
@ -111,18 +115,22 @@ class StringCommandHandler(Handler):
|
|||
return args[1:]
|
||||
return None
|
||||
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[List[str]] = None) -> Dict[str, Any]:
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[List[str]] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pass_args:
|
||||
optional_args['args'] = check_result
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[List[str]]) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[List[str]],
|
||||
) -> None:
|
||||
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 telegram.utils.types import HandlerArg
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram.ext import CallbackContext, Dispatcher
|
||||
|
||||
|
@ -90,19 +91,22 @@ class StringRegexHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
pattern: Union[str, Pattern],
|
||||
callback: Callable[[HandlerArg, 'CallbackContext'], RT],
|
||||
pass_groups: bool = False,
|
||||
pass_groupdict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
|
||||
if isinstance(pattern, str):
|
||||
pattern = re.compile(pattern)
|
||||
|
@ -127,10 +131,12 @@ class StringRegexHandler(Handler):
|
|||
return match
|
||||
return None
|
||||
|
||||
def collect_optional_args(self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Match] = None) -> Dict[str, Any]:
|
||||
def collect_optional_args(
|
||||
self,
|
||||
dispatcher: 'Dispatcher',
|
||||
update: HandlerArg = None,
|
||||
check_result: Optional[Match] = None,
|
||||
) -> Dict[str, Any]:
|
||||
optional_args = super().collect_optional_args(dispatcher, update, check_result)
|
||||
if self.pattern:
|
||||
if self.pass_groups and check_result:
|
||||
|
@ -139,10 +145,12 @@ class StringRegexHandler(Handler):
|
|||
optional_args['groupdict'] = check_result.groupdict()
|
||||
return optional_args
|
||||
|
||||
def collect_additional_context(self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Match]) -> None:
|
||||
def collect_additional_context(
|
||||
self,
|
||||
context: 'CallbackContext',
|
||||
update: HandlerArg,
|
||||
dispatcher: 'Dispatcher',
|
||||
check_result: Optional[Match],
|
||||
) -> None:
|
||||
if self.pattern and check_result:
|
||||
context.matches = [check_result]
|
||||
|
|
|
@ -74,18 +74,21 @@ class TypeHandler(Handler):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
type: Type,
|
||||
callback: Callable[[Any, 'CallbackContext'], RT],
|
||||
strict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False):
|
||||
def __init__(
|
||||
self,
|
||||
type: Type,
|
||||
callback: Callable[[Any, 'CallbackContext'], RT],
|
||||
strict: bool = False,
|
||||
pass_update_queue: bool = False,
|
||||
pass_job_queue: bool = False,
|
||||
run_async: bool = False,
|
||||
):
|
||||
super().__init__(
|
||||
callback,
|
||||
pass_update_queue=pass_update_queue,
|
||||
pass_job_queue=pass_job_queue,
|
||||
run_async=run_async)
|
||||
run_async=run_async,
|
||||
)
|
||||
self.type = type
|
||||
self.strict = strict
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ from telegram.error import Unauthorized, InvalidToken, RetryAfter, TimedOut
|
|||
from telegram.utils.deprecate import TelegramDeprecationWarning
|
||||
from telegram.utils.helpers import get_signal_name
|
||||
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
|
||||
|
||||
|
@ -108,26 +108,30 @@ class Updater:
|
|||
|
||||
_request = None
|
||||
|
||||
def __init__(self,
|
||||
token: str = None,
|
||||
base_url: str = None,
|
||||
workers: int = 4,
|
||||
bot: Bot = None,
|
||||
private_key: bytes = None,
|
||||
private_key_password: bytes = None,
|
||||
user_sig_handler: Callable = None,
|
||||
request_kwargs: Dict[str, Any] = None,
|
||||
persistence: 'BasePersistence' = None,
|
||||
defaults: 'Defaults' = None,
|
||||
use_context: bool = True,
|
||||
dispatcher: Dispatcher = None,
|
||||
base_file_url: str = None):
|
||||
def __init__(
|
||||
self,
|
||||
token: str = None,
|
||||
base_url: str = None,
|
||||
workers: int = 4,
|
||||
bot: Bot = None,
|
||||
private_key: bytes = None,
|
||||
private_key_password: bytes = None,
|
||||
user_sig_handler: Callable = None,
|
||||
request_kwargs: Dict[str, Any] = None,
|
||||
persistence: 'BasePersistence' = None,
|
||||
defaults: 'Defaults' = None,
|
||||
use_context: bool = True,
|
||||
dispatcher: Dispatcher = None,
|
||||
base_file_url: str = None,
|
||||
):
|
||||
|
||||
if defaults and bot:
|
||||
warnings.warn('Passing defaults to an Updater has no effect when a Bot is passed '
|
||||
'as well. Pass them to the Bot instead.',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2)
|
||||
warnings.warn(
|
||||
'Passing defaults to an Updater has no effect when a Bot is passed '
|
||||
'as well. Pass them to the Bot instead.',
|
||||
TelegramDeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
if dispatcher 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:
|
||||
self.logger.warning(
|
||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
||||
con_pool_size)
|
||||
con_pool_size,
|
||||
)
|
||||
else:
|
||||
# we need a connection pool the size of:
|
||||
# * for each of the workers
|
||||
|
@ -169,24 +174,28 @@ class Updater:
|
|||
if 'con_pool_size' not in request_kwargs:
|
||||
request_kwargs['con_pool_size'] = con_pool_size
|
||||
self._request = Request(**request_kwargs)
|
||||
self.bot = Bot(token, # type: ignore[arg-type]
|
||||
base_url,
|
||||
base_file_url=base_file_url,
|
||||
request=self._request,
|
||||
private_key=private_key,
|
||||
private_key_password=private_key_password,
|
||||
defaults=defaults)
|
||||
self.bot = Bot(
|
||||
token, # type: ignore[arg-type]
|
||||
base_url,
|
||||
base_file_url=base_file_url,
|
||||
request=self._request,
|
||||
private_key=private_key,
|
||||
private_key_password=private_key_password,
|
||||
defaults=defaults,
|
||||
)
|
||||
self.update_queue: Queue = Queue()
|
||||
self.job_queue = JobQueue()
|
||||
self.__exception_event = Event()
|
||||
self.persistence = persistence
|
||||
self.dispatcher = Dispatcher(self.bot,
|
||||
self.update_queue,
|
||||
job_queue=self.job_queue,
|
||||
workers=workers,
|
||||
exception_event=self.__exception_event,
|
||||
persistence=persistence,
|
||||
use_context=use_context)
|
||||
self.dispatcher = Dispatcher(
|
||||
self.bot,
|
||||
self.update_queue,
|
||||
job_queue=self.job_queue,
|
||||
workers=workers,
|
||||
exception_event=self.__exception_event,
|
||||
persistence=persistence,
|
||||
use_context=use_context,
|
||||
)
|
||||
self.job_queue.set_dispatcher(self.dispatcher)
|
||||
else:
|
||||
con_pool_size = dispatcher.workers + 4
|
||||
|
@ -195,7 +204,8 @@ class Updater:
|
|||
if self.bot.request.con_pool_size < con_pool_size:
|
||||
self.logger.warning(
|
||||
'Connection pool of Request object is smaller than optimal value (%s)',
|
||||
con_pool_size)
|
||||
con_pool_size,
|
||||
)
|
||||
self.update_queue = dispatcher.update_queue
|
||||
self.__exception_event = dispatcher.exception_event
|
||||
self.persistence = dispatcher.persistence
|
||||
|
@ -211,10 +221,12 @@ class Updater:
|
|||
self.__threads: List[Thread] = []
|
||||
|
||||
def _init_thread(self, target: Callable, name: str, *args: Any, **kwargs: Any) -> None:
|
||||
thr = Thread(target=self._thread_wrapper,
|
||||
name="Bot:{}:{}".format(self.bot.id, name),
|
||||
args=(target,) + args,
|
||||
kwargs=kwargs)
|
||||
thr = Thread(
|
||||
target=self._thread_wrapper,
|
||||
name="Bot:{}:{}".format(self.bot.id, name),
|
||||
args=(target,) + args,
|
||||
kwargs=kwargs,
|
||||
)
|
||||
thr.start()
|
||||
self.__threads.append(thr)
|
||||
|
||||
|
@ -229,13 +241,15 @@ class Updater:
|
|||
raise
|
||||
self.logger.debug('{} - ended'.format(thr_name))
|
||||
|
||||
def start_polling(self,
|
||||
poll_interval: float = 0.0,
|
||||
timeout: float = 10,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = -1,
|
||||
read_latency: float = 2.,
|
||||
allowed_updates: List[str] = None) -> Optional[Queue]:
|
||||
def start_polling(
|
||||
self,
|
||||
poll_interval: float = 0.0,
|
||||
timeout: float = 10,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = -1,
|
||||
read_latency: float = 2.0,
|
||||
allowed_updates: List[str] = None,
|
||||
) -> Optional[Queue]:
|
||||
"""Starts polling updates from Telegram.
|
||||
|
||||
Args:
|
||||
|
@ -270,9 +284,17 @@ class Updater:
|
|||
dispatcher_ready = Event()
|
||||
polling_ready = Event()
|
||||
self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready)
|
||||
self._init_thread(self._start_polling, "updater", poll_interval, timeout,
|
||||
read_latency, bootstrap_retries, clean, allowed_updates,
|
||||
ready=polling_ready)
|
||||
self._init_thread(
|
||||
self._start_polling,
|
||||
"updater",
|
||||
poll_interval,
|
||||
timeout,
|
||||
read_latency,
|
||||
bootstrap_retries,
|
||||
clean,
|
||||
allowed_updates,
|
||||
ready=polling_ready,
|
||||
)
|
||||
|
||||
self.logger.debug('Waiting for Dispatcher and polling to start')
|
||||
dispatcher_ready.wait()
|
||||
|
@ -282,17 +304,19 @@ class Updater:
|
|||
return self.update_queue
|
||||
return None
|
||||
|
||||
def start_webhook(self,
|
||||
listen: str = '127.0.0.1',
|
||||
port: int = 80,
|
||||
url_path: str = '',
|
||||
cert: str = None,
|
||||
key: str = None,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = 0,
|
||||
webhook_url: str = None,
|
||||
allowed_updates: List[str] = None,
|
||||
force_event_loop: bool = False) -> Optional[Queue]:
|
||||
def start_webhook(
|
||||
self,
|
||||
listen: str = '127.0.0.1',
|
||||
port: int = 80,
|
||||
url_path: str = '',
|
||||
cert: str = None,
|
||||
key: str = None,
|
||||
clean: bool = False,
|
||||
bootstrap_retries: int = 0,
|
||||
webhook_url: str = None,
|
||||
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
|
||||
and key are not provided, the webhook will be started directly on
|
||||
|
@ -344,9 +368,21 @@ class Updater:
|
|||
dispatcher_ready = Event()
|
||||
self.job_queue.start()
|
||||
self._init_thread(self.dispatcher.start, "dispatcher", dispatcher_ready)
|
||||
self._init_thread(self._start_webhook, "updater", listen, port, url_path, cert,
|
||||
key, bootstrap_retries, clean, webhook_url, allowed_updates,
|
||||
ready=webhook_ready, force_event_loop=force_event_loop)
|
||||
self._init_thread(
|
||||
self._start_webhook,
|
||||
"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')
|
||||
webhook_ready.wait()
|
||||
|
@ -357,8 +393,16 @@ class Updater:
|
|||
return None
|
||||
|
||||
@no_type_check
|
||||
def _start_polling(self, poll_interval, timeout, read_latency, bootstrap_retries, clean,
|
||||
allowed_updates, ready=None): # pragma: no cover
|
||||
def _start_polling(
|
||||
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
|
||||
# updates from Telegram and inserts them in the update queue of the
|
||||
# Dispatcher.
|
||||
|
@ -370,10 +414,12 @@ class Updater:
|
|||
self.logger.debug('Bootstrap done')
|
||||
|
||||
def polling_action_cb():
|
||||
updates = self.bot.get_updates(self.last_update_id,
|
||||
timeout=timeout,
|
||||
read_latency=read_latency,
|
||||
allowed_updates=allowed_updates)
|
||||
updates = self.bot.get_updates(
|
||||
self.last_update_id,
|
||||
timeout=timeout,
|
||||
read_latency=read_latency,
|
||||
allowed_updates=allowed_updates,
|
||||
)
|
||||
|
||||
if updates:
|
||||
if not self.running:
|
||||
|
@ -393,8 +439,9 @@ class Updater:
|
|||
if ready is not None:
|
||||
ready.set()
|
||||
|
||||
self._network_loop_retry(polling_action_cb, polling_onerr_cb, 'getting Updates',
|
||||
poll_interval)
|
||||
self._network_loop_retry(
|
||||
polling_action_cb, polling_onerr_cb, 'getting Updates', poll_interval
|
||||
)
|
||||
|
||||
@no_type_check
|
||||
def _network_loop_retry(self, action_cb, onerr_cb, description, interval):
|
||||
|
@ -450,8 +497,20 @@ class Updater:
|
|||
return current_interval
|
||||
|
||||
@no_type_check
|
||||
def _start_webhook(self, listen, port, url_path, cert, key, bootstrap_retries, clean,
|
||||
webhook_url, allowed_updates, ready=None, force_event_loop=False):
|
||||
def _start_webhook(
|
||||
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)')
|
||||
use_ssl = cert is not None and key is not None
|
||||
if not url_path.startswith('/'):
|
||||
|
@ -479,14 +538,18 @@ class Updater:
|
|||
if not webhook_url:
|
||||
webhook_url = self._gen_webhook_url(listen, port, url_path)
|
||||
|
||||
self._bootstrap(max_retries=bootstrap_retries,
|
||||
clean=clean,
|
||||
webhook_url=webhook_url,
|
||||
cert=open(cert, 'rb'),
|
||||
allowed_updates=allowed_updates)
|
||||
self._bootstrap(
|
||||
max_retries=bootstrap_retries,
|
||||
clean=clean,
|
||||
webhook_url=webhook_url,
|
||||
cert=open(cert, 'rb'),
|
||||
allowed_updates=allowed_updates,
|
||||
)
|
||||
elif clean:
|
||||
self.logger.warning("cleaning updates is not supported if "
|
||||
"SSL-termination happens elsewhere; skipping")
|
||||
self.logger.warning(
|
||||
"cleaning updates is not supported if "
|
||||
"SSL-termination happens elsewhere; skipping"
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
@no_type_check
|
||||
def _bootstrap(self,
|
||||
max_retries,
|
||||
clean,
|
||||
webhook_url,
|
||||
allowed_updates,
|
||||
cert=None,
|
||||
bootstrap_interval=5):
|
||||
def _bootstrap(
|
||||
self, max_retries, clean, webhook_url, allowed_updates, cert=None, bootstrap_interval=5
|
||||
):
|
||||
retries = [0]
|
||||
|
||||
def bootstrap_del_webhook():
|
||||
|
@ -516,16 +575,17 @@ class Updater:
|
|||
return False
|
||||
|
||||
def bootstrap_set_webhook():
|
||||
self.bot.set_webhook(url=webhook_url,
|
||||
certificate=cert,
|
||||
allowed_updates=allowed_updates)
|
||||
self.bot.set_webhook(
|
||||
url=webhook_url, certificate=cert, allowed_updates=allowed_updates
|
||||
)
|
||||
return False
|
||||
|
||||
def bootstrap_onerr_cb(exc):
|
||||
if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries):
|
||||
retries[0] += 1
|
||||
self.logger.warning('Failed bootstrap phase; try=%s max_retries=%s', retries[0],
|
||||
max_retries)
|
||||
self.logger.warning(
|
||||
'Failed bootstrap phase; try=%s max_retries=%s', retries[0], max_retries
|
||||
)
|
||||
else:
|
||||
self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], 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.
|
||||
# NOTE: We don't know ahead if a webhook is configured, so we just delete.
|
||||
if clean or not webhook_url:
|
||||
self._network_loop_retry(bootstrap_del_webhook, bootstrap_onerr_cb,
|
||||
'bootstrap del webhook', bootstrap_interval)
|
||||
self._network_loop_retry(
|
||||
bootstrap_del_webhook,
|
||||
bootstrap_onerr_cb,
|
||||
'bootstrap del webhook',
|
||||
bootstrap_interval,
|
||||
)
|
||||
retries[0] = 0
|
||||
|
||||
# Clean pending messages, if requested.
|
||||
if clean:
|
||||
self._network_loop_retry(bootstrap_clean_updates, bootstrap_onerr_cb,
|
||||
'bootstrap clean updates', bootstrap_interval)
|
||||
self._network_loop_retry(
|
||||
bootstrap_clean_updates,
|
||||
bootstrap_onerr_cb,
|
||||
'bootstrap clean updates',
|
||||
bootstrap_interval,
|
||||
)
|
||||
retries[0] = 0
|
||||
sleep(1)
|
||||
|
||||
# Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set,
|
||||
# so we set it anyhow.
|
||||
if webhook_url:
|
||||
self._network_loop_retry(bootstrap_set_webhook, bootstrap_onerr_cb,
|
||||
'bootstrap set webhook', bootstrap_interval)
|
||||
self._network_loop_retry(
|
||||
bootstrap_set_webhook,
|
||||
bootstrap_onerr_cb,
|
||||
'bootstrap set webhook',
|
||||
bootstrap_interval,
|
||||
)
|
||||
|
||||
def stop(self) -> None:
|
||||
"""Stops the polling/webhook thread, the dispatcher and the job queue."""
|
||||
|
@ -573,9 +645,11 @@ class Updater:
|
|||
@no_type_check
|
||||
def _stop_httpd(self) -> None:
|
||||
if self.httpd:
|
||||
self.logger.debug('Waiting for current webhook connection to be '
|
||||
'closed... Send a Telegram message to the bot to exit '
|
||||
'immediately.')
|
||||
self.logger.debug(
|
||||
'Waiting for current webhook connection to be '
|
||||
'closed... Send a Telegram message to the bot to exit '
|
||||
'immediately.'
|
||||
)
|
||||
self.httpd.shutdown()
|
||||
self.httpd = None
|
||||
|
||||
|
@ -596,8 +670,9 @@ class Updater:
|
|||
def signal_handler(self, signum, frame) -> None:
|
||||
self.is_idle = False
|
||||
if self.running:
|
||||
self.logger.info('Received signal {} ({}), stopping...'.format(
|
||||
signum, get_signal_name(signum)))
|
||||
self.logger.info(
|
||||
'Received signal {} ({}), stopping...'.format(signum, get_signal_name(signum))
|
||||
)
|
||||
if self.persistence:
|
||||
# Update user_data, chat_data and bot_data before flushing
|
||||
self.dispatcher.update_persistence()
|
||||
|
@ -608,6 +683,7 @@ class Updater:
|
|||
else:
|
||||
self.logger.warning('Exiting immediately!')
|
||||
import os
|
||||
|
||||
os._exit(1)
|
||||
|
||||
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 typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -64,18 +65,20 @@ class Animation(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_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 typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -65,17 +66,19 @@ class Audio(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
performer: str = None,
|
||||
title: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
thumb: PhotoSize = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
performer: str = None,
|
||||
title: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
thumb: PhotoSize = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
from telegram import TelegramObject
|
||||
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -61,13 +62,15 @@ class ChatPhoto(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
small_file_id: str,
|
||||
small_file_unique_id: str,
|
||||
big_file_id: str,
|
||||
big_file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
small_file_id: str,
|
||||
small_file_unique_id: str,
|
||||
big_file_id: str,
|
||||
big_file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
self.small_file_id = small_file_id
|
||||
self.small_file_unique_id = small_file_unique_id
|
||||
self.big_file_id = big_file_id
|
||||
|
@ -75,7 +78,10 @@ class ChatPhoto(TelegramObject):
|
|||
|
||||
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':
|
||||
"""Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the
|
||||
|
|
|
@ -45,13 +45,15 @@ class Contact(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
user_id: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
user_id: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.phone_number = str(phone_number)
|
||||
self.first_name = first_name
|
||||
|
|
|
@ -22,6 +22,7 @@ from telegram import PhotoSize, TelegramObject
|
|||
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -57,17 +58,20 @@ class Document(TelegramObject):
|
|||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
||||
_id_keys = ('file_id',)
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
thumb: PhotoSize = None,
|
||||
file_name: str = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -27,6 +27,7 @@ from telegram import TelegramObject
|
|||
from telegram.passport.credentials import decrypt
|
||||
|
||||
from typing import Any, Optional, IO, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, FileCredentials
|
||||
|
||||
|
@ -68,13 +69,15 @@ class File(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
file_size: int = None,
|
||||
file_path: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
bot: 'Bot' = None,
|
||||
file_size: int = None,
|
||||
file_path: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -86,10 +89,9 @@ class File(TelegramObject):
|
|||
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
def download(self,
|
||||
custom_path: str = None,
|
||||
out: IO = None,
|
||||
timeout: int = None) -> Union[str, IO]:
|
||||
def download(
|
||||
self, custom_path: str = None, out: IO = None, timeout: int = None
|
||||
) -> Union[str, IO]:
|
||||
"""
|
||||
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
|
||||
|
@ -125,9 +127,9 @@ class File(TelegramObject):
|
|||
if out:
|
||||
buf = self.bot.request.retrieve(url)
|
||||
if self._credentials:
|
||||
buf = decrypt(b64decode(self._credentials.secret),
|
||||
b64decode(self._credentials.hash),
|
||||
buf)
|
||||
buf = decrypt(
|
||||
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
|
||||
)
|
||||
out.write(buf)
|
||||
return out
|
||||
else:
|
||||
|
@ -140,9 +142,9 @@ class File(TelegramObject):
|
|||
|
||||
buf = self.bot.request.retrieve(url, timeout=timeout)
|
||||
if self._credentials:
|
||||
buf = decrypt(b64decode(self._credentials.secret),
|
||||
b64decode(self._credentials.hash),
|
||||
buf)
|
||||
buf = decrypt(
|
||||
b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf
|
||||
)
|
||||
with open(filename, 'wb') as fobj:
|
||||
fobj.write(buf)
|
||||
return filename
|
||||
|
@ -150,8 +152,11 @@ class File(TelegramObject):
|
|||
def _get_encoded_url(self) -> str:
|
||||
"""Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string."""
|
||||
sres = urllib_parse.urlsplit(self.file_path)
|
||||
return urllib_parse.urlunsplit(urllib_parse.SplitResult(
|
||||
sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment))
|
||||
return urllib_parse.urlunsplit(
|
||||
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:
|
||||
"""Download this file and return it as a bytearray.
|
||||
|
|
|
@ -57,15 +57,14 @@ class InputFile:
|
|||
|
||||
if 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)
|
||||
|
||||
try:
|
||||
self.mimetype = self.is_image(self.input_file_content)
|
||||
except TelegramError:
|
||||
if self.filename:
|
||||
self.mimetype = mimetypes.guess_type(
|
||||
self.filename)[0] or DEFAULT_MIME_TYPE
|
||||
self.mimetype = mimetypes.guess_type(self.filename)[0] or DEFAULT_MIME_TYPE
|
||||
else:
|
||||
self.mimetype = DEFAULT_MIME_TYPE
|
||||
if not self.filename:
|
||||
|
|
|
@ -34,6 +34,7 @@ class InputMedia(TelegramObject):
|
|||
:class:`telegram.InputMediaVideo` for detailed use.
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -76,14 +77,16 @@ class InputMediaAnimation(InputMedia):
|
|||
arguments.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Animation],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None):
|
||||
def __init__(
|
||||
self,
|
||||
media: Union[str, FileLike, Animation],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None,
|
||||
):
|
||||
self.type = 'animation'
|
||||
|
||||
if isinstance(media, Animation):
|
||||
|
@ -136,10 +139,12 @@ class InputMediaPhoto(InputMedia):
|
|||
in :class:`telegram.ParseMode` for the available modes.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, PhotoSize],
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
||||
def __init__(
|
||||
self,
|
||||
media: Union[str, FileLike, PhotoSize],
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
):
|
||||
self.type = 'photo'
|
||||
|
||||
if isinstance(media, PhotoSize):
|
||||
|
@ -200,15 +205,17 @@ class InputMediaVideo(InputMedia):
|
|||
by Telegram.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Video],
|
||||
caption: str = None,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None,
|
||||
supports_streaming: bool = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb: FileLike = None):
|
||||
def __init__(
|
||||
self,
|
||||
media: Union[str, FileLike, Video],
|
||||
caption: str = None,
|
||||
width: int = None,
|
||||
height: int = None,
|
||||
duration: int = None,
|
||||
supports_streaming: bool = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb: FileLike = None,
|
||||
):
|
||||
self.type = 'video'
|
||||
|
||||
if isinstance(media, Video):
|
||||
|
@ -282,14 +289,16 @@ class InputMediaAudio(InputMedia):
|
|||
optional arguments.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Audio],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
duration: int = None,
|
||||
performer: str = None,
|
||||
title: str = None):
|
||||
def __init__(
|
||||
self,
|
||||
media: Union[str, FileLike, Audio],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
duration: int = None,
|
||||
performer: str = None,
|
||||
title: str = None,
|
||||
):
|
||||
self.type = '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.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
media: Union[str, FileLike, Document],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE):
|
||||
def __init__(
|
||||
self,
|
||||
media: Union[str, FileLike, Document],
|
||||
thumb: FileLike = None,
|
||||
caption: str = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
):
|
||||
self.type = 'document'
|
||||
|
||||
if isinstance(media, Document):
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -55,14 +56,16 @@ class PhotoSize(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, List, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -71,19 +72,21 @@ class Sticker(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
is_animated: bool,
|
||||
thumb: PhotoSize = None,
|
||||
emoji: str = None,
|
||||
file_size: int = None,
|
||||
set_name: str = None,
|
||||
mask_position: 'MaskPosition' = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
is_animated: bool,
|
||||
thumb: PhotoSize = None,
|
||||
emoji: str = None,
|
||||
file_size: int = None,
|
||||
set_name: str = None,
|
||||
mask_position: 'MaskPosition' = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
@ -158,15 +161,17 @@ class StickerSet(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
name: str,
|
||||
title: str,
|
||||
is_animated: bool,
|
||||
contains_masks: bool,
|
||||
stickers: List[Sticker],
|
||||
bot: 'Bot' = None,
|
||||
thumb: PhotoSize = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
title: str,
|
||||
is_animated: bool,
|
||||
contains_masks: bool,
|
||||
stickers: List[Sticker],
|
||||
bot: 'Bot' = None,
|
||||
thumb: PhotoSize = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
self.name = name
|
||||
self.title = title
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
FOREHEAD: str = 'forehead'
|
||||
""":obj:`str`: 'forehead'"""
|
||||
EYES: str = 'eyes'
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import TelegramObject, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -50,13 +51,15 @@ class Venue(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
location: Location,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
location: Location,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.location = location
|
||||
self.title = title
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -61,17 +62,19 @@ class Video(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
width: int,
|
||||
height: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import PhotoSize, TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -58,15 +59,17 @@ class VideoNote(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
length: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
length: int,
|
||||
duration: int,
|
||||
thumb: PhotoSize = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import TelegramObject
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File
|
||||
|
||||
|
@ -55,14 +56,16 @@ class Voice(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
duration: int,
|
||||
mime_type: str = None,
|
||||
file_size: int = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.file_id = str(file_id)
|
||||
self.file_unique_id = str(file_unique_id)
|
||||
|
|
|
@ -23,6 +23,7 @@ import sys
|
|||
from telegram import MessageEntity, TelegramObject, Animation, PhotoSize
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import List, Any, Dict, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -66,14 +67,16 @@ class Game(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
title: str,
|
||||
description: str,
|
||||
photo: List[PhotoSize],
|
||||
text: str = None,
|
||||
text_entities: List[MessageEntity] = None,
|
||||
animation: Animation = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
title: str,
|
||||
description: str,
|
||||
photo: List[PhotoSize],
|
||||
text: str = None,
|
||||
text_entities: List[MessageEntity] = None,
|
||||
animation: Animation = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.title = title
|
||||
self.description = description
|
||||
|
@ -130,11 +133,11 @@ class Game(TelegramObject):
|
|||
raise RuntimeError("This Game has no 'text'.")
|
||||
|
||||
# Is it a narrow build, if so we don't need to convert
|
||||
if sys.maxunicode == 0xffff:
|
||||
return self.text[entity.offset:entity.offset + entity.length]
|
||||
if sys.maxunicode == 0xFFFF:
|
||||
return self.text[entity.offset : entity.offset + entity.length]
|
||||
else:
|
||||
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')
|
||||
|
||||
|
@ -164,7 +167,8 @@ class Game(TelegramObject):
|
|||
|
||||
return {
|
||||
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:
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import TelegramObject, User
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import TelegramObject
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import CallbackGame, LoginUrl
|
||||
|
||||
|
@ -81,16 +82,18 @@ class InlineKeyboardButton(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
text: str,
|
||||
url: str = None,
|
||||
callback_data: str = None,
|
||||
switch_inline_query: str = None,
|
||||
switch_inline_query_current_chat: str = None,
|
||||
callback_game: 'CallbackGame' = None,
|
||||
pay: bool = None,
|
||||
login_url: 'LoginUrl' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
url: str = None,
|
||||
callback_data: str = None,
|
||||
switch_inline_query: str = None,
|
||||
switch_inline_query_current_chat: str = None,
|
||||
callback_game: 'CallbackGame' = None,
|
||||
pay: bool = None,
|
||||
login_url: 'LoginUrl' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.text = text
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import ReplyMarkup, InlineKeyboardButton
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, List, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -57,8 +58,7 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return data
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data: Optional[JSONDict],
|
||||
bot: 'Bot') -> Optional['InlineKeyboardMarkup']:
|
||||
def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineKeyboardMarkup']:
|
||||
data = cls.parse_data(data)
|
||||
|
||||
if not data:
|
||||
|
@ -91,8 +91,9 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return cls([[button]], **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, button_row: List[InlineKeyboardButton],
|
||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
||||
def from_row(
|
||||
cls, button_row: List[InlineKeyboardButton], **kwargs: Any
|
||||
) -> 'InlineKeyboardMarkup':
|
||||
"""Shortcut for::
|
||||
|
||||
InlineKeyboardMarkup([button_row], **kwargs)
|
||||
|
@ -108,8 +109,9 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
return cls([button_row], **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_column(cls, button_column: List[InlineKeyboardButton],
|
||||
**kwargs: Any) -> 'InlineKeyboardMarkup':
|
||||
def from_column(
|
||||
cls, button_column: List[InlineKeyboardButton], **kwargs: Any
|
||||
) -> 'InlineKeyboardMarkup':
|
||||
"""Shortcut for::
|
||||
|
||||
InlineKeyboardMarkup([[button] for button in button_column], **kwargs)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
from telegram import TelegramObject, User, Location
|
||||
from telegram.utils.types import JSONDict
|
||||
from typing import Any, Optional, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
@ -57,14 +58,16 @@ class InlineQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
offset: str,
|
||||
location: Location = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
from_user: User,
|
||||
query: str,
|
||||
offset: str,
|
||||
location: Location = None,
|
||||
bot: 'Bot' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
|
@ -125,8 +128,5 @@ class InlineQuery(TelegramObject):
|
|||
|
||||
"""
|
||||
return self.bot.answer_inline_query(
|
||||
self.id,
|
||||
*args,
|
||||
current_offset=self.offset if auto_pagination else None,
|
||||
**kwargs
|
||||
self.id, *args, current_offset=self.offset if auto_pagination else None, **kwargs
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -61,18 +62,20 @@ class InlineQueryResultArticle(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
title: str,
|
||||
input_message_content: 'InputMessageContent',
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
url: str = None,
|
||||
hide_url: bool = None,
|
||||
description: str = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
title: str,
|
||||
input_message_content: 'InputMessageContent',
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
url: str = None,
|
||||
hide_url: bool = None,
|
||||
description: str = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('article', id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -65,17 +66,19 @@ class InlineQueryResultAudio(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
audio_url: str,
|
||||
title: str,
|
||||
performer: str = None,
|
||||
audio_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
audio_url: str,
|
||||
title: str,
|
||||
performer: str = None,
|
||||
audio_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('audio', id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -59,14 +60,16 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
audio_file_id: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
audio_file_id: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('audio', id)
|
||||
self.audio_file_id = audio_file_id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -65,16 +66,18 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
title: str,
|
||||
document_file_id: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
title: str,
|
||||
document_file_id: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('document', id)
|
||||
self.title = title
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -64,15 +65,17 @@ class InlineQueryResultCachedGif(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
gif_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
gif_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('gif', id)
|
||||
self.gif_file_id = gif_file_id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -64,15 +65,17 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
mpeg4_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
mpeg4_file_id: str,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('mpeg4_gif', id)
|
||||
self.mpeg4_file_id = mpeg4_file_id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -66,16 +67,18 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
photo_file_id: str,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
photo_file_id: str,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('photo', id)
|
||||
self.photo_file_id = photo_file_id
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
@ -50,12 +51,14 @@ class InlineQueryResultCachedSticker(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
sticker_file_id: str,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
sticker_file_id: str,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('sticker', id)
|
||||
self.sticker_file_id = sticker_file_id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -66,16 +67,18 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
video_file_id: str,
|
||||
title: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
video_file_id: str,
|
||||
title: str,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('video', id)
|
||||
self.video_file_id = video_file_id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -61,15 +62,17 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
voice_file_id: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
voice_file_id: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('voice', id)
|
||||
self.voice_file_id = voice_file_id
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
@ -64,18 +65,20 @@ class InlineQueryResultContact(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('contact', id)
|
||||
self.phone_number = phone_number
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -76,20 +77,22 @@ class InlineQueryResultDocument(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
document_url: str,
|
||||
title: str,
|
||||
mime_type: str,
|
||||
caption: str = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
document_url: str,
|
||||
title: str,
|
||||
mime_type: str,
|
||||
caption: str = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('document', id)
|
||||
self.document_url = document_url
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup
|
||||
|
||||
|
@ -43,11 +44,9 @@ class InlineQueryResultGame(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
game_short_name: str,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self, id: str, game_short_name: str, reply_markup: 'ReplyMarkup' = None, **kwargs: Any
|
||||
):
|
||||
# Required
|
||||
super().__init__('game', id)
|
||||
self.id = id
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -76,20 +77,22 @@ class InlineQueryResultGif(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
gif_url: str,
|
||||
thumb_url: str,
|
||||
gif_width: int = None,
|
||||
gif_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
gif_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
gif_url: str,
|
||||
thumb_url: str,
|
||||
gif_width: int = None,
|
||||
gif_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
gif_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('gif', id)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
@ -64,18 +65,20 @@ class InlineQueryResultLocation(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
live_period: int = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
live_period: int = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('location', id)
|
||||
self.latitude = latitude
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -76,20 +77,22 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
mpeg4_url: str,
|
||||
thumb_url: str,
|
||||
mpeg4_width: int = None,
|
||||
mpeg4_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
mpeg4_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
mpeg4_url: str,
|
||||
thumb_url: str,
|
||||
mpeg4_width: int = None,
|
||||
mpeg4_height: int = None,
|
||||
title: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
mpeg4_duration: int = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
thumb_mime_type: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('mpeg4_gif', id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -73,26 +74,28 @@ class InlineQueryResultPhoto(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
photo_url: str,
|
||||
thumb_url: str,
|
||||
photo_width: int = None,
|
||||
photo_height: int = None,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
photo_url: str,
|
||||
thumb_url: str,
|
||||
photo_width: int = None,
|
||||
photo_height: int = None,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
super().__init__('photo', id)
|
||||
self.photo_url = photo_url
|
||||
self.thumb_url = thumb_url
|
||||
|
||||
# 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.title = title
|
||||
self.description = description
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from telegram import InlineQueryResult
|
||||
from typing import Any, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import ReplyMarkup, InputMessageContent
|
||||
|
||||
|
@ -70,20 +71,22 @@ class InlineQueryResultVenue(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
thumb_url: str = None,
|
||||
thumb_width: int = None,
|
||||
thumb_height: int = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('venue', id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -83,21 +84,23 @@ class InlineQueryResultVideo(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
video_url: str,
|
||||
mime_type: str,
|
||||
thumb_url: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
video_width: int = None,
|
||||
video_height: int = None,
|
||||
video_duration: int = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
video_url: str,
|
||||
mime_type: str,
|
||||
thumb_url: str,
|
||||
title: str,
|
||||
caption: str = None,
|
||||
video_width: int = None,
|
||||
video_height: int = None,
|
||||
video_duration: int = None,
|
||||
description: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('video', id)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
from telegram import InlineQueryResult
|
||||
from telegram.utils.helpers import DEFAULT_NONE, DefaultValue
|
||||
from typing import Any, Union, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import InputMessageContent, ReplyMarkup
|
||||
|
||||
|
@ -64,16 +65,18 @@ class InlineQueryResultVoice(InlineQueryResult):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id: str,
|
||||
voice_url: str,
|
||||
title: str,
|
||||
voice_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
id: str,
|
||||
voice_url: str,
|
||||
title: str,
|
||||
voice_duration: int = None,
|
||||
caption: str = None,
|
||||
reply_markup: 'ReplyMarkup' = None,
|
||||
input_message_content: 'InputMessageContent' = None,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
|
||||
# Required
|
||||
super().__init__('voice', id)
|
||||
|
|
|
@ -45,12 +45,14 @@ class InputContactMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
phone_number: str,
|
||||
first_name: str,
|
||||
last_name: str = None,
|
||||
vcard: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.phone_number = phone_number
|
||||
self.first_name = first_name
|
||||
|
|
|
@ -23,6 +23,7 @@ from typing import Any
|
|||
|
||||
|
||||
class InputLocationMessageContent(InputMessageContent):
|
||||
# fmt: off
|
||||
"""
|
||||
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.
|
||||
|
||||
"""
|
||||
# fmt: on
|
||||
|
||||
def __init__(self, latitude: float, longitude: float, live_period: int = None, **kwargs: Any):
|
||||
# Required
|
||||
|
|
|
@ -29,6 +29,7 @@ class InputMessageContent(TelegramObject):
|
|||
:class:`telegram.InputVenueMessageContent` for more details.
|
||||
|
||||
"""
|
||||
|
||||
@property
|
||||
def _has_parse_mode(self) -> bool:
|
||||
return hasattr(self, 'parse_mode')
|
||||
|
|
|
@ -51,11 +51,13 @@ class InputTextMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
message_text: str,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
message_text: str,
|
||||
parse_mode: Union[str, DefaultValue] = DEFAULT_NONE,
|
||||
disable_web_page_preview: Union[bool, DefaultValue] = DEFAULT_NONE,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.message_text = message_text
|
||||
# Optionals
|
||||
|
|
|
@ -52,14 +52,16 @@ class InputVenueMessageContent(InputMessageContent):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
latitude: float,
|
||||
longitude: float,
|
||||
title: str,
|
||||
address: str,
|
||||
foursquare_id: str = None,
|
||||
foursquare_type: str = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.latitude = latitude
|
||||
self.longitude = longitude
|
||||
|
|
|
@ -60,12 +60,14 @@ class KeyboardButton(TelegramObject):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
text: str,
|
||||
request_contact: bool = None,
|
||||
request_location: bool = None,
|
||||
request_poll: bool = None,
|
||||
**kwargs: Any):
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
request_contact: bool = None,
|
||||
request_location: bool = None,
|
||||
request_poll: bool = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
# Required
|
||||
self.text = text
|
||||
# Optionals
|
||||
|
@ -73,5 +75,9 @@ class KeyboardButton(TelegramObject):
|
|||
self.request_location = request_location
|
||||
self.request_poll = request_poll
|
||||
|
||||
self._id_attrs = (self.text, self.request_contact, self.request_location,
|
||||
self.request_poll)
|
||||
self._id_attrs = (
|
||||
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
|
||||
create a poll of any type.
|
||||
"""
|
||||
|
||||
def __init__(self, type: str = None, **kwargs: Any):
|
||||
self.type = type
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue