Skip to content
This repository was archived by the owner on Jul 4, 2024. It is now read-only.

Commit 55b9780

Browse files
author
Joscha Götzer
committed
Moved some unnecessary services to private project
1 parent f575921 commit 55b9780

File tree

14 files changed

+152
-96
lines changed

14 files changed

+152
-96
lines changed

botkit/botkit_modules/module_manager/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async def enable_module(self, module_info: ModuleInfosCollectionModel):
5555
module_to_enable = module_info.page_items[0]
5656
module_name = module_to_enable.name
5757
module = self.module_loader.get_module_by_name(module_name)
58-
await self.module_loader.register_module(module)
58+
await self.module_loader.try_register_module(module)
5959
module_to_enable.is_enabled = True
6060
return module_info
6161

botkit/botkit_modules/system/status_pings.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ class Ping(BaseModel):
2222

2323
class StatusPings:
2424
def __init__(
25-
self, client: Client, log_chat: Union[int, str], environment: str, environment_priority: List[str],
25+
self,
26+
client: Client,
27+
log_chat: Union[int, str],
28+
environment: str,
29+
environment_priority: List[str],
2630
):
2731
self.log_chat = log_chat
2832
self.environment = environment
@@ -99,7 +103,9 @@ async def update_status(self, queried_ping: Optional[Ping], other_detected: bool
99103
return
100104

101105
# Waiting for all other instances to be offline for some time
102-
if self.timestamp_older_than(queried_ping.ping_time, seconds=self.reactivate_after_seconds):
106+
if self.timestamp_older_than(
107+
queried_ping.ping_time, seconds=self.reactivate_after_seconds
108+
):
103109
command = ToggleSystemStateCommand(
104110
new_state="unpause",
105111
triggered_by=self.__class__.__name__,
@@ -117,13 +123,17 @@ async def update_status(self, queried_ping: Optional[Ping], other_detected: bool
117123
f"{self.environment} ready to take over."
118124
)
119125
else:
120-
self.log.debug(f"Paused since another instance with higher priority ({queried_ping.env}) is running.")
126+
self.log.debug(
127+
f"Paused since another instance with higher priority ({queried_ping.env}) is running."
128+
)
121129

122130
def has_higher_priority(self, env: str, compare_to: str) -> Optional[bool]:
123131
try:
124132
return self.priority.index(env) < self.priority.index(compare_to)
125133
except ValueError:
126-
self.log.exception(f"Environment priority map does not contain '{env}' and '{compare_to}'.")
134+
self.log.exception(
135+
f"Environment priority map does not contain '{env}' and '{compare_to}'."
136+
)
127137
return None
128138

129139
async def query_most_recent_ping(self) -> Optional[Ping]:
@@ -164,7 +174,11 @@ def timestamp_older_than(dt: datetime, seconds: int) -> bool:
164174

165175
@staticmethod
166176
def timestamp_between(dt: datetime, min_seconds: int, max_seconds: int):
167-
return dt + timedelta(max_seconds) > datetime.now(tz=pytz.UTC) > dt + timedelta(seconds=min_seconds)
177+
return (
178+
dt + timedelta(max_seconds)
179+
> datetime.now(tz=pytz.UTC)
180+
> dt + timedelta(seconds=min_seconds)
181+
)
168182

169183
async def _send_ping(self, force_resend: bool = False):
170184
self.last_sent_ping = Ping(env=self.environment, ping_time=datetime.now(tz=pytz.UTC))
@@ -177,4 +191,6 @@ async def _send_ping(self, force_resend: bool = False):
177191
return
178192
except:
179193
pass
180-
self.last_ping_msg = await self.client.send_message(self.log_chat, self.last_sent_ping.json())
194+
self.last_ping_msg = await self.client.send_message(
195+
self.log_chat, self.last_sent_ping.json()
196+
)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from typing import Any, List, Optional
2+
from unittest.mock import Mock
3+
4+
from haps import Inject
5+
from pyrogram import Chat, Message, User
6+
7+
from botkit.core.moduleloader import ModuleLoader
8+
from botkit.core.modules import Module, module
9+
from botkit.routing.pipelines.callbacks import HandlerSignature
10+
from botkit.routing.route import RouteDefinition, RouteHandler
11+
from botkit.routing.route_builder.builder import RouteBuilder
12+
from botkit.routing.route_builder.route_collection import RouteCollection
13+
from botkit.routing.update_types.updatetype import UpdateType
14+
from botkit.types.client import IClient
15+
16+
17+
def notests(func):
18+
func.notests = True
19+
return func
20+
21+
22+
class SystemTestsModule(Module):
23+
loader: ModuleLoader = Inject()
24+
25+
def register(self, routes: RouteBuilder):
26+
pass
27+
28+
async def load(self) -> None:
29+
for m in self.loader.modules:
30+
31+
if not m.route_collection:
32+
continue
33+
34+
for client, routes in m.route_collection.routes_by_client.items():
35+
await self.test_module_routes(routes)
36+
37+
async def unload(self) -> None:
38+
return await super().unload()
39+
40+
async def test_module_routes(self, routes: List[RouteDefinition]):
41+
for route in routes:
42+
for update_type, route_wrapper in route.handler_by_update_type.items():
43+
await self.fire_request(update_type, route_wrapper)
44+
45+
async def fire_request(self, update_type: UpdateType, route: RouteHandler):
46+
try:
47+
should_not_test = route.callback.notests
48+
return
49+
except AttributeError:
50+
pass
51+
52+
client = Mock(IClient)
53+
if update_type == UpdateType.message:
54+
message = Mock(Message)
55+
(user := Mock(User)).configure_mock()
56+
(chat := Mock(Chat)).configure_mock(id=12345)
57+
message.configure_mock(
58+
message_id=12345,
59+
command="test",
60+
from_user=user,
61+
chat=chat,
62+
text="test",
63+
forward_from=None,
64+
reply_to_message=None,
65+
)
66+
try:
67+
res = await route.callback(client, message)
68+
print(res)
69+
except Exception as ex:
70+
self.log.exception(ex)

botkit/botkit_modules/system/sytem_management_module.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pyrogram import Filters, Message, User, Client
77
from typing import Optional, List, Any, Literal
88

9+
from botkit.botkit_modules.system.system_tests import notests
910
from botkit.persistence.callback_manager import (
1011
RedisCallbackManager,
1112
ICallbackManager,
@@ -49,7 +50,9 @@ def register(self, routes: RouteBuilder):
4950
routes.on(restart_command & only_owner).call(self.restart_system)
5051

5152
routes.on(Filters.command(["off", "pause"]) & only_owner).call(self.handle_pause_command)
52-
routes.on(Filters.command(["on", "unpause"]) & only_owner).call(self.handle_unpause_command)
53+
routes.on(Filters.command(["on", "unpause"]) & only_owner).call(
54+
self.handle_unpause_command
55+
)
5356

5457
command_bus.register(_ToggleSystemStateCommandHandler(self))
5558

@@ -59,14 +62,19 @@ async def restart_system(_, message: Message):
5962
await message.delete()
6063
command_bus.execute(
6164
ToggleSystemStateCommand(
62-
new_state="pause", triggered_by="user", reason_phrase="User requested restart of system.",
65+
new_state="pause",
66+
triggered_by="user",
67+
reason_phrase="User requested restart of system.",
6368
)
6469
)
6570
await asyncio.sleep(2)
6671
command_bus.execute(
67-
ToggleSystemStateCommand(new_state="unpause", triggered_by="user", reason_phrase="Starting back up.",)
72+
ToggleSystemStateCommand(
73+
new_state="unpause", triggered_by="user", reason_phrase="Starting back up.",
74+
)
6875
)
6976

77+
@notests
7078
async def handle_pause_command(self, _client, message: Message):
7179
await message.delete()
7280
if self.system_paused:
@@ -83,14 +91,18 @@ async def pause_system(self):
8391
and not self.module_loader.is_disabled(x)
8492
and not isinstance(x, type(self))
8593
]
86-
self.log.info(f"Pausing modules:\n" + "\n".join([m.get_name() for m in loaded_modules]) + "\n...")
94+
self.log.info(
95+
f"Pausing modules:\n" + "\n".join([m.get_name() for m in loaded_modules]) + "\n..."
96+
)
8797
tasks = [self.module_loader.unregister_module(m) for m in loaded_modules]
8898
await asyncio.gather(*tasks, return_exceptions=True)
8999
self.system_paused = True
90100
self.paused_modules = loaded_modules
91101

92102
try:
93-
callback_manager: RedisCallbackManager = Container().get_object(ICallbackManager, "redis")
103+
callback_manager: RedisCallbackManager = Container().get_object(
104+
ICallbackManager, "redis"
105+
)
94106
callback_manager.callbacks.sync()
95107
self.log.info("Callbacks synced.")
96108
except:
@@ -110,7 +122,7 @@ async def unpause_system(self):
110122
if self.paused_modules:
111123
self.log.info(f"Unpausing {len(self.paused_modules)} modules...")
112124
for m in self.paused_modules:
113-
await self.module_loader.register_module(m)
125+
await self.module_loader.try_register_module(m)
114126
else:
115127
self.log.error(
116128
f"For some reason there were no paused modules: {self.paused_modules}. "

botkit/core/moduleloader.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ async def register_enabled_modules(self) -> None:
4848
tasks: List[Coroutine] = []
4949
for n, module in enumerate(self.modules):
5050
module.group_index = n
51-
tasks.append(self.register_module(module))
51+
tasks.append(self.try_register_module(module))
5252

53-
results = await asyncio.gather(*tasks)
53+
await asyncio.gather(*tasks)
5454

55-
async def register_module(self, module: Module) -> None:
55+
async def try_register_module(self, module: Module) -> None:
5656
try:
5757
if self.is_disabled(module):
5858
log.debug(f"{module.get_name()} is disabled.")

botkit/dispatching/dispatcher.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from botkit.core.modules import Module
1010
from botkit.routing.route import RouteHandler
1111
from botkit.routing.update_types.updatetype import UpdateType
12+
from botkit.types.client import IClient
1213

1314
"""
1415
Indicates where the evaluation of individual updates takes place
@@ -24,7 +25,7 @@ class BotkitDispatcher:
2425
def __init__(self):
2526
self.callback_action_dispatchers: Dict[Client, CallbackActionDispatcher] = dict()
2627
self._inline_query_factory: Any = None
27-
self._module_handlers: Dict[int, Dict[Client, List[Handler]]] = dict()
28+
self.module_handlers: Dict[int, Dict[Client, List[Handler]]] = dict()
2829

2930
self.log = logzero.setup_logger(BotkitDispatcher.__name__)
3031

@@ -34,7 +35,9 @@ async def add_module_routes(self, module: Module):
3435
for client, routes in module.route_collection.routes_by_client.items():
3536
for route in routes:
3637
for update_type, route_wrapper in route.handler_by_update_type.items():
37-
await self.add_route_for_update_type(module, client, update_type, route_wrapper)
38+
await self.add_route_for_update_type(
39+
module, client, update_type, route_wrapper
40+
)
3841

3942
"""
4043
TODO: split this up into:
@@ -52,7 +55,8 @@ async def add_module_routes(self, module: Module):
5255
"""
5356

5457
self.log.info(
55-
f"({module.group_index}) {module.get_name()} loaded" + (" with: " + ", ".join(log_msg) if log_msg else "")
58+
f"({module.group_index}) {module.get_name()} loaded"
59+
+ (" with: " + ", ".join(log_msg) if log_msg else "")
5660
)
5761

5862
async def add_route_for_update_type(
@@ -89,14 +93,14 @@ async def add_route_for_update_type(
8993
async def remove_module_routes(self, module: Module):
9094
group = module.group_index
9195

92-
for client, h in self._module_handlers[group].items():
96+
for client, h in self.module_handlers[group].items():
9397
for handler in h:
9498
try:
9599
client.remove_handler(handler, group)
96100
except Exception:
97101
self.log.exception(f"Could not remove handler {handler} from group {group}.")
98102

99-
del self._module_handlers[group]
103+
del self.module_handlers[group]
100104

101105
async def add_handler(self, group: int, client: Client, handler: Handler):
102106
assert group is not None
@@ -106,16 +110,21 @@ async def add_handler(self, group: int, client: Client, handler: Handler):
106110
async with client.dispatcher.locks_list[-1]:
107111
client.add_handler(handler, group)
108112

109-
self._module_handlers.setdefault(group, {})
110-
self._module_handlers[group].setdefault(client, [])
111-
self._module_handlers[group][client].append(handler)
113+
self.module_handlers.setdefault(group, {})
114+
self.module_handlers[group].setdefault(client, [])
115+
self.module_handlers[group][client].append(handler)
112116

113117
def is_registered(self, module: Module) -> bool:
114-
return module.group_index in self._module_handlers
118+
return module.group_index in self.module_handlers
115119

116120
async def _get_or_create_action_dispatcher(self, client) -> CallbackActionDispatcher:
121+
117122
if not (action_dispatcher := self.callback_action_dispatchers.get(client)):
118-
self.callback_action_dispatchers[client] = (action_dispatcher := CallbackActionDispatcher())
123+
self.callback_action_dispatchers[client] = (
124+
action_dispatcher := CallbackActionDispatcher()
125+
)
126+
119127
# All callback queries use the same group (only one of them applies for a given update)
120128
await self.add_handler(0, client, action_dispatcher.pyrogram_handler)
129+
121130
return action_dispatcher

botkit/routing/pipelines/execution_plan.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222

2323
class SendTo(Enum):
24+
self = auto()
2425
same_chat = auto()
2526
same_chat_quote = auto()
2627
same_chat_quote_replied_to = auto()

botkit/routing/pipelines/factories/steps/gather_step_factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ async def gather_initial_state_async(context: BotkitContext):
4444

4545
return result
4646
except Exception as e:
47-
raise GatherStepError(gatherer) from e
47+
raise GatherStepError(e)
4848

4949
return gather_initial_state_async, is_coroutine
5050

botkit/routing/pipelines/factories/steps/send_view_step_factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ def evaluate_send_target(send_target: SendTarget, context: BotkitContext) -> _Ev
103103
else:
104104
static_send_target = send_target
105105

106+
if static_send_target == SendTo.self or static_send_target == SendTo.self.name:
107+
return _EvaluatedSendTarget("me", None)
106108
if static_send_target == SendTo.same_chat or static_send_target == SendTo.same_chat.name:
107109
return _EvaluatedSendTarget(context.chat_id, None)
108110
if (

botkit/routing/route_builder/builder.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
from pyrogram.client.filters.filters import create
2222
from pyrogram.client.handlers.handler import Handler
2323

24-
from botkit.routing.pipelines.execution_plan import ExecutionPlan, SendTarget, SendTo, SendTo
24+
from botkit.routing.pipelines.callbacks import HandlerSignature
25+
from botkit.routing.pipelines.execution_plan import ExecutionPlan, SendTarget, SendTo
2526
from botkit.routing.pipelines.gatherer import GathererSignature
2627
from botkit.routing.pipelines.reducer import ReducerSignature
2728
from botkit.routing.route import RouteDefinition
@@ -31,7 +32,6 @@
3132
from botkit.routing.route_builder.webhook_action_expression import WebhookActionExpressionMixin
3233
from botkit.routing.triggers import RouteTriggers
3334
from botkit.routing.types import TState
34-
from botkit.routing.pipelines.callbacks import HandlerSignature
3535
from botkit.routing.update_types.updatetype import UpdateType
3636
from botkit.types.client import IClient
3737
from botkit.views.base import InlineResultViewBase
@@ -83,15 +83,15 @@ def then_invoke(self, component: "Component") -> RouteExpression:
8383
self._route_collection.add_for_current_client(route)
8484
return RouteExpression(self._route_collection, route)
8585

86-
def then_update(self, view_type): # TODO: update with functional views
86+
def then_update(self, view_type) -> RouteExpression:
8787
self._plan.set_view(view_type, "update")
8888
route = RouteDefinition(triggers=self._triggers, plan=self._plan)
8989
self._route_collection.add_for_current_client(route)
9090
return RouteExpression(self._route_collection, route)
9191

9292
def then_send(
9393
self, view_or_view_type, to: SendTarget = SendTo.same_chat, via: IClient = None,
94-
):
94+
) -> RouteExpression:
9595
if via and not self._route_collection.current_client.is_user:
9696
raise ValueError(
9797
"Can only send a view `via` another bot when the client that this route belongs to is a "
@@ -126,8 +126,16 @@ def call(self, handler: HandlerSignature) -> RouteExpression:
126126
self._route_collection.add_for_current_client(route)
127127
return RouteExpression(self._route_collection, route)
128128

129-
def send_view(self, view: TView) -> RouteExpression:
130-
self._plan.set_view(view, "send")
129+
def send_view(
130+
self, view_or_view_type, to: SendTarget = SendTo.same_chat, via: IClient = None,
131+
):
132+
if via and not self._route_collection.current_client.is_user:
133+
raise ValueError(
134+
"Can only send a view `via` another bot when the client that this route belongs to is a "
135+
"userbot. A userbot and a regular bot together form a 'companion bot' relationship.",
136+
self._route_collection.current_client,
137+
)
138+
self._plan.set_view(view_or_view_type, "send").set_send_via(via).set_send_target(to)
131139
route = RouteDefinition(triggers=self._triggers, plan=self._plan)
132140
self._route_collection.add_for_current_client(route)
133141
return RouteExpression(self._route_collection, route)

0 commit comments

Comments
 (0)