スプレッドシートを設定ファイルとして使うライブラリを作ってみた
slackやdiscordなどのbotを作るときに、ファイルを触れない人にも設定をいじってもらおうとしたら、スプレッドシートあたりが無難なのかなと思いました。そんなわけでスプレッドシートを設定ファイルとして使うライブラリを作ってみました。
インストール方法
いつもどおりpipで以下のように実行してみてください (主にgspreadとpydanticに依存しています)。
$ pip install sheetconf
使い方
基本的には pydantic で作成したConfigクラスをパラメータとして取ります。
sheetconf.loadfile()
にConfigクラスとformatを渡してください。
注意点として、必ず、セクションが別れたConfigクラスを定義する必要があります。以下のコードでは、xxx,yyy,loggerというセクションに分かれています。
import typing_extensions as tx import sheetconf from pydantic import BaseModel, Field class XXXConfig(BaseModel): name: str token: str class YYYConfig(BaseModel): name: str = Field(default="yyy", description="name of yyy") token: str = Field(description="token of yyy") class LoggerConfig(BaseModel): level: tx.Literal["DEBUG", "INFO", "WARNING", "ERROR"] class Config(BaseModel): xxx: XXXConfig yyy: YYYConfig logger: LoggerConfig if __name__ == "__main__": url = "https://docs.google.com/spreadsheets/d/1PgLfX5POop6QjpgjDLE9wbSWWXJYcowxRBEpxmpG8og" config = sheetconf.loadfile(url, config=Config, format="spreadsheet", adjust=True) print(config) # Config(logger=LoggerConfig(level='INFO'), xxx=XXXConfig(name='xxx', token='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), yyy=YYYConfig(name='yyy', token='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'))
利用しているスプレッドシートはこういう感じのものです。スプレッドシート中の各ワークシート(タブ)が1つのセクションを表しています。
credentials
スプレッドシートの読み取りには権限が必要です。初回実行時にこういうメッセージが出るのでいい感じに設定してください。
CredentialsFileIsNotFound('/Users/me/.config/sheetconf/credentials.json') Please save file at /Users/me/.config/sheetconf/credentials.json (OAuth 2.0 client ID) opening... https://console.cloud.google.com/apis/credentials
CSVファイルを設定ファイルとして読み込み
何かを試すときに常にスプレッドシートが必要というのもまた面倒ですね。formatに"csv"を指定すると、csvファイルをスプレッドシートの代わりに読み込めます。
$ tree config-csv/ config-csv/ ├── logger.csv ├── xxx.csv └── yyy.csv $ python -m sheetconf.cli load --config=00sheetconf.py:Config --format=csv config-csv Config(xxx=XXXConfig(name='xxx', token='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), yyy=YYYConfig(name='yyy', token=''), logger=LoggerConfig(level='DEBUG'))
もちろんpython側のほうでも同様の指定でCSVを読み込めます。
if __name__ == "__main__": url = "config-csv" config = sheetconf.loadfile(url, config=Config, format="csv", adjust=True) print(config)
対応しているのは以下の様なフォーマットです。
name,value,value_type,description name,xxx,str, token,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,str,
JSONファイルの読み込み
たとえスプレッドシートが不要になったとしても、CSVファイルの場合は1ファイルで完結しないので不便ですね。JSONファイルでも大丈夫です。
if __name__ == "__main__": url = "config.json" config = sheetconf.loadfile(url, config=Config, format="json", adjust=True) print(config)
以下の設定ファイルはlogger部分を含んでいませんが、loggerはConfigの定義時にdefaultを指定しているので推測してくれます。
config.json
{ "xxx": { "name": "", "token": "" }, "yyy": { "name": "yyy", "token": "" } }
$ python -m sheetconf.cli load --config=00sheetconf.py:Config --format=json config.json Config(xxx=XXXConfig(name='', token=''), yyy=YYYConfig(name='yyy', token=''), logger=LoggerConfig(level='DEBUG'))
init
初回などに設定ファイルを作るのは面倒ですね。シートさえ用意してあげたらinitで生成することができます。面倒なのでJSONでやりますが、CSVファイルやスプレッドシートでも同様です。
$ python -m sheetconf.cli init --config=00sheetconf.py:Config --format=json config2.json $ cat config2.json { "xxx": { "name": "", "token": "" }, "yyy": { "name": "yyy", "token": "" }, "logger": { "level": "DEBUG" } }
jsonschema
ついでにおまけと言ってはなんですが、pydanticのJSONSchemaを生成する機能をCLI越しで使えます。
$ python -m sheetconf.cli schema --config=00sheetconf.py:Config { "definitions": { "XXXConfig": { "title": "XXXConfig", "type": "object", "properties": { "name": { "title": "Name", "type": "string" }, "token": { "title": "Token", "type": "string" } }, "required": [ "name", "token" ] }, "YYYConfig": { "title": "YYYConfig", "type": "object", "properties": { "name": { "title": "Name", "description": "name of yyy", "default": "yyy", "type": "string" }, "token": { "title": "Token", "description": "token of yyy", "type": "string" } }, "required": [ "token" ] }, "LoggerConfig": { "title": "LoggerConfig", "type": "object", "properties": { "level": { "title": "Level", "anyOf": [ { "const": "DEBUG", "type": "string" }, { "const": "INFO", "type": "string" }, { "const": "WARNING", "type": "string" }, { "const": "ERROR", "type": "string" } ] } }, "required": [ "level" ] }, "Config": { "title": "Config", "type": "object", "properties": { "xxx": { "$ref": "#/definitions/XXXConfig" }, "yyy": { "$ref": "#/definitions/YYYConfig" }, "logger": { "$ref": "#/definitions/LoggerConfig" } }, "required": [ "xxx", "yyy", "logger" ] } }, "$ref": "#/definitions/Config" }