2015-06-18 394 views
3

我想在我的Python腳本中使用YAML配置文件,我發現的問題之一是我無法訪問其他屬性,所以我需要複製大量內容。Python YAML參數參考(從其他參數獲取值)

例如

root_path: /root 
script_path: root_path + /scripts 

這並不存在,當然,但有某種方式來實現這一目標?因爲有很多的,我不能重複的,因爲當一個人改變內容,我需要到處改變它...

我也在創造自己的聯接功能

root_path: &ROOT /root 
script_path: !join [*ROOT, '/scripts'] 


def join(loader, node): 
    seq = loader.construct_sequence(node) 
    return ''.join([str(i) for i in seq]) 

yaml.add_constructor('!join', join) 

但我需要每次設置一個&VARNAME,這將是很好的自動設置參數鍵作爲參考對象...

回答

1

嗯,我一直在努力尋找解決方案,因爲沒有什麼是我想要的東西,一切是如此的複雜,我想死......

該解決方案轉換一個%something%字符串轉換爲something值。

它完美,這是一個例子

root_path: /root 
script_path: "%root%/scripts" 

使用這種方法,script_path將成爲/root/scripts

def replace_values(yaml_file): 
    def _get(dict, list): 
     return reduce(lambda d, k: d[k], list, dict) 

    def _replace(obj): 
     for k, v in obj.iteritems(): 
      if isinstance(v, dict): 
       _replace(v) 
      if isinstance(v, str): 
       match = re.match(r'%(.*)%', v) 
       if match: 
        reference = match.group(1).split('.') 
        replace = _get(yaml_file, reference) 
        obj[k] = re.sub(r'%.*%', replace, v) 

    _replace(yaml_file) 
    return yaml_file 

用法很簡單,只需以正常方式加載Yaml文件,然後調用replace。

with open(config_file.get(options.env), 'r') as ymlfile: 
    config = yaml.load(ymlfile) 

config = replace_values(config) 

然後我們的新config將存儲的替代值,它不會覆蓋原有的文件.yml當然。我希望你覺得這很有用,我真的這麼做,因爲這正是我所需要的。

我用一個百分比%道理,但你可以將其更改爲任何你想要的,改變方法,使其與正則表達式的工作(有些令牌是由正則表達式,這就是爲什麼我用%使用)

0

你不能真的用YAML做到這一點。對於一個配置文件,你也可以使用ConfigParser,它可以讓你插入值,使你的例子是這樣的:

root_path: /root 
script_path: %(root_path)s/scripts 
0

我僅僅調整了YAML解析器有點¹:

import ruamel.yaml as yaml 
from ruamel.yaml.comments import CommentedMap 

yaml_str = """\ 
root_path: /root # use this key for expansion of values 
script_path: root_path + /scripts 
""" 

def set_item(self, key, value): 
    split_val = value.split(' + ', 1) 
    if len(split_val) > 1: 
     alt_key = split_val[0].strip() 
     if alt_key in self.keys(): 
      value = self.get(alt_key) + split_val[1] 
    self._org__setitem__(key, value) 

CommentedMap._org__setitem__ = CommentedMap.__setitem__ 
CommentedMap.__setitem__ = set_item 

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader) 
print yaml.dump(data, Dumper=yaml.RoundTripDumper) 

會給你:

root_path: /root # use this key for expansion of values 
script_path: /root/scripts 

請注意,無論是評論和按鍵的順序被保留與RoundTripLoader /自卸車組合。 data作爲一個正常的Python dict


使用ruamel.yaml由本人筆者¹這樣做。它是PyYAML的一個超集,主要用於保存數據往返的評論和其他信息。