Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StatesV2: Support for topics, multibots, and business messages #2321

Merged
merged 26 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fce1c3d
Added statesv2
coder2020official Jun 23, 2024
7e5a044
Sync states v2 early version
coder2020official Jul 8, 2024
4a7bc5d
all update types are supported for states(theoretically)
coder2020official Jul 8, 2024
90a8f32
Merge branch 'master' into statesv2
coder2020official Jul 8, 2024
5e4598d
Merge branch 'eternnoir:master' into statesv2
coder2020official Jul 12, 2024
676597c
added redis support(not fully tested)
coder2020official Jul 12, 2024
5bd4271
Added redis dependency check
coder2020official Jul 12, 2024
a79fd77
fix test
coder2020official Jul 12, 2024
c29bf0e
Added pickle and renamed method
coder2020official Jul 12, 2024
15bced9
Fixed bugs, renamed StateContext for retrieve_data to StateDataContex…
coder2020official Jul 17, 2024
ff6485d
Async version fully supported, partially tested.
coder2020official Jul 19, 2024
af79db6
rewrote pickle sync with lock decorators, few changes to storages to …
coder2020official Jul 21, 2024
1adca13
Improved docstrings, fixed bugs, allow accessing statecontext via sta…
coder2020official Jul 21, 2024
adae7a9
Removed aioredis from optional dependencies, breaking change made for…
coder2020official Jul 21, 2024
d33db85
Updated examples
coder2020official Jul 21, 2024
536ffa2
Added migrate_format to migrate from old format of states to new. Onl…
coder2020official Jul 25, 2024
d2485bf
Another approach to bot id
coder2020official Jul 26, 2024
dd0dfa9
fix tests
coder2020official Jul 26, 2024
7f99176
fixed redis data bug on set_state
coder2020official Jul 26, 2024
3fec98c
Code cleanup
coder2020official Jul 27, 2024
dbfa514
code cleanuop & renamed aio -> asyncio
coder2020official Jul 27, 2024
2dbf190
Remove apihelper following the validate_token not using getMe
coder2020official Jul 28, 2024
b10e8d7
Reverted changes regarding self._user, fixed validate_token=False cau…
coder2020official Jul 28, 2024
6108e35
fix docstring
coder2020official Jul 28, 2024
30ebe75
make extract_bot_id return None in case validation fails
coder2020official Jul 30, 2024
d44ebce
Fix versions
coder2020official Aug 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 102 additions & 14 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import threading
import time
import traceback
from typing import Any, Callable, List, Optional, Union
from typing import Any, Callable, List, Optional, Union, Dict

# these imports are used to avoid circular import error
import telebot.util
Expand Down Expand Up @@ -168,7 +168,8 @@ def __init__(
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
allow_sending_without_reply: Optional[bool]=None,
colorful_logs: Optional[bool]=False
colorful_logs: Optional[bool]=False,
token_check: Optional[bool]=True
):

