Switch Code Formatting to Black (#2122)

* Swtich code formatting to Black

* Update docs

* Fix tests

* TRy fixing pre-commit
This commit is contained in:
Bibo-Joshi 2020-10-09 17:22:07 +02:00 committed by GitHub
parent 8efb05290a
commit 264b2c9c72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
237 changed files with 9442 additions and 5895 deletions

View file

@ -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.
- Dont 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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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))

View file

@ -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__)

View file

@ -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():

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)],
)

View file

@ -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()

View 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):

View file

@ -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)

View file

@ -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():

View file

@ -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
View 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

View file

@ -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

View file

@ -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',
]

View file

@ -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', ' ')))

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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
)

View file

@ -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':

View file

@ -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

View file

@ -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,
)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.
"""

View file

@ -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',
)

View file

@ -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.

View file

@ -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

View file

@ -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]

View file

@ -23,6 +23,7 @@ from .handler import Handler
from telegram.utils.types import HandlerArg
from typing import Optional, Union, TypeVar
RT = TypeVar('RT')

View file

@ -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):

View file

@ -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)

View file

@ -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):

View file

@ -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:

View file

@ -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
)

View file

@ -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'

View file

@ -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

View file

@ -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]

View file

@ -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:
"""

View file

@ -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)

View file

@ -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)

View file

@ -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()

View file

@ -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:

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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:

View file

@ -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):

View file

@ -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)

View file

@ -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'

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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,
)

View file

@ -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