1
0
mirror of https://github.com/eternnoir/pyTelegramBotAPI.git synced 2023-08-10 21:12:57 +03:00

Compare commits

..

42 Commits
4.0.1 ... 4.1.1

Author SHA1 Message Date
4dce9340b0 Merge pull request #1326 from TrevorWinstral/master
Added my bots to README
2021-10-08 13:45:24 +03:00
bf79e8341e Moved bots to bottom of list 2021-10-08 10:39:59 +00:00
dadfdc2f13 Updated README with my bots 2021-10-06 14:15:30 +02:00
585f627e1f Updated README with my bots 2021-10-06 14:14:05 +02:00
eead303d47 Updated README with my bots 2021-10-06 14:13:05 +02:00
14cc15c711 Merge pull request #1325 from coder2020official/master
Critical fix
2021-10-01 21:47:50 +03:00
bf8736e17e Critical fix 2021-10-01 23:29:59 +05:00
5014ca2459 Merge pull request #1324 from coder2020official/master
Update of state handlers
2021-10-01 14:55:09 +03:00
f337abe06e Update __init__.py 2021-10-01 16:09:20 +05:00
ff35f25211 Update __init__.py 2021-10-01 16:08:01 +05:00
2e4280a947 Update of state handlers
No need to create state handlers
2021-10-01 15:56:54 +05:00
4a6b5b3d28 Merge pull request #1322 from Badiboy/master
Bugfix with one_time_keyboard = False
2021-09-30 11:57:54 +03:00
a28af3903d Bugfix with one_time_keyboard = False 2021-09-30 11:56:36 +03:00
d1d5b9effb Merge pull request #1320 from Badiboy/master
polling should leave our world. :)
2021-09-28 19:18:32 +03:00
062fababf2 polling should leave our world. :) 2021-09-28 19:17:09 +03:00
946afcc3c1 Merge pull request #1317 from coder2020official/master
Update handler_backends.py
2021-09-25 21:35:25 +03:00
6e502cd1c6 Merge branch 'master' into master 2021-09-25 23:29:50 +05:00
0a7f897f05 Merge pull request #1318 from Badiboy/master
States minor update
2021-09-25 21:15:52 +03:00
b35f17124f States minor update 2021-09-25 21:15:24 +03:00
44b44ac2c5 Optimization 2021-09-25 23:05:36 +05:00
39e875c1ea Update handler_backends.py 2021-09-25 22:49:32 +05:00
be7317cc86 Merge pull request #1315 from coder2020official/master
States, New filter, and more
2021-09-25 20:43:33 +03:00
e1c33a1de6 Merge pull request #1316 from Badiboy/master
Release 4.1.0
2021-09-25 20:34:05 +03:00
8149551a15 Release 4.1.0 2021-09-25 20:33:32 +03:00
ab648ef3db Merge branch 'master' of https://github.com/coder2020official/pyTelegramBotAPI 2021-09-25 22:19:09 +05:00
e721910c0c Update __init__.py 2021-09-25 22:19:07 +05:00
9287eced49 Update a typo 2021-09-25 21:10:29 +05:00
967b94b14f Update handler_backends.py 2021-09-25 20:27:03 +05:00
2df6f00ba5 Optimization
Optimized code, added filters support
2021-09-25 18:22:54 +05:00
beb4f8df44 Update register_handler.py 2021-09-25 17:15:33 +05:00
92ac5a4166 States, and some minor improvements 2021-09-25 17:12:32 +05:00
716323e56a Register_XXX_Handler 2021-09-22 22:46:19 +05:00
cd92d95f91 Create admin_filter_example.py 2021-09-22 22:37:57 +05:00
9c86ed623d Update custom_filters.py 2021-09-22 22:37:18 +05:00
c6ff9b07df Merge pull request #1311 from SwissCorePy/master
added property `user` to TeleBot class
2021-09-20 15:40:14 +03:00
38cc96d0f3 added property user to TeleBot class
Added property `user` to TeleBot class. The idea is to have easy access to the user object representing the bot without doing an API call every time.
2021-09-20 14:31:00 +02:00
82518d8664 Merge pull request #1309 from bim-ba/master
Added new example: anonymous chat-bot
2021-09-19 17:50:51 +03:00
aba2a9e179 Improve readabilty of "elif-zone" 2021-09-19 17:41:07 +03:00
c5c4d081ea Added new example: anonymous chat-bot 2021-09-18 19:46:53 +03:00
f854163626 Merge pull request #1308 from coder2020official/master
Added example and editd description.
2021-09-14 13:08:45 +03:00
fc31a2d466 Update custom_filters.py 2021-09-14 15:02:54 +05:00
86a0a8cd68 Little fixes and example
Fixed is_forwarded custom filter & created example
2021-09-14 15:00:27 +05:00
26 changed files with 447 additions and 39 deletions

