web-dev-qa-db-ja.com

pythonスクリプトを使用して解析されるyamlファイルの環境変数値を置換する方法

スクリプトで解析する必要があるyamlファイルで環境変数「PATH」を使用する必要があります。

これは、端末で設定した環境変数です。

$ echo $PATH
/Users/abc/Downloads/tbwork

これは私のsample.ymlです:

---
Top: ${PATH}/my.txt
Vars:
- a
- b

このyamlファイルをスクリプトで解析すると、PATH変数の実際の値が表示されません。

これは私のスクリプトです:

import yaml
import os
import sys

stream = open("sample.yml", "r")
docs = yaml.load_all(stream)
for doc in docs:
    for k,v in doc.items():
        print k, "->", v
    print "\n",

出力:

Top -> ${PATH}/my.txt
Vars -> ['a', 'b']

予想される出力は次のとおりです。

Top -> /Users/abc/Downloads/tbwork/my.txt
Vars -> ['a', 'b']

間違った方法でやっている場合、誰かが正しい方法を見つけるのを手伝ってくれますか?

6
npatel

PY-yamlライブラリは、デフォルトでは環境変数を解決しません。環境変数を定義する正規表現を見つけ、それを解決する関数を実行する暗黙的なリゾルバーを定義する必要があります。

yaml.add_implicit_resolverおよびyaml.add_constructorを使用して実行できます。以下のコードでは、YAML値の$ {env変数}に一致するリゾルバーを定義し、関数path_constructorを呼び出して環境変数を検索しています。

import yaml
import re
import os

path_matcher = re.compile(r'\$\{([^}^{]+)\}')
def path_constructor(loader, node):
  ''' Extract the matched value, expand env variable, and replace the match '''
  value = node.value
  match = path_matcher.match(value)
  env_var = match.group()[2:-1]
  return os.environ.get(env_var) + value[match.end():]

yaml.add_implicit_resolver('!path', path_matcher)
yaml.add_constructor('!path', path_constructor)

data = """
env: ${VAR}/file.txt
other: file.txt
"""

if __name__ == '__main__':
  p = yaml.safe_load(data)
  print(os.environ.get('VAR')) ## /home/abc
  print(p['env']) ## /home/abc/file.txt
9
dmchk

グローバル/デフォルトのyaml Loaderを変更したくない場合に、新しいLoaderクラスを使用する代替バージョンを次に示します。

さらに重要なことは、環境変数だけではなく、例えばpath/to/${SOME_VAR}/and/${NEXT_VAR}/foo/bar

        path_matcher = re.compile(r'.*\$\{([^}^{]+)\}.*')
        def path_constructor(loader, node):
            return os.path.expandvars(node.value)

        class EnvVarLoader(yaml.SafeLoader):
            pass

        EnvVarLoader.add_implicit_resolver('!path', path_matcher, None)
        EnvVarLoader.add_constructor('!path', path_constructor)

        with open(configPath) as f:
            c = yaml.load(f, Loader=EnvVarLoader)
5
kolis