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?
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
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)