View File

@ -121,13 +121,13 @@ This one echoes all incoming text messages back to the sender. It uses a lambda
We now have a basic bot which replies a static message to "/start" and "/help" commands and which echoes the rest of the sent messages. To start the bot, add the following to our source file:
```python
bot.polling()
bot.infinity_polling()
```
Alright, that's it! Our source file now looks like this:
```python
import telebot
bot = telebot.TeleBot("TOKEN")
bot = telebot.TeleBot("YOUR_BOT_TOKEN")
@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
@ -137,7 +137,7 @@ def send_welcome(message):
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling()
bot.infinity_polling()
```
To start the bot, simply open up a terminal and enter `python echo_bot.py` to run the bot! Test it by sending commands ('/start' and '/help') and arbitrary text messages.
@ -242,7 +242,7 @@ Handle edited channel post messages
Handle callback queries
```python
@bot.callback_query_handler(func=lambda call: True)
def test_callback(call): # <- passes a CallbackQuery type object to your function
def test_callback(call): # <- passes a CallbackQuery type object to your function
logger.info(call)
```
@ -381,12 +381,10 @@ TOKEN = '<token_string>'
tb = telebot.TeleBot(TOKEN) #create a new Telegram Bot object
# Upon calling this function, TeleBot starts polling the Telegram servers for new messages.
# - none_stop: True/False (default False) - Don't stop polling when receiving an error from the Telegram servers
# - interval: True/False (default False) - The interval between polling requests
# Note: Editing this parameter harms the bot's response time
# - interval: int (default 0) - The interval between polling requests
# - timeout: integer (default 20) - Timeout in seconds for long polling.
# - allowed_updates: List of Strings (default None) - List of update types to request
tb.polling(none_stop=False, interval=0, timeout=20)
tb.infinity_polling(interval=0, timeout=20)
# getMe
user = tb.get_me()
@ -398,6 +396,7 @@ tb.remove_webhook()
# getUpdates
updates = tb.get_updates()
# or
updates = tb.get_updates(1234,100,20) #get_Updates(offset, limit, timeout):
# sendMessage
@ -614,7 +613,7 @@ def handle_messages(messages):
bot.reply_to(message, 'Hi')
bot.set_update_listener(handle_messages)
bot.polling()
bot.infinity_polling()
```
### Using web hooks
@ -760,5 +759,9 @@ Get help. Discuss. Chat.
* [Anti-Tracking Bot](https://t.me/AntiTrackingBot) by Leon Heess [(source)](https://github.com/leonheess/AntiTrackingBot). Send any link, and the bot tries its best to remove all tracking from the link you sent.
* [Developer Bot](https://t.me/IndDeveloper_bot) by [Vishal Singh](https://github.com/vishal2376) [(source code)](https://github.com/vishal2376/telegram-bot) This telegram bot can do tasks like GitHub search & clone,provide c++ learning resources ,Stackoverflow search, Codeforces(profile visualizer,random problems)
* [oneIPO bot](https://github.com/aaditya2200/IPO-proj) by [Aadithya](https://github.com/aaditya2200) & [Amol Soans](https://github.com/AmolDerickSoans) This Telegram bot provides live updates , data and documents on current and upcoming IPOs(Initial Public Offerings)
* [CoronaGraphsBot](https://t.me/CovidGraph_bot) ([source](https://github.com/TrevorWinstral/CoronaGraphsBot)) by *TrevorWinstral* - Gets live COVID Country data, plots it, and briefs the user
* [ETHLectureBot](https://t.me/ETHLectureBot) ([source](https://github.com/TrevorWinstral/ETHLectureBot)) by *TrevorWinstral* - Notifies ETH students when their lectures have been uploaded
**Want to have your bot listed here? Just make a pull request. Only bots with public source code are accepted.**

117
examples/anonymous_bot.py Normal file
View File

@ -0,0 +1,117 @@
# This bot is needed to connect two people and their subsequent anonymous communication
#
# Avaiable commands:
# `/start` - Just send you a messsage how to start
# `/find` - Find a person you can contact
# `/stop` - Stop active conversation
import telebot
from telebot import types
# Initialize bot with your token
bot = telebot.TeleBot(TOKEN)
# The `users` variable is needed to contain chat ids that are either in the search or in the active dialog, like {chat_id, chat_id}
users = {}
# The `freeid` variable is needed to contain chat id, that want to start conversation
# Or, in other words: chat id of user in the search
freeid = None
# `/start` command handler
#
# That command only sends you 'Just use /find command!'
@bot.message_handler(commands=['start'])
def start(message: types.Message):
bot.send_message(message.chat.id, 'Just use /find command!')
# `/find` command handler
#
# That command finds opponent for you
#
# That command according to the following principle:
# 1. You have written `/find` command
# 2. If you are already in the search or have an active dialog, bot sends you 'Shut up!'
# 3. If not:
# 3.1. Bot sends you 'Finding...'
# 3.2. If there is no user in the search:
# 3.2.2. `freeid` updated with `your_chat_id`
# 3.3. If there is user in the search:
# 3.3.1. Both you and the user in the search recieve the message 'Founded!'
# 3.3.2. `users` updated with a {user_in_the_search_chat_id, your_chat_id}
# 3.3.3. `users` updated with a {your_chat_id, user_in_the_search_id}
# 3.3.4. `freeid` updated with `None`
@bot.message_handler(commands=['find'])
def find(message: types.Message):
global freeid
if message.chat.id not in users:
bot.send_message(message.chat.id, 'Finding...')
if freeid == None:
freeid = message.chat.id
else:
# Question:
# Is there any way to simplify this like `bot.send_message([message.chat.id, freeid], 'Founded!')`?
bot.send_message(message.chat.id, 'Founded!')
bot.send_message(freeid, 'Founded!')
users[freeid] = message.chat.id
users[message.chat.id] = freeid
freeid = None
print(users, freeid) # Debug purpose, you can remove that line
else:
bot.send_message(message.chat.id, 'Shut up!')
# `/stop` command handler
#
# That command stops your current conversation (if it exist)
#
# That command according to the following principle:
# 1. You have written `/stop` command
# 2. If you are not have active dialog or you are not in search, bot sends you 'You are not in search!'
# 3. If you are in active dialog:
# 3.1. Bot sends you 'Stopping...'
# 3.2. Bot sends 'Your opponent is leavin`...' to your opponent
# 3.3. {your_opponent_chat_id, your_chat_id} removes from `users`
# 3.4. {your_chat_id, your_opponent_chat_id} removes from `users`
# 4. If you are only in search:
# 4.1. Bot sends you 'Stopping...'
# 4.2. `freeid` updated with `None`
@bot.message_handler(commands=['stop'])
def stop(message: types.Message):
global freeid
if message.chat.id in users:
bot.send_message(message.chat.id, 'Stopping...')
bot.send_message(users[message.chat.id], 'Your opponent is leavin`...')
del users[users[message.chat.id]]
del users[message.chat.id]
print(users, freeid) # Debug purpose, you can remove that line
elif message.chat.id == freeid:
bot.send_message(message.chat.id, 'Stopping...')
freeid = None
print(users, freeid) # Debug purpose, you can remove that line
else:
bot.send_message(message.chat.id, 'You are not in search!')
# message handler for conversation
#
# That handler needed to send message from one opponent to another
# If you are not in `users`, you will recieve a message 'No one can hear you...'
# Otherwise all your messages are sent to your opponent
#
# Questions:
# 1. Is there any way to improve readability like `content_types=['all']`?
# 2. Is there any way to register this message handler only when i found the opponent?
@bot.message_handler(content_types=['animation', 'audio', 'contact', 'dice', 'document', 'location', 'photo', 'poll', 'sticker', 'text', 'venue', 'video', 'video_note', 'voice'])
def chatting(message: types.Message):
if message.chat.id in users:
bot.copy_message(users[message.chat.id], users[users[message.chat.id]], message.id)
else:
bot.send_message(message.chat.id, 'No one can hear you...')
bot.infinity_polling(skip_pending=True)

