Skip to content

Commit cf5ef98

Browse files
committed
feat: emit ExperimentalWarning when agent kwarg is used
Adds a custom ExperimentalWarning (subclass of FutureWarning) that is emitted when a listener explicitly requests the `agent` argument, informing developers that this feature is experimental and subject to change. Co-Authored-By: William Bergamin <wbergamin@salesforce.com>
1 parent 5335855 commit cf5ef98

File tree

6 files changed

+74
-2
lines changed

6 files changed

+74
-2
lines changed

slack_bolt/adapter/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
"""Adapter modules for running Bolt apps along with Web frameworks or Socket Mode.
2-
"""
1+
"""Adapter modules for running Bolt apps along with Web frameworks or Socket Mode."""

slack_bolt/kwargs_injection/async_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import inspect
22
import logging
3+
import warnings
34
from typing import Callable, Dict, MutableSequence, Optional, Any
45

56
from slack_bolt.request.async_request import AsyncBoltRequest
67
from slack_bolt.response import BoltResponse
8+
from slack_bolt.warning import ExperimentalWarning
79
from .async_args import AsyncArgs
810
from slack_bolt.request.payload_utils import (
911
to_options,
@@ -86,6 +88,12 @@ def build_async_required_kwargs(
8688
# Defer agent creation to avoid constructing AsyncBoltAgent on every request
8789
if "agent" in required_arg_names or "args" in required_arg_names:
8890
all_available_args["agent"] = request.context.agent
91+
if "agent" in required_arg_names:
92+
warnings.warn(
93+
"The agent listener argument is experimental and may change in future versions.",
94+
category=ExperimentalWarning,
95+
stacklevel=2, # Point to the caller, not this internal helper
96+
)
8997

9098
if len(required_arg_names) > 0:
9199
# To support instance/class methods in a class for listeners/middleware,

slack_bolt/kwargs_injection/utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import inspect
22
import logging
3+
import warnings
34
from typing import Callable, Dict, MutableSequence, Optional, Any
45

56
from slack_bolt.request import BoltRequest
67
from slack_bolt.response import BoltResponse
8+
from slack_bolt.warning import ExperimentalWarning
79
from .args import Args
810
from slack_bolt.request.payload_utils import (
911
to_options,
@@ -85,6 +87,12 @@ def build_required_kwargs(
8587
# Defer agent creation to avoid constructing BoltAgent on every request
8688
if "agent" in required_arg_names or "args" in required_arg_names:
8789
all_available_args["agent"] = request.context.agent
90+
if "agent" in required_arg_names:
91+
warnings.warn(
92+
"The agent listener argument is experimental and may change in future versions.",
93+
category=ExperimentalWarning,
94+
stacklevel=2, # Point to the caller, not this internal helper
95+
)
8896

8997
if len(required_arg_names) > 0:
9098
# To support instance/class methods in a class for listeners/middleware,

slack_bolt/warning/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Bolt specific warning types."""
2+
3+
4+
class ExperimentalWarning(FutureWarning):
5+
"""Warning for features that are still in experimental phase."""
6+
7+
pass

tests/scenario_tests/test_events_agent.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
from time import sleep
33
from unittest.mock import patch, MagicMock
44

5+
import pytest
56
from slack_sdk.web import WebClient
67
from slack_sdk.web.chat_stream import ChatStream
78

89
from slack_bolt import App, BoltRequest, BoltContext, BoltAgent
910
from slack_bolt.agent.agent import BoltAgent as BoltAgentDirect
11+
from slack_bolt.warning import ExperimentalWarning
1012
from tests.mock_web_api_server import (
1113
setup_mock_web_api_server,
1214
cleanup_mock_web_api_server,
@@ -188,6 +190,29 @@ def test_agent_import_from_agent_module(self):
188190

189191
assert ImportedBoltAgent is BoltAgentDirect
190192

193+
def test_agent_kwarg_emits_experimental_warning(self):
194+
app = App(client=self.web_client)
195+
196+
state = {"called": False}
197+
198+
def assert_target_called():
199+
count = 0
200+
while state["called"] is False and count < 20:
201+
sleep(0.1)
202+
count += 1
203+
assert state["called"] is True
204+
state["called"] = False
205+
206+
@app.event("app_mention")
207+
def handle_mention(agent: BoltAgent):
208+
state["called"] = True
209+
210+
request = BoltRequest(body=app_mention_event_body, mode="socket_mode")
211+
with pytest.warns(ExperimentalWarning, match="agent listener argument is experimental"):
212+
response = app.dispatch(request)
213+
assert response.status == 200
214+
assert_target_called()
215+
191216

192217
# ---- Test event bodies ----
193218

tests/scenario_tests_async/test_events_agent.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from slack_bolt.app.async_app import AsyncApp
1111
from slack_bolt.context.async_context import AsyncBoltContext
1212
from slack_bolt.request.async_request import AsyncBoltRequest
13+
from slack_bolt.warning import ExperimentalWarning
1314
from tests.mock_web_api_server import (
1415
cleanup_mock_web_api_server_async,
1516
setup_mock_web_api_server_async,
@@ -206,6 +207,30 @@ async def test_agent_import_from_agent_module(self):
206207

207208
assert ImportedAsyncBoltAgent is AsyncBoltAgent
208209

210+
@pytest.mark.asyncio
211+
async def test_agent_kwarg_emits_experimental_warning(self):
212+
app = AsyncApp(client=self.web_client)
213+
214+
state = {"called": False}
215+
216+
async def assert_target_called():
217+
count = 0
218+
while state["called"] is False and count < 20:
219+
await asyncio.sleep(0.1)
220+
count += 1
221+
assert state["called"] is True
222+
state["called"] = False
223+
224+
@app.event("app_mention")
225+
async def handle_mention(agent: AsyncBoltAgent):
226+
state["called"] = True
227+
228+
request = AsyncBoltRequest(body=app_mention_event_body, mode="socket_mode")
229+
with pytest.warns(ExperimentalWarning, match="agent listener argument is experimental"):
230+
response = await app.async_dispatch(request)
231+
assert response.status == 200
232+
await assert_target_called()
233+
209234

210235
# ---- Test event bodies ----
211236

0 commit comments

Comments
 (0)