Skip to content

Commit

Permalink
Update docstring and add the api-docs generator script
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch committed Mar 24, 2021
1 parent 1282934 commit 66aad21
Show file tree
Hide file tree
Showing 73 changed files with 1,719 additions and 384 deletions.
6 changes: 6 additions & 0 deletions .github/maintainers_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ $ ngrok http 3000 --subdomain {your-domain}

### Releasing

#### Generate API documents

```bash
./scripts/generate_api_docs.sh
```

#### test.pypi.org deployment

##### $HOME/.pypirc
Expand Down
3 changes: 3 additions & 0 deletions docs/_includes/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<a href="{{ site.url | append: site.baseurl | append: localized_base_url }}/tutorial/getting-started">
<li class="title">{{ site.t[page.lang].start }}</li>
</a>
<a href="{{ site.url | append: site.baseurl | append: localized_base_url }}/api-docs/slack_bolt/" target="_blank">
<li class="title">API Documents</li>
</a>
</ul>

<ul class="sidebar-section">
Expand Down
10 changes: 10 additions & 0 deletions scripts/generate_api_docs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
# Generate API documents from the latest source code

script_dir=`dirname $0`
cd ${script_dir}/..

pip install pdoc3
rm -rf docs/api-docs
pdoc slack_bolt --html -o docs/api-docs
open docs/api-docs/slack_bolt/index.html
7 changes: 7 additions & 0 deletions slack_bolt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
A Python framework to build Slack apps in a flash with the latest platform features. Read the [getting started guide](https://slack.dev/bolt-python/tutorial/getting-started) and look at our [code examples](https://github.com/slackapi/bolt-python/tree/main/examples) to learn how to build apps using Bolt.
* Website: https://slack.dev/bolt-python/
* GitHub repository: https://github.com/slackapi/bolt-python
* The class representing a Bolt app: `slack_bolt.app.app`
"""
# Don't add async module imports here
from .app import App # noqa
from .context import BoltContext # noqa
Expand Down
2 changes: 2 additions & 0 deletions slack_bolt/adapter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Adapter modules for running Bolt apps along with Web frameworks or Socket Mode.
"""
7 changes: 7 additions & 0 deletions slack_bolt/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
"""Application interface in Bolt.
For most use cases, we recommend using `slack_bolt.app.app`.
If you already have knowledge about asyncio and prefer the programming model,
you can use `slack_bolt.app.async_app` for building async apps.\
"""

# Don't add async module imports here
from .app import App # type: ignore
406 changes: 327 additions & 79 deletions slack_bolt/app/app.py

Large diffs are not rendered by default.

408 changes: 333 additions & 75 deletions slack_bolt/app/async_app.py

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions slack_bolt/app/async_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ def __init__( # type:ignore
path: str,
app: "AsyncApp", # type:ignore
):
"""Standalone AIOHTTP Web Server
"""Standalone AIOHTTP Web Server.
Refer to https://docs.aiohttp.org/en/stable/web.html for details of AIOHTTP.
Refer to AIOHTTP documents for details.
https://docs.aiohttp.org/en/stable/web.html
Args:
port: The port to listen on
path: The path to receive incoming requests from Slack
app: The `AsyncApp` instance that is used for processing requests
"""
self.port = port
self.path = path
Expand Down Expand Up @@ -70,10 +73,7 @@ async def handle_post_requests(self, request: web.Request) -> web.Response:
return await to_aiohttp_response(bolt_resp)

def start(self) -> None:
"""Starts a new web server process.
:return: None
"""
"""Starts a new web server process."""
if self.bolt_app.logger.level > logging.INFO:
print(get_boot_message())
else:
Expand Down
46 changes: 46 additions & 0 deletions slack_bolt/async_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
"""Module for creating asyncio based apps
### Creating an async app
If you'd prefer to build your app with [asyncio](https://docs.python.org/3/library/asyncio.html), you can import the [AIOHTTP](https://docs.aiohttp.org/en/stable/) library and call the `AsyncApp` constructor. Within async apps, you can use the async/await pattern.
```bash
# Python 3.6+ required
python -m venv .venv
source .venv/bin/activate
pip install -U pip
# aiohttp is required
pip install slack_bolt aiohttp
```
In async apps, all middleware/listeners must be async functions. When calling utility methods (like `ack` and `say`) within these functions, it's required to use the `await` keyword.
```python
# Import the async app instead of the regular one
from slack_bolt.async_app import AsyncApp
app = AsyncApp()
@app.event("app_mention")
async def event_test(body, say, logger):
logger.info(body)
await say("What's up?")
@app.command("/hello-bolt-python")
async def command(ack, body, respond):
await ack()
await respond(f"Hi <@{body['user_id']}>!")
if __name__ == "__main__":
app.start(3000)
```
If you want to use another async Web framework (e.g., Sanic, FastAPI, Starlette), take a look at the built-in adapters and their examples.
* [The Bolt app examples](https://github.com/slackapi/bolt-python/tree/main/examples)
* [The built-in adapters](https://github.com/slackapi/bolt-python/tree/main/slack_bolt/adapter)
Apps can be run the same way as the synchronous example above. If you'd prefer another async Web framework (e.g., Sanic, FastAPI, Starlette), take a look at [the built-in adapters](https://github.com/slackapi/bolt-python/tree/main/slack_bolt/adapter) and their corresponding [examples](https://github.com/slackapi/bolt-python/tree/main/examples).
Refer to `slack_bolt.app.async_app` for more details.
"""
from .app.async_app import AsyncApp # noqa
from .context.ack.async_ack import AsyncAck # noqa
from .context.async_context import AsyncBoltContext # noqa
Expand Down
5 changes: 5 additions & 0 deletions slack_bolt/authorization/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
"""Authorization is the process of determining which Slack credentials should be available
while processing an incoming Slack event.
Refer to https://slack.dev/bolt-python/concepts#authorization for details.
"""
from .authorize_result import AuthorizeResult
11 changes: 6 additions & 5 deletions slack_bolt/authorization/async_authorize_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ def __init__(
team_id: Optional[str], # can be None for org-wide installed apps
user_id: Optional[str],
):
"""The whole arguments that are passed to Authorize functions.
"""The full list of the arguments passed to `authorize` function.
:param context: The request context
:param enterprise_id: The Organization ID (Enterprise Grid)
:param team_id: The workspace ID
:param user_id: The request user ID
Args:
context: The request context
enterprise_id: The Organization ID (Enterprise Grid)
team_id: The workspace ID
user_id: The request user ID
"""
self.context = context
self.logger = context.logger
Expand Down
11 changes: 6 additions & 5 deletions slack_bolt/authorization/authorize_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ def __init__(
team_id: Optional[str], # can be None for org-wide installed apps
user_id: Optional[str],
):
"""The whole arguments that are passed to Authorize functions.
"""The full list of the arguments passed to `authorize` function.
:param context: The request context
:param enterprise_id: The Organization ID (Enterprise Grid)
:param team_id: The workspace ID
:param user_id: The request user ID
Args:
context: The request context
enterprise_id: The Organization ID (Enterprise Grid)
team_id: The workspace ID
user_id: The request user ID
"""
self.context = context
self.logger = context.logger
Expand Down
20 changes: 11 additions & 9 deletions slack_bolt/authorization/authorize_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@


class AuthorizeResult(dict):
"""Authorize function call result"""

enterprise_id: Optional[str]
team_id: Optional[str]
bot_id: Optional[str]
Expand All @@ -25,15 +27,15 @@ def __init__(
user_id: Optional[str] = None,
user_token: Optional[str] = None,
):
"""The `auth.test` API result for an incoming request.
:param enterprise_id: Organization ID (Enterprise Grid)
:param team_id: Workspace ID
:param bot_user_id: Bot user's User ID
:param bot_id: Bot ID
:param bot_token: Bot user access token starting with xoxb-
:param user_id: The request user ID
:param user_token: User access token starting with xoxp-
"""
Args:
enterprise_id: Organization ID (Enterprise Grid) starting with `E`
team_id: Workspace ID starting with `T`
bot_user_id: Bot user's User ID starting with either `U` or `W`
bot_id: Bot ID starting with `B`
bot_token: Bot user access token starting with `xoxb-`
user_id: The request user ID
user_token: User access token starting with `xoxp-`
"""
self["enterprise_id"] = self.enterprise_id = enterprise_id
self["team_id"] = self.team_id = team_id
Expand Down
7 changes: 7 additions & 0 deletions slack_bolt/context/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
"""All listeners have access to a context dictionary, which can be used to enrich events with additional information.
Bolt automatically attaches information that is included in the incoming event,
like `user_id`, `team_id`, `channel_id`, and `enterprise_id`.
Refer to https://slack.dev/bolt-python/concepts#context for details.
"""

# Don't add async module imports here
from .context import BoltContext
68 changes: 68 additions & 0 deletions slack_bolt/context/async_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,94 @@


class AsyncBoltContext(BaseContext):
"""Context object associated with a request from Slack."""

@property
def client(self) -> Optional[AsyncWebClient]:
"""The `AsyncWebClient` instance available for this request.
@app.event("app_mention")
async def handle_events(context):
await context.client.chat_postMessage(
channel=context.channel_id,
text="Thanks!",
)
# You can access "client" this way too.
@app.event("app_mention")
async def handle_events(client, context):
await client.chat_postMessage(
channel=context.channel_id,
text="Thanks!",
)
Returns:
`AsyncWebClient` instance
"""
if "client" not in self:
self["client"] = AsyncWebClient(token=None)
return self["client"]

@property
def ack(self) -> AsyncAck:
"""`ack()` function for this request.
@app.action("button")
async def handle_button_clicks(context):
await context.ack()
# You can access "ack" this way too.
@app.action("button")
async def handle_button_clicks(ack):
await ack()
Returns:
Callable `ack()` function
"""
if "ack" not in self:
self["ack"] = AsyncAck()
return self["ack"]

@property
def say(self) -> AsyncSay:
"""`say()` function for this request.
@app.action("button")
async def handle_button_clicks(context):
await context.ack()
await context.say("Hi!")
# You can access "ack" this way too.
@app.action("button")
async def handle_button_clicks(ack, say):
await ack()
await say("Hi!")
Returns:
Callable `say()` function
"""
if "say" not in self:
self["say"] = AsyncSay(client=self.client, channel=self.channel_id)
return self["say"]

@property
def respond(self) -> Optional[AsyncRespond]:
"""`respond()` function for this request.
@app.action("button")
async def handle_button_clicks(context):
await context.ack()
await context.respond("Hi!")
# You can access "ack" this way too.
@app.action("button")
async def handle_button_clicks(ack, respond):
await ack()
await respond("Hi!")
Returns:
Callable `respond()` function
"""
if "respond" not in self:
self["respond"] = AsyncRespond(response_url=self.response_url)
return self["respond"]
15 changes: 15 additions & 0 deletions slack_bolt/context/base_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,46 @@


class BaseContext(dict):
"""Context object associated with a request from Slack."""

@property
def logger(self) -> Logger:
"""The properly configured logger that is available for middleware/listeners."""
return self["logger"]

@property
def token(self) -> Optional[str]:
"""The (bot/user) token resolved for this request."""
return self.get("token")

@property
def enterprise_id(self) -> Optional[str]:
"""The Enterprise Grid Organization ID of this request."""
return self.get("enterprise_id")

@property
def is_enterprise_install(self) -> Optional[bool]:
"""True if the request is associated with an Org-wide installation."""
return self.get("is_enterprise_install")

@property
def team_id(self) -> Optional[str]:
"""The Workspace ID of this request."""
return self.get("team_id")

@property
def user_id(self) -> Optional[str]:
"""The user ID associated ith this request."""
return self.get("user_id")

@property
def channel_id(self) -> Optional[str]:
"""The conversation ID associated with this request."""
return self.get("channel_id")

@property
def response_url(self) -> Optional[str]:
"""The `response_url` associated with this request."""
return self.get("response_url")

@property
Expand All @@ -46,22 +56,27 @@ def matches(self) -> Optional[Tuple]:

@property
def authorize_result(self) -> Optional[AuthorizeResult]:
"""The authorize result resolved for this request."""
return self.get("authorize_result")

@property
def bot_token(self) -> Optional[str]:
"""The bot token resolved for this request."""
return self.get("bot_token")

@property
def bot_id(self) -> Optional[str]:
"""The bot ID resolved for this request."""
return self.get("bot_id")

@property
def bot_user_id(self) -> Optional[str]:
"""The bot user ID resolved for this request."""
return self.get("bot_user_id")

@property
def user_token(self) -> Optional[str]:
"""The user token resolved for this request."""
return self.get("user_token")

def set_authorize_result(self, authorize_result: AuthorizeResult):
Expand Down
Loading

0 comments on commit 66aad21

Please sign in to comment.