View File

@ -30,4 +30,4 @@ def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
def delall(message: types.Message):
bot.delete_message(message.chat.id,message.message_id)
bot.polling(allowed_updates=util.update_types)
bot.infinity_polling(allowed_updates=util.update_types)

View File

@ -0,0 +1,12 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('TOKEN')
# Handler
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
def answer_for_admin(message):
bot.send_message(message.chat.id,"hello my admin")
# Register filter
bot.add_custom_filter(custom_filters.IsAdminFilter(bot))
bot.infinity_polling()

View File

@ -39,4 +39,4 @@ def bye_user(message):
bot.add_custom_filter(MainFilter())
bot.add_custom_filter(IsAdmin())
bot.polling(skip_pending=True,non_stop=True) # Skip old updates
bot.infinity_polling(skip_pending=True) # Skip old updates

View File

@ -13,10 +13,7 @@ def admin_rep(message):
def not_admin(message):
bot.send_message(message.chat.id, "You are not allowed to use this command")
# Do not forget to register
bot.add_custom_filter(custom_filters.ChatFilter())
bot.polling(non_stop=True)
bot.infinity_polling()

View File

@ -0,0 +1,21 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot('TOKEN')
# Check if message is a reply
@bot.message_handler(is_reply=True)
def start_filter(message):
bot.send_message(message.chat.id, "Looks like you replied to my message.")
# Check if message was forwarded
@bot.message_handler(is_forwarded=True)
def text_filter(message):
bot.send_message(message.chat.id, "I do not accept forwarded messages!")
# Do not forget to register filters
bot.add_custom_filter(custom_filters.IsReplyFilter())
bot.add_custom_filter(custom_filters.ForwardFilter())
bot.infinity_polling()

