web-dev-qa-db-fra.com

Comment remplacer la valeur de variable d'environnement dans le fichier yaml à analyser en utilisant python

J'ai besoin d'utiliser la variable d'environnement "PATH" dans le fichier yaml qui doit être analysé avec un script.

Voici la variable d'environnement que j'ai définie sur mon terminal:

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

Voici mon sample.yml:

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

Lorsque j'analyse ce fichier yaml avec mon script, je ne vois pas la valeur réelle des variables PATH.

Voici mon script:

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",

Sortie:

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

La sortie attendue est:

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

Quelqu'un peut-il m'aider à trouver la bonne façon de le faire si je le fais mal?

6
npatel

La bibliothèque PY-yaml ne résout pas les variables d'environnement par défaut. Vous devez définir un résolveur implicite qui trouvera l'expression régulière qui définit une variable d'environnement et exécutera une fonction pour la résoudre.

Vous pouvez le faire via yaml.add_implicit_resolver et yaml.add_constructor. Dans le code ci-dessous, vous définissez un résolveur qui correspondra à $ {env variable} dans la valeur YAML et appelez la fonction path_constructor pour rechercher la variable d'environnement.

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

Voici une version alternative qui utilise une nouvelle classe Loader si vous ne souhaitez pas modifier le chargeur yaml global/par défaut.

Et plus important encore, il remplace correctement les chaînes interpolées qui ne sont pas uniquement les variables d'environnement, par exemple 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