テンプレートに埋め込む際の環境変数からの情報取得について

github.com github.com

jinja2テンプレートに埋め込む際に何だかんだで環境変数からの情報が取得できると便利。なので環境変数から取得する方法について考えたりしてみた。

j2cliの場合

元々kamidanaを作る発端となったパッケージに、j2cli というものがあった。こちらはどうなっているかというと。os.environを読み込むだけ。やばい。全ての環境変数がtemplateから見えるのはどうなんだという気持ちがあったりした。

あと、j2cliは複数のsourceから情報を読む事はできないみたいなので、設定の大部分を別のファイルから読み取り、環境変数を使って一部だけ設定を上書きするみたいなことはできない。

ホワイトリストを使って環境変数から読む方法

さすがに全部の環境変数が見えるのは嫌だったのでホワイトリスト形式で読み込むことにした。環境変数を利用して読み取りたい場合には、末尾に “.env” または “.environ” で終わるファイル名のファイルを使うことにする。そしてこれらのファイルの形式はこのsuffixを取り除いたファイル名から決めることにする。例えば、yamlで定義されたホワイトリストの名前は <filename>.yaml.env などになる。

そして、変換後のdictのペアのvalue部分を環境変数から取得するkey名とすることにする。

例えば以下の様なperson.yaml.envがあった場合には、環境変数の “NAME” と “AGE” を見ることにする。

person:
  properties:
    name: NAME
    age: AGE

そしてその環境変数名で引いた値をホワイトリストのファイルのvalue部分に焼き付けた値を設定値とすることにする。 例えば、こういう感じ。

$ NAME=foo AGE=20 dictknife concat person.yaml.env
person:
  properties:
    name: foo
    age: '20'

型を指定したい場合

これはoptionalな機能ではあるけれど。型を指定したい場合がある。先程の例では環境変数から値を取得したのですべての値が文字列になっている。 ageは数値を利用したい事があるかもしれない。この場合に型(というかpythonの組み込みのtype)を":“付きで後置で修飾することにする。以下の様に書く。

person2.yaml.env

person:
  properties:
    name: NAME
    age: AGE:int

AGE部分がintの値になってほしい場合。

$ NAME=foo AGE=20 dictknife concat person2.yaml.env
person:
  properties:
    name: foo
    age: 20

20はintになっている。

kamidanaはdictknifeに依存している

kamidanaはdictknifeに依存しているので上の機能がdictknife上で実装されたらそれがそのまますぐに使える。

--dump-context

その前にkamidanaに --dump-context というオプションを追加した。これは --data により読み込まれたデータがどのようなものであったか判断するのに役に立つ。

例えば以下の様なtemplateと設定ファイルがあるとする。

template.j2

{{name}}({{age}}): hai.

person.yaml

name: foo
age: 20

これをkamidanaで実行すると以下のような結果になる。

$ kamidana --data ./person.yaml template.j2
foo(20): hai.

どのようなデータが読み込まれているか見たい場合に --dump-context が使える。

$ kamidana --data ./person.yaml template.j2 --dump-context
{
  "name": "foo",
  "age": 20,
  "template_filename": "template.j2"
}

jsonで出力されるのが無難そうなので、jsonで出力されるようにした(このあたりは変えるかもしれない)。

環境変数から設定を読み取ってtemplateを使う

kamidanaはdictknifeに依存しているので上の機能がdictknife上で実装されたらそれがそのまますぐに使える。 先程実装した環境変数から設定を読み込む処理を使って同様のことをやってみる。

NAMEとAGEを環境変数から取り出している。

$ NAME=bar AGE=10 kamidana --data ./person.yaml.env template.j2 --dump-context
{
  "name": "bar",
  "age": 10,
  "template_filename": "template.j2"
}
$ NAME=bar AGE=10 kamidana --data ./person.yaml.env template.j2
bar(10): hai.

j2cliとは異なり、一部分だけを環境変数で上書きということも出来る。名前だけ環境変数経由でbarに変えてみる。

$ NAME=bar kamidana --data ./person.yaml --data ./person.yaml.env template.j2 --dump-context
{
  "name": "bar",
  "age": 20,
  "template_filename": "template.j2"
}
$ NAME=bar kamidana --data ./person.yaml --data ./person.yaml.env template.j2
bar(20): hai.

--data オプションで後方に来たもので上書きされる。