View File

@ -18,4 +18,4 @@ def text_filter(message):
bot.add_custom_filter(custom_filters.TextMatchFilter())
bot.add_custom_filter(custom_filters.TextStartsFilter())
bot.polling(non_stop=True)
bot.infinity_polling()

64
examples/custom_states.py Normal file
View File

@ -0,0 +1,64 @@
import telebot
from telebot import custom_filters
bot = telebot.TeleBot("")
@bot.message_handler(commands=['start'])
def start_ex(message):
"""
Start command. Here we are starting state
"""
bot.set_state(message.chat.id, 1)
bot.send_message(message.chat.id, 'Hi, write me a name')
@bot.message_handler(state="*", commands='cancel')
def any_state(message):
"""
Cancel state
"""
bot.send_message(message.chat.id, "Your state was cancelled.")
bot.delete_state(message.chat.id)
@bot.message_handler(state=1)
def name_get(message):
"""
State 1. Will process when user's state is 1.
"""
bot.send_message(message.chat.id, f'Now write me a surname')
bot.set_state(message.chat.id, 2)
with bot.retrieve_data(message.chat.id) as data:
data['name'] = message.text
@bot.message_handler(state=2)
def ask_age(message):
"""
State 2. Will process when user's state is 2.
"""
bot.send_message(message.chat.id, "What is your age?")
bot.set_state(message.chat.id, 3)
with bot.retrieve_data(message.chat.id) as data:
data['surname'] = message.text
# result
@bot.message_handler(state=3, is_digit=True)
def ready_for_answer(message):
with bot.retrieve_data(message.chat.id) as data:
bot.send_message(message.chat.id, "Ready, take a look:\n<b>Name: {name}\nSurname: {surname}\nAge: {age}</b>".format(name=data['name'], surname=data['surname'], age=message.text), parse_mode="html")
bot.delete_state(message.chat.id)
#incorrect number
@bot.message_handler(state=3, is_digit=False)
def age_incorrect(message):
bot.send_message(message.chat.id, 'Looks like you are submitting a string in the field age. Please enter a number')
# register filters
bot.add_custom_filter(custom_filters.StateFilter(bot))
bot.add_custom_filter(custom_filters.IsDigitFilter())
bot.infinity_polling(skip_pending=True)

