スプレッドシートを設定ファイルとして使うライブラリを作ってみた
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"
}