-
Notifications
You must be signed in to change notification settings - Fork 288
Expand file tree
/
Copy pathasync_utils.py
More file actions
134 lines (124 loc) · 4.99 KB
/
async_utils.py
File metadata and controls
134 lines (124 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import inspect
import logging
import warnings
from typing import Callable, Dict, MutableSequence, Optional, Any
from slack_bolt.request.async_request import AsyncBoltRequest
from slack_bolt.response import BoltResponse
from slack_bolt.warning import ExperimentalWarning
from .async_args import AsyncArgs
from slack_bolt.request.payload_utils import (
to_options,
to_shortcut,
to_action,
to_view,
to_command,
to_event,
to_message,
to_step,
)
from ..logger.messages import warning_skip_uncommon_arg_name
def build_async_required_kwargs(
*,
logger: logging.Logger,
required_arg_names: MutableSequence[str],
request: AsyncBoltRequest,
response: Optional[BoltResponse],
next_func: Optional[Callable[[], None]] = None,
this_func: Optional[Callable] = None,
error: Optional[Exception] = None, # for error handlers
next_keys_required: bool = True, # False for listeners / middleware / error handlers
) -> Dict[str, Any]:
all_available_args: Dict[str, Any] = {
"logger": logger,
"client": request.context.client,
"req": request,
"request": request,
"resp": response,
"response": response,
"context": request.context,
"body": request.body,
# payload
"options": to_options(request.body),
"shortcut": to_shortcut(request.body),
"action": to_action(request.body),
"view": to_view(request.body),
"command": to_command(request.body),
"event": to_event(request.body),
"message": to_message(request.body),
"step": to_step(request.body),
# utilities
"ack": request.context.ack,
"say": request.context.say,
"respond": request.context.respond,
"complete": request.context.complete,
"fail": request.context.fail,
"set_status": request.context.set_status,
"set_title": request.context.set_title,
"set_suggested_prompts": request.context.set_suggested_prompts,
"get_thread_context": request.context.get_thread_context,
"save_thread_context": request.context.save_thread_context,
# middleware
"next": next_func,
"next_": next_func, # for the middleware using Python's built-in `next()` function
# error handler
"error": error, # Exception
}
if not next_keys_required:
all_available_args.pop("next")
all_available_args.pop("next_")
all_available_args["payload"] = (
all_available_args["options"]
or all_available_args["shortcut"]
or all_available_args["action"]
or all_available_args["view"]
or all_available_args["command"]
or all_available_args["event"]
or all_available_args["message"]
or all_available_args["step"]
or request.body
)
for k, v in request.context.items():
if k not in all_available_args:
all_available_args[k] = v
# Defer agent creation to avoid constructing AsyncBoltAgent on every request
if "agent" in required_arg_names:
from slack_bolt.agent.async_agent import AsyncBoltAgent
event = request.body.get("event", {})
all_available_args["agent"] = AsyncBoltAgent(
client=request.context.client,
channel_id=request.context.channel_id,
thread_ts=request.context.thread_ts or event.get("thread_ts"),
ts=event.get("ts"),
team_id=request.context.team_id,
user_id=request.context.user_id,
)
warnings.warn(
"The agent listener argument is experimental and may change in future versions.",
category=ExperimentalWarning,
stacklevel=2, # Point to the caller, not this internal helper
)
if len(required_arg_names) > 0:
# To support instance/class methods in a class for listeners/middleware,
# check if the first argument is either self or cls
first_arg_name = required_arg_names[0]
if first_arg_name in {"self", "cls"}:
required_arg_names.pop(0)
elif first_arg_name not in all_available_args.keys() and first_arg_name != "args":
if this_func is None:
logger.warning(warning_skip_uncommon_arg_name(first_arg_name))
required_arg_names.pop(0)
elif inspect.ismethod(this_func):
# We are sure that we should skip manipulating this arg
required_arg_names.pop(0)
kwargs: Dict[str, Any] = {k: v for k, v in all_available_args.items() if k in required_arg_names}
found_arg_names = kwargs.keys()
for name in required_arg_names:
if name == "args":
if isinstance(request, AsyncBoltRequest):
kwargs[name] = AsyncArgs(**all_available_args)
else:
logger.warning(f"Unknown Request object type detected ({type(request)})")
elif name not in found_arg_names:
logger.warning(f"{name} is not a valid argument")
kwargs[name] = None
return kwargs