2020-06-13
Slack のステータスを変更する CLI ツールっぽいものを Python で作ってみた
一つ前の記事で Google Apps Script を使って Slack のステータスを変更しましたが、今回はそれを Python 製の CLI ツールっぽいものとして作ってみた話です。
目次
概要
コマンドラインから Slack のステータスを変更するコードを Python で実装します。 CLI ツールというほどしっかりしたものではないため、 「っぽいもの」 ということにしておきます。
基本的には前回の記事で書いたスクリプトを Python に書き換えるのですが、セットする絵文字やメッセージをコマンドラインからオプションとして渡せるような形で実装をしています。
Google Apps Script で Slack のステータスを変更する
実装
構成としては、 Slack の API や対象のユーザ ID などを記述した設定ファイル config.json と、実際の処理をする Python スクリプト change_status.py の 2 つを次のように配置します。
$ tree .
.
├── config.json
└── src
└── change_status.py
config.json
config.json の中身は次のような構造にします。
{
"slack": {
"user_id": "XXXXXXXX",
"api_token": "xoxp-********-********-********",
"default_status_emoji": ":ghost:",
"default_status_message": "I'm a ghost."
}
}
user_id: ステータス変更の対象となる Slack ユーザの ID です。api_token: Slack API を利用するための token です。 スコープとしてusers.profile:writeが必要になります。default_status_emoji: 絵文字指定オプションを省略した際に使用する絵文字コードです。default_status_message: メッセージ指定オプションを省略した際に使用するメッセージです。
change_status.py
change_status.py は次のように実装します。ランタイムは Python 3 です。
import argparse
import json
import os
import urllib.parse
import urllib.request
# define config value
with open(os.path.dirname(os.path.abspath(__file__)) + '/../config.json') as j:
config = json.load(j)
USER_ID = config['slack']['user_id']
API_TOKEN = config['slack']['api_token']
DEFAULT_STATUS_EMOJI = config['slack']['default_status_emoji']
DEFAULT_STATUS_MESSAGE = config['slack']['default_status_message']
PROFILE_SET_URL = 'https://slack.com/api/users.profile.set'
# CLI option setting
p = argparse.ArgumentParser()
p.add_argument('-e', '--emoji',
help='Slack emoji code for status icon. (e.g) :ghost:',
default=DEFAULT_STATUS_EMOJI)
p.add_argument('-m', '--message',
help='message for status.',
default=DEFAULT_STATUS_MESSAGE)
args = p.parse_args()
def set_status(emoji, message):
# type: (str) -> ()
"""Set Slack status."""
headers = {
'Authorization': 'Bearer %s' % API_TOKEN,
'X-Slack-User': USER_ID,
'Content-Type': 'application/json; charset=utf-8'
}
params = {
'profile': {
'status_emoji': emoji,
'status_text': message
}
}
req = urllib.request.Request(
PROFILE_SET_URL,
method='POST',
data=json.dumps(params).encode('utf-8'),
headers=headers
)
with urllib.request.urlopen(req) as res:
print(json.dumps(json.loads(res.read().decode('utf-8')), indent=2))
if __name__ == '__main__':
status_emoji = args.emoji
status_message = args.message
set_status(status_emoji, status_message)
特に変わったところは無いですが、コマンドラインから実行する際に引数とオプションを楽に扱うことが出来るように argparse モジュールを使用しています。
ファイル上部にある下記の部分で、コマンドラインオプションの設定をしています。
# CLI option setting
p = argparse.ArgumentParser()
p.add_argument('-e', '--emoji',
help='Slack emoji code for status icon. (e.g) :ghost:',
default=DEFAULT_STATUS_EMOJI)
p.add_argument('-m', '--message',
help='message for status.',
default=DEFAULT_STATUS_MESSAGE)
args = p.parse_args()
これで、 -e または --emoji オプション、 -m または --message オプションを使用して絵文字とメッセージそれぞれの値を受け取ることができます。例えば -e オプションで指定された値をプログラム内で参照するには、 args.emoji のようにして使います。
argparse については下記の記事を参考にしました。
argparse を使用すると、 -h オプションで実行することで add_argument() の help で指定した文字列が良い感じに出力されます。
$ python3 src/change_status.py -h
usage: change_status.py [-h] [-e EMOJI] [-m MESSAGE]
optional arguments:
-h, --help show this help message and exit
-e EMOJI, --emoji EMOJI
Slack emoji code for status icon. (e.g) :ghost:
-m MESSAGE, --message MESSAGE
message for status.
Docker イメージで実行
次のコマンドを叩いて実行します。
$ python3 src/change_status.py
ただ、これだと Python 3 の環境が無いとダメなので、 Docker イメージで実行できるようにしてみました。
次のような Dockerfile を用意します。今回は Python 3.8.3 のイメージを使用します。
FROM python:3.8.3
COPY . /app
ENTRYPOINT [ "python", "/app/src/change_status.py" ]
これをビルドして
$ docker build -t michimani/chss .
実行します。
$ docker run michimani/chss
オプションを指定する場合は次のように実行します。
$ docker run michimani/chss -e ":monkey:" -m "I am a monkey."
このように、 Docker は CLI っぽく使うことが出来るのが良いですね。必要なプロセスを必要なときにだけ起動して、不要になったら削除するという Docker の主とした使い方です。 … まあこれは先日レビューしたみんなの Python の 第 2 章に書かれていたことなんですが。
まとめ
Slack のステータスを変更する CLI ツールっぽいものを Python で作ってみた話でした。 ソースコードは GitHub に置いているので、もしよかったら使ってみてください。
https://github.com/michimani/chss
用途としては、毎日の勤務開始・終了と一緒に使うくらいですかね…。