View File

@ -74,4 +74,4 @@ def send_welcome(message):
bot.reply_to(message, reply)
bot.polling()
bot.infinity_polling()

View File

@ -130,4 +130,4 @@ def command_default(m):
bot.send_message(m.chat.id, "I don't understand \"" + m.text + "\"\nMaybe try the help page at /help")
bot.polling()
bot.infinity_polling()

View File

@ -25,4 +25,4 @@ def echo_message(message):
bot.reply_to(message, message.text)
bot.polling()
bot.infinity_polling()

View File

@ -61,7 +61,7 @@ def default_query(inline_query):
def main_loop():
bot.polling(True)
bot.infinity_polling()
while 1:
time.sleep(3)

View File

@ -24,4 +24,4 @@ def callback_query(call):
def message_handler(message):
bot.send_message(message.chat.id, "Yes/no?", reply_markup=gen_markup())
bot.polling(none_stop=True)
bot.infinity_polling()

View File

@ -50,4 +50,4 @@ def start(message):
bot.send_message(message.chat.id, _('hello'))
bot.polling()
bot.infinity_polling()

View File

@ -58,4 +58,4 @@ def start(message):
bot.send_message(message.chat.id, bot.session['state'])
bot.polling()
bot.infinity_polling()

View File

@ -78,5 +78,4 @@ def got_payment(message):
parse_mode='Markdown')
bot.skip_pending = True
bot.polling(none_stop=True, interval=0)
bot.infinity_polling(skip_pending = True)

View File

@ -0,0 +1,21 @@
import telebot
api_token = 'token'
bot = telebot.TeleBot(api_token)
def start_executor(message):
bot.send_message(message.chat.id, 'Hello!')
bot.register_message_handler(start_executor, commands=['start']) # Start command executor
# See also
# bot.register_callback_query_handler(*args, **kwargs)
# bot.register_channel_post_handler(*args, **kwargs)
# bot.register_chat_member_handler(*args, **kwargs)
# bot.register_inline_handler(*args, **kwargs)
# bot.register_my_chat_member_handler(*args, **kwargs)
# bot.register_edited_message_handler(*args, **kwargs)
# And other functions..
bot.infinity_polling()

View File

@ -10,4 +10,4 @@ def send_welcome(message):
def echo_all(message):
bot.reply_to(message, message.text)
bot.polling(skip_pending=True)# Skip pending skips old updates
bot.infinity_polling(skip_pending=True)# Skip pending skips old updates

View File

@ -83,4 +83,4 @@ bot.enable_save_next_step_handlers(delay=2)
# WARNING It will work only if enable_save_next_step_handlers was called!
bot.load_next_step_handlers()
bot.polling()
bot.infinity_polling()

View File

@ -81,4 +81,4 @@ def listener(messages):
bot.set_update_listener(listener)
bot.polling()
bot.infinity_polling()

View File