# update-related
Expand All @@ -186,6 +187,11 @@ def __init__(
self.webhook_listener = None
self._user = None

# token check
if token_check:
self._user = self.get_me()
self.bot_id = self._user.id

# logs-related
if colorful_logs:
try:
Expand Down Expand Up @@ -280,6 +286,8 @@ def __init__(
self.threaded = threaded
if self.threaded:
self.worker_pool = util.ThreadPool(self, num_threads=num_threads)



@property
def user(self) -> types.User:
Expand Down Expand Up @@ -1172,6 +1180,9 @@ def polling(self, non_stop: Optional[bool]=False, skip_pending: Optional[bool]=F
if restart_on_change:
self._setup_change_detector(path_to_watch)

if not self._user:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed that get_me should be optional.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, my bad, for sync there's no need for this as self.user is a property that already does this

self._user = self.get_me()

logger.info('Starting your bot with username: [@%s]', self.user.username)

if self.threaded:
Expand Down Expand Up @@ -6634,7 +6645,9 @@ def setup_middleware(self, middleware: BaseMiddleware):
self.middlewares.append(middleware)


def set_state(self, user_id: int, state: Union[int, str, State], chat_id: Optional[int]=None) -> None:
def set_state(self, user_id: int, state: Union[int, str, State], chat_id: Optional[int]=None,
business_connection_id: Optional[str]=None, message_thread_id: Optional[int]=None,
bot_id: Optional[int]=None) -> None:
"""
Sets a new state of a user.

Expand All @@ -6653,14 +6666,29 @@ def set_state(self, user_id: int, state: Union[int, str, State], chat_id: Option
:param chat_id: Chat's identifier
:type chat_id: :obj:`int`

:param bot_id: Bot's identifier
:type bot_id: :obj:`int`

:param business_connection_id: Business identifier
:type business_connection_id: :obj:`str`

:param message_thread_id: Identifier of the message thread
:type message_thread_id: :obj:`int`

:return: None
"""
if chat_id is None:
chat_id = user_id
self.current_states.set_state(chat_id, user_id, state)
if bot_id is None:
bot_id = self.bot_id
return self.current_states.set_state(
chat_id=chat_id, user_id=user_id, state=state, bot_id=bot_id,
business_connection_id=business_connection_id, message_thread_id=message_thread_id)


def reset_data(self, user_id: int, chat_id: Optional[int]=None):
def reset_data(self, user_id: int, chat_id: Optional[int]=None,
business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None, bot_id: Optional[int]=None) -> None:
"""
Reset data for a user in chat.

Expand All @@ -6670,14 +6698,27 @@ def reset_data(self, user_id: int, chat_id: Optional[int]=None):
:param chat_id: Chat's identifier
:type chat_id: :obj:`int`

:param bot_id: Bot's identifier
:type bot_id: :obj:`int`

:param business_connection_id: Business identifier
:type business_connection_id: :obj:`str`

:param message_thread_id: Identifier of the message thread
:type message_thread_id: :obj:`int`

:return: None
"""
if chat_id is None:
chat_id = user_id
self.current_states.reset_data(chat_id, user_id)
if bot_id is None:
bot_id = self.bot_id
return self.current_states.reset_data(chat_id=chat_id, user_id=user_id, bot_id=bot_id,
business_connection_id=business_connection_id, message_thread_id=message_thread_id)


def delete_state(self, user_id: int, chat_id: Optional[int]=None) -> None:
def delete_state(self, user_id: int, chat_id: Optional[int]=None, business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None, bot_id: Optional[int]=None) -> None:
"""
Delete the current state of a user.

Expand All @@ -6691,10 +6732,14 @@ def delete_state(self, user_id: int, chat_id: Optional[int]=None) -> None:
"""
if chat_id is None:
chat_id = user_id
self.current_states.delete_state(chat_id, user_id)
if bot_id is None:
bot_id = self.bot_id
return self.current_states.delete_state(chat_id=chat_id, user_id=user_id, bot_id=bot_id,
business_connection_id=business_connection_id, message_thread_id=message_thread_id)


def retrieve_data(self, user_id: int, chat_id: Optional[int]=None) -> Optional[Any]:
def retrieve_data(self, user_id: int, chat_id: Optional[int]=None, business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None, bot_id: Optional[int]=None) -> Optional[Dict[str, Any]]:
"""
Returns context manager with data for a user in chat.

Expand All @@ -6704,15 +6749,30 @@ def retrieve_data(self, user_id: int, chat_id: Optional[int]=None) -> Optional[A
:param chat_id: Chat's unique identifier, defaults to user_id
:type chat_id: int, optional

:param bot_id: Bot's identifier
:type bot_id: int, optional

:param business_connection_id: Business identifier
:type business_connection_id: str, optional

:param message_thread_id: Identifier of the message thread
:type message_thread_id: int, optional

:return: Context manager with data for a user in chat
:rtype: Optional[Any]
"""
if chat_id is None:
chat_id = user_id
return self.current_states.get_interactive_data(chat_id, user_id)
if bot_id is None:
bot_id = self.bot_id
return self.current_states.get_interactive_data(chat_id=chat_id, user_id=user_id, bot_id=bot_id,
business_connection_id=business_connection_id,
message_thread_id=message_thread_id)


def get_state(self, user_id: int, chat_id: Optional[int]=None) -> Optional[Union[int, str, State]]:
def get_state(self, user_id: int, chat_id: Optional[int]=None,
business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None, bot_id: Optional[int]=None) -> Union[int, str]:
"""
Gets current state of a user.
Not recommended to use this method. But it is ok for debugging.
Expand All @@ -6723,15 +6783,31 @@ def get_state(self, user_id: int, chat_id: Optional[int]=None) -> Optional[Union
:param chat_id: Chat's identifier
:type chat_id: :obj:`int`

:param bot_id: Bot's identifier
:type bot_id: :obj:`int`

:param business_connection_id: Business identifier
:type business_connection_id: :obj:`str`

:param message_thread_id: Identifier of the message thread
:type message_thread_id: :obj:`int`

:return: state of a user
:rtype: :obj:`int` or :obj:`str` or :class:`telebot.types.State`
"""
if chat_id is None:
chat_id = user_id
return self.current_states.get_state(chat_id, user_id)
if bot_id is None:
bot_id = self.bot_id
return self.current_states.get_state(chat_id=chat_id, user_id=user_id, bot_id=bot_id,
business_connection_id=business_connection_id, message_thread_id=message_thread_id)


def add_data(self, user_id: int, chat_id: Optional[int]=None, **kwargs):
def add_data(self, user_id: int, chat_id: Optional[int]=None,
business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None,
bot_id: Optional[int]=None,
**kwargs) -> None:
"""
Add data to states.

Expand All @@ -6741,13 +6817,25 @@ def add_data(self, user_id: int, chat_id: Optional[int]=None, **kwargs):
:param chat_id: Chat's identifier
:type chat_id: :obj:`int`

:param bot_id: Bot's identifier
:type bot_id: :obj:`int`

:param business_connection_id: Business identifier
:type business_connection_id: :obj:`str`

:param message_thread_id: Identifier of the message thread
:type message_thread_id: :obj:`int`

:param kwargs: Data to add
:return: None
"""
if chat_id is None:
chat_id = user_id
if bot_id is None:
bot_id = self.bot_id
for key, value in kwargs.items():
self.current_states.set_data(chat_id, user_id, key, value)
self.current_states.set_data(chat_id=chat_id, user_id=user_id, key=key, value=value, bot_id=bot_id,
business_connection_id=business_connection_id, message_thread_id=message_thread_id)


def register_next_step_handler_by_chat_id(
Expand Down
Loading
Loading