Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 8 additions & 2 deletions slack_bolt/kwargs_injection/async_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# pytype: skip-file
import inspect
import logging
from typing import Callable, Dict, Optional, Any, Sequence

Expand All @@ -25,6 +26,7 @@ def build_async_required_kwargs(
request: AsyncBoltRequest,
response: Optional[BoltResponse],
next_func: Callable[[], None] = None,
this_func: Optional[Callable] = None,
) -> Dict[str, Any]:
all_available_args = {
"logger": logger,
Expand Down Expand Up @@ -73,8 +75,12 @@ def build_async_required_kwargs(
if first_arg_name in {"self", "cls"}:
required_arg_names.pop(0)
elif first_arg_name not in all_available_args.keys():
logger.warning(warning_skip_uncommon_arg_name(first_arg_name))
required_arg_names.pop(0)
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
Expand Down
10 changes: 8 additions & 2 deletions slack_bolt/kwargs_injection/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# pytype: skip-file
import inspect
import logging
from typing import Callable, Dict, Optional, Any, Sequence

Expand All @@ -25,6 +26,7 @@ def build_required_kwargs(
request: BoltRequest,
response: Optional[BoltResponse],
next_func: Callable[[], None] = None,
this_func: Optional[Callable] = None,
) -> Dict[str, Any]:
all_available_args = {
"logger": logger,
Expand Down Expand Up @@ -73,8 +75,12 @@ def build_required_kwargs(
if first_arg_name in {"self", "cls"}:
required_arg_names.pop(0)
elif first_arg_name not in all_available_args.keys():
logger.warning(warning_skip_uncommon_arg_name(first_arg_name))
required_arg_names.pop(0)
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
Expand Down
1 change: 1 addition & 0 deletions slack_bolt/lazy_listener/async_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ async def request_wired_wrapper() -> None:
required_arg_names=arg_names,
request=request,
response=None,
this_func=internal_func,
)
)
except Exception as e:
Expand Down
1 change: 1 addition & 0 deletions slack_bolt/lazy_listener/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def request_wired_func_wrapper() -> None:
required_arg_names=arg_names,
request=request,
response=None,
this_func=func,
)
)
except Exception as e:
Expand Down
1 change: 1 addition & 0 deletions slack_bolt/listener/async_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ async def run_ack_function(
required_arg_names=self.arg_names,
request=request,
response=response,
this_func=self.ack_function,
)
)

Expand Down
1 change: 1 addition & 0 deletions slack_bolt/listener/custom_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ def run_ack_function(
required_arg_names=self.arg_names,
request=request,
response=response,
this_func=self.ack_function,
)
)
1 change: 1 addition & 0 deletions slack_bolt/listener_matcher/async_builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ async def async_matches(self, req: AsyncBoltRequest, resp: BoltResponse) -> bool
required_arg_names=self.arg_names,
request=req,
response=resp,
this_func=self.func,
)
)
1 change: 1 addition & 0 deletions slack_bolt/listener_matcher/async_listener_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ async def async_matches(self, req: AsyncBoltRequest, resp: BoltResponse) -> bool
required_arg_names=self.arg_names,
request=req,
response=resp,
this_func=self.func,
)
)

Expand Down
1 change: 1 addition & 0 deletions slack_bolt/listener_matcher/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def matches(self, req: BoltRequest, resp: BoltResponse) -> bool:
required_arg_names=self.arg_names,
request=req,
response=resp,
this_func=self.func,
)
)

Expand Down
1 change: 1 addition & 0 deletions slack_bolt/listener_matcher/custom_listener_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ def matches(self, req: BoltRequest, resp: BoltResponse) -> bool:
required_arg_names=self.arg_names,
request=req,
response=resp,
this_func=self.func,
)
)
1 change: 1 addition & 0 deletions slack_bolt/middleware/async_custom_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ async def async_process(
request=req,
response=resp,
next_func=next,
this_func=self.func,
)
)

Expand Down
1 change: 1 addition & 0 deletions slack_bolt/middleware/custom_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def process(
request=req,
response=resp,
next_func=next,
this_func=self.func,
)
)

Expand Down
49 changes: 49 additions & 0 deletions tests/scenario_tests/test_app_using_methods_in_class.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import inspect
import json
from time import time, sleep
from typing import Callable
Expand Down Expand Up @@ -31,6 +32,29 @@ def teardown_method(self):
cleanup_mock_web_api_server(self)
restore_os_env(self.old_os_env)

def test_inspect_behaviors(self):
def f():
pass

assert inspect.ismethod(f) is False

class A:
def b(self):
pass

@classmethod
def c(cls):
pass

@staticmethod
def d():
pass

a = A()
assert inspect.ismethod(a.b) is True
assert inspect.ismethod(A.c) is True
assert inspect.ismethod(A.d) is False

def run_app_and_verify(self, app: App):
payload = {
"type": "message_action",
Expand Down Expand Up @@ -119,12 +143,24 @@ def test_instance_methods_uncommon_name(self):
app.shortcut("test-shortcut")(awesome.instance_method2)
self.run_app_and_verify(app)

def test_instance_methods_uncommon_name_3(self):
app = App(client=self.web_client, signing_secret=self.signing_secret)
awesome = AwesomeClass("Slackbot")
app.use(awesome.instance_middleware)
app.shortcut("test-shortcut")(awesome.instance_method3)
self.run_app_and_verify(app)

def test_static_methods(self):
app = App(client=self.web_client, signing_secret=self.signing_secret)
app.use(AwesomeClass.static_middleware)
app.shortcut("test-shortcut")(AwesomeClass.static_method)
self.run_app_and_verify(app)

def test_invalid_arg_in_func(self):
app = App(client=self.web_client, signing_secret=self.signing_secret)
app.shortcut("test-shortcut")(top_level_function)
self.run_app_and_verify(app)


class AwesomeClass:
def __init__(self, name: str):
Expand Down Expand Up @@ -159,7 +195,20 @@ def instance_method2(whatever, context: BoltContext, say: Say, ack: Ack):
ack()
say(f"Hello <@{context.user_id}>! My name is {whatever.name}")

text = "hello world"

def instance_method3(this, ack, logger, say):
ack()
logger.debug(this.text)
say(f"Hi there!")

@staticmethod
def static_method(context: BoltContext, say: Say, ack: Ack):
ack()
say(f"Hello <@{context.user_id}>!")


def top_level_function(invalid_arg, ack, say):
assert invalid_arg is None
ack()
say("Hi")
53 changes: 52 additions & 1 deletion tests/scenario_tests_async/test_app_using_methods_in_class.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import inspect
import json
from time import time
from typing import Callable
Expand Down Expand Up @@ -41,6 +42,29 @@ def event_loop(self):
finally:
restore_os_env(old_os_env)

def test_inspect_behaviors(self):
async def f():
pass

assert inspect.ismethod(f) is False

class A:
async def b(self):
pass

@classmethod
async def c(cls):
pass

@staticmethod
async def d():
pass

a = A()
assert inspect.ismethod(a.b) is True
assert inspect.ismethod(A.c) is True
assert inspect.ismethod(A.d) is False

async def run_app_and_verify(self, app: AsyncApp):
payload = {
"type": "message_action",
Expand Down Expand Up @@ -126,20 +150,34 @@ async def test_instance_methods(self):
await self.run_app_and_verify(app)

@pytest.mark.asyncio
async def test_instance_methods_uncommon_name(self):
async def test_instance_methods_uncommon_name_1(self):
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
awesome = AwesomeClass("Slackbot")
app.use(awesome.instance_middleware)
app.shortcut("test-shortcut")(awesome.instance_method2)
await self.run_app_and_verify(app)

@pytest.mark.asyncio
async def test_instance_methods_uncommon_name_2(self):
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
awesome = AwesomeClass("Slackbot")
app.use(awesome.instance_middleware)
app.shortcut("test-shortcut")(awesome.instance_method3)
await self.run_app_and_verify(app)

@pytest.mark.asyncio
async def test_static_methods(self):
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
app.use(AwesomeClass.static_middleware)
app.shortcut("test-shortcut")(AwesomeClass.static_method)
await self.run_app_and_verify(app)

@pytest.mark.asyncio
async def test_invalid_arg_in_func(self):
app = AsyncApp(client=self.web_client, signing_secret=self.signing_secret)
app.shortcut("test-shortcut")(top_level_function)
await self.run_app_and_verify(app)


class AwesomeClass:
def __init__(self, name: str):
Expand Down Expand Up @@ -182,7 +220,20 @@ async def instance_method2(
await ack()
await say(f"Hello <@{context.user_id}>! My name is {whatever.name}")

text = "hello world"

async def instance_method3(this, ack, logger, say):
await ack()
logger.debug(this.text)
await say(f"Hi there!")

@staticmethod
async def static_method(context: AsyncBoltContext, say: AsyncSay, ack: AsyncAck):
await ack()
await say(f"Hello <@{context.user_id}>!")


async def top_level_function(invalid_arg, ack, say):
assert invalid_arg is None
await ack()
await say("Hi")