@ -27,7 +27,7 @@ logger.addHandler(console_output_handler)
logger.setLevel(logging.ERROR)
from telebot import apihelper, util, types
from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend
from telebot.handler_backends import MemoryHandlerBackend, FileHandlerBackend, State
REPLY_MARKUP_TYPES = Union[
@ -186,6 +186,9 @@ class TeleBot:
self.my_chat_member_handlers = []
self.chat_member_handlers = []
self.custom_filters = {}
self.state_handlers = []
self.current_states = State()
if apihelper.ENABLE_MIDDLEWARE:
self.typed_middleware_handlers = {
@ -208,6 +211,16 @@ class TeleBot:
self.threaded = threaded
if self.threaded:
self.worker_pool = util.ThreadPool(num_threads=num_threads)
@property
def user(self) -> types.User:
"""
The User object representing this bot.
Equivalent to bot.get_me() but the result is cached so only one API call is needed
"""
if not hasattr(self, "_user"):
self._user = types.User.de_json(self.get_me())
return self._user
def enable_save_next_step_handlers(self, delay=120, filename="./.handler-saves/step.save"):
"""
@ -549,8 +562,9 @@ class TeleBot:
for listener in self.update_listener:
self._exec_task(listener, new_messages)
def infinity_polling(self, timeout=20, skip_pending=False, long_polling_timeout=20, logger_level=logging.ERROR,
allowed_updates=None, *args, **kwargs):
def infinity_polling(self, timeout: int=20, skip_pending: bool=False, long_polling_timeout: int=20, logger_level=logging.ERROR,
allowed_updates: Optional[List[str]]=None, *args, **kwargs):
"""
Wrap polling with infinite loop and exception handling to avoid bot stops polling.
@ -659,7 +673,10 @@ class TeleBot:
# self.worker_pool.clear_exceptions()
logger.info("Waiting for {0} seconds until retry".format(error_interval))
time.sleep(error_interval)
error_interval *= 2
if error_interval * 2 < 60:
error_interval *= 2
else:
error_interval = 60
else:
# polling_thread.clear_exceptions()
# self.worker_pool.clear_exceptions()
@ -2352,6 +2369,41 @@ class TeleBot:
chat_id = message.chat.id
self.register_next_step_handler_by_chat_id(chat_id, callback, *args, **kwargs)
def set_state(self, chat_id, state):
"""
Sets a new state of a user.
:param chat_id:
:param state: new state. can be string or integer.
"""
self.current_states.add_state(chat_id, state)
def delete_state(self, chat_id):
"""
Delete the current state of a user.
:param chat_id:
:return:
"""
self.current_states.delete_state(chat_id)
def retrieve_data(self, chat_id):
return self.current_states.retrieve_data(chat_id)
def get_state(self, chat_id):
"""
Get current state of a user.
:param chat_id:
:return: state of a user
"""
return self.current_states.current_state(chat_id)
def add_data(self, chat_id, **kwargs):
"""
Add data to states.
:param chat_id:
"""
for key, value in kwargs.items():
self.current_states._add_data(chat_id, key, value)
def register_next_step_handler_by_chat_id(
self, chat_id: Union[int, str], callback: Callable, *args, **kwargs) -> None:
"""
@ -2416,6 +2468,7 @@ class TeleBot:
if need_pop:
new_messages.pop(i) # removing message that was detected with next_step_handler
@staticmethod
def _build_handler_dict(handler, **filters):
"""
@ -2651,6 +2704,7 @@ class TeleBot:
**kwargs)
self.add_edited_message_handler(handler_dict)
def channel_post_handler(self, commands=None, regexp=None, func=None, content_types=None, **kwargs):
"""
Channel post handler decorator

View File

@ -87,7 +87,7 @@ class ChatFilter(AdvancedCustomFilter):
class ForwardFilter(SimpleCustomFilter):
"""
Check whether message was forwarded.
Check whether message was forwarded from channel or group.
Example:
@ -130,3 +130,47 @@ class LanguageFilter(AdvancedCustomFilter):
if type(text) is list:return message.from_user.language_code in text
else: return message.from_user.language_code == text
class IsAdminFilter(SimpleCustomFilter):
"""
Check whether the user is administrator / owner of the chat.
Example:
@bot.message_handler(chat_types=['supergroup'], is_chat_admin=True)
"""
key = 'is_chat_admin'
def __init__(self, bot):
self._bot = bot
def check(self, message):
return self._bot.get_chat_member(message.chat.id, message.from_user.id).status in ['creator', 'administrator']
class StateFilter(AdvancedCustomFilter):
"""
Filter to check state.
Example:
@bot.message_handler(state=1)
"""
def __init__(self, bot):
self.bot = bot
key = 'state'
def check(self, message, text):
if self.bot.current_states.current_state(message.from_user.id) is False:return False
elif text == '*':return True
elif type(text) is list:return self.bot.current_states.current_state(message.from_user.id) in text
return self.bot.current_states.current_state(message.from_user.id) == text
class IsDigitFilter(SimpleCustomFilter):
"""
Filter to check whether the string is made up of only digits.
Example:
@bot.message_handler(is_digit=True)
"""
key = 'is_digit'
def check(self, message):
return message.text.isdigit()

View File

@ -141,3 +141,79 @@ class RedisHandlerBackend(HandlerBackend):
handlers = pickle.loads(value)
self.clear_handlers(handler_group_id)
return handlers
class State:
def __init__(self):
self._states = {}
def add_state(self, chat_id, state):
"""
Add a state.
:param chat_id:
:param state: new state
"""
if chat_id in self._states:
self._states[chat_id]['state'] = state
else:
self._states[chat_id] = {'state': state,'data': {}}
def current_state(self, chat_id):
"""Current state"""
if chat_id in self._states: return self._states[chat_id]['state']
else: return False
def delete_state(self, chat_id):
"""Delete a state"""
return self._states.pop(chat_id)
def _get_data(self, chat_id):
return self._states[chat_id]['data']
def set(self, chat_id, new_state):
"""
Set a new state for a user.
:param chat_id:
:param new_state: new_state of a user
"""
self.add_state(chat_id,new_state)
def _add_data(self, chat_id, key, value):
result = self._states[chat_id]['data'][key] = value
return result
def finish(self, chat_id):
"""
Finish(delete) state of a user.
:param chat_id:
"""
self.delete_state(chat_id)
def retrieve_data(self, chat_id):
"""
Save input text.
Usage:
with state.retrieve_data(message.chat.id) as data:
data['name'] = message.text
Also, at the end of your 'Form' you can get the name:
data['name']
"""
return StateContext(self, chat_id)
class StateContext:
"""
Class for data.
"""
def __init__(self , obj: State, chat_id) -> None:
self.obj = obj
self.chat_id = chat_id
self.data = obj._get_data(chat_id)
def __enter__(self):
return self.data
def __exit__(self, exc_type, exc_val, exc_tb):
return

View File

@ -873,7 +873,7 @@ class ForceReply(JsonSerializable):
def to_json(self):
json_dict = {'force_reply': True}
if self.selective is not None:
json_dict['selective'] = True
json_dict['selective'] = self.selective
if self.input_field_placeholder:
json_dict['input_field_placeholder'] = self.input_field_placeholder
return json.dumps(json_dict)
@ -886,7 +886,7 @@ class ReplyKeyboardRemove(JsonSerializable):
def to_json(self):
json_dict = {'remove_keyboard': True}
if self.selective:
json_dict['selective'] = True
json_dict['selective'] = self.selective
return json.dumps(json_dict)
@ -960,11 +960,11 @@ class ReplyKeyboardMarkup(JsonSerializable):
"""
json_dict = {'keyboard': self.keyboard}
if self.one_time_keyboard is not None:
json_dict['one_time_keyboard'] = True
json_dict['one_time_keyboard'] = self.one_time_keyboard
if self.resize_keyboard is not None:
json_dict['resize_keyboard'] = True
json_dict['resize_keyboard'] = self.resize_keyboard
if self.selective is not None:
json_dict['selective'] = True
json_dict['selective'] = self.selective
if self.input_field_placeholder:
json_dict['input_field_placeholder'] = self.input_field_placeholder
return json.dumps(json_dict)

View File

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