Skip to content

Enable to use instance/class methods for listeners #174

Description

@seratch

Currently, App/AsyncApp accepts only static methods as listeners. Developers may want to use instance/class methods in a class for some reason. We can update the kwrags_injection mechanism to accept cls, self along with other args.

from slack_bolt import App
app = App()

class Foo:
    def i(self, ack):
        ack()

    @classmethod
    def c(cls, ack):
        ack()

    @classmethod
    def c2(cls):
        def _c(ack):
            ack()
        return _c

    @staticmethod
    def s(ack):
        ack()


foo = Foo()

# This works
@app.command('/hello-bolt-python')
def handle(ack):
    ack()

# This works
app.command('/hello-bolt-python')(handle)

# This does not work
app.command('/hello-bolt-python')(foo.i)

# This does not work
app.command('/hello-bolt-python')(Foo.c)

# This works
app.command('/hello-bolt-python')(Foo.c2())

# This works
app.command('/hello-bolt-python')(Foo.s)

Category (place an x in each of the [ ])

  • slack_bolt.App and/or its core components
  • slack_bolt.async_app.AsyncApp and/or its core components
  • Adapters in slack_bolt.adapter
  • Others

Requirements

Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.

Activity

  1. added this to the 1.1.3 milestone on Dec 7, 2020
  2. self-assigned this
    on Dec 7, 2020
  3. removed this from the 1.1.3 milestone on Dec 11, 2020
  4. seratch commented on Dec 11, 2020

    @seratch
    ContributorAuthor

    I tried to update this library to support the use cases like i and c in the above example. However, it was not so easy that I concluded that handling cls / self in the current design is not possible (at least, I do not have any magical idea to implement it).

    The recommended ways are:

    • Use methods that do not belong to a class (se handle in the example)
    • Use static methods in a class (see Foo.s in the example)
    • Returns a function from class/instance methods (see Foo.c2() in the example)
  5. reopened this on Jan 5, 2021
  6. seratch commented on Jan 5, 2021

    @seratch
    ContributorAuthor

    #191 gave me an inspiration - I managed to fix this issue now. I will come up with a pull request.

  7. added this to the 1.2.0 milestone on Jan 5, 2021
  8. added a commit that references this issue on Jan 8, 2021
    899ce76
  9. liuyangc3 commented on Jan 12, 2021

    @liuyangc3
    Contributor

    Hi @seratch , I think the bound method and function is not just that simple by distinguishing with their first argument name, normally we should use the self as the first argument of the method, but consider the code below, it can runs too.

    class T:
        text = 'hello world'
        def say(this):
            print(this.text)
    
    T.say()

    I think a better way to do this is using inspect.ismethod.

  10. seratch commented on Jan 12, 2021

    @seratch
    ContributorAuthor

    @liuyangc3 Thanks for the helpful suggestion. Although my implementation already works also in this scenario, checking the signature using inspect.ismethod is a better way to go. I will update the code later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions