Skip to main content

Click support for Slack-Bolt apps

Project description

Click support for Slack Apps

As a Python Slack-Bolt application developer I want to create slash-command that are composed with the Python Click package. I use the FastAPI web framework in asyncio mode.

I need support for --help --version and any usage error to be properly sent as Slack messages.

Quick Start

Check out the example application.

Async Usage

The following example illustrates how to device a Click group object and bind it to the Slack-Bolt command listener. In this example the code is all asyncio. Click was not written to support async io natively, so the @click_async decorator is required.

By default the Developer should pass the Slack-Bolt request instance as the Click obj value when executing the Click group/command. There is a mechanism to change this behavior, shown in a later example.

import click
from slack_bolt.request.async_request import AsyncBoltRequest as Request
from slack_click.async_click import click_async, version_option, AsyncSlackClickGroup

# -----------------------------------------------------------------------------
# Define a Click group handler for the Slack Slash-Command
#
# Notes:
#   @click_async decorator must be used for asyncio mode
#   @click.pass_obj inserts the click.Context obj into the callback parameters
#       By default the obj is the Slack-Bolt request instance; see the
#       @app.command code further down.
# -----------------------------------------------------------------------------

@click.group(name="/clicker", cls=AsyncSlackClickGroup)
@version_option(version="0.1.0")
@click.pass_obj
@click_async
async def cli_click_group(request: Request):
    """
    This is the Clicker /click command group
    """
    say = request.context["say"]
    await say("`/click` command invoked without any commands or options.")


# -----------------------------------------------------------------------------
# Register the command with Slack-Bolt
# -----------------------------------------------------------------------------

@app.command(cli_click_group.name)
async def on_clicker(request: Request, ack, say):
    await ack()
    await say("Got it.")

    return await cli_click_group(prog_name=cli_click_group.name, obj=request)

# -----------------------------------------------------------------------------
# Add a command the Click group
# -----------------------------------------------------------------------------

@cli_click_group.command("hello")
@click.pass_obj
async def click_hello_command(request: Request):
    await request.context.say(f"Hi there <@{request.context.user_id}> :eyes:")

Identifying the Slack-Bolt Request

As a Developer you may need to pass the Click obj as something other than the bolt request direct, as shown in the example above. You can identify where the Slack-Bolt request object can be found in the obj by passing a callback function to the click.command() or click.group() function called slack_request. This parameter expects a function that takes the click obj and returns the slack request.

The example below uses an inline lambda to get the request from the obj as a dictionary, using a the key "here".

from random import randrange

import click
from slack_bolt.request.async_request import AsyncBoltRequest as Request
from slack_click.async_click import click_async, AsyncSlackClickCommand

# -----------------------------------------------------------------------------
# /fuzzy command to manifest an anminal
# -----------------------------------------------------------------------------


animals = [":smile_cat:", ":hear_no_evil:", ":unicorn_face:"]


@click.command(
    name="/fuzzy", cls=AsyncSlackClickCommand, slack_request=lambda obj: obj["here"]
)
@click_async
@click.pass_obj
async def cli_fuzzy_command(obj: dict):
    request = obj["here"]
    say = request.context["say"]
    this_animal = animals[randrange(len(animals))]

    await say(f"Poof :magic_wand: {this_animal}")


@app.command(cli_fuzzy_command.name)
async def on_fuzzy(request: Request, ack):
    await ack()
    return await cli_fuzzy_command(
        prog_name=cli_fuzzy_command.name, obj={"here": request}
    )

Customizing Help

If you want to change the Slack message format for help or usage methods you can subclass AsyncSlackCLickCommand or AsyncSlackClickGroup and overload the methods:

  • slack_format_help - returns the Slack message payload (dict) for --help
  • slack_format_usage_help - returns the Slack message payload (dict) when click exception UsageError is raised.

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slack_click-2.0.1.tar.gz (11.2 kB view hashes)

Uploaded Source

Built Distribution

slack_click-2.0.1-py3-none-any.whl (11.1 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page