2017-07-17 116 views
1

我們有一個項目,它將設置存儲在YAML中(設置文件由可執行腳本生成)。現在我們使用pyyaml來解析YAML格式和棉花糖來驗證設置。我很喜歡在YAML中存儲設置,但我不認爲marshmellow是我需要的工具(模式很難閱讀,我不需要序列化設置,想要像xsd)。那麼在項目中驗證設置的最佳實踐是什麼,也許有語言獨立的方式? (我們使用Python 2.7)解析和驗證YAML配置文件的最佳方式

YAML設置:

successive: 
    worker: 
    cds_process_number: 0 # positive integer or zero 
    spider_interval: 10 # positive integer 
    run_worker_sh: /home/lmakeev/CDS/releases/master/scripts/run_worker.sh # OS path 
    allow: 
     - "*" # regular expression 
    deny: 
     - "^[A-Z]{3}_.+$" # regular expression 
+0

可能會詳細說明一點。你爲什麼認爲棉花糖不是正確的工具?現在這是非常開放的。 – Grimmy

+0

由於非常複雜的結構架構難以閱讀,我不需要序列化的設置,想要的東西像xsd – Helvdan

+0

這樣的事情?:https://github.com/Julian/jsonschema – Grimmy

回答

1

一個模式描述是它自己的語言,用它自己的語法,你必須學會​​的特質。如果您的要求發生變化,您必須維護您的YAML所針對的「程序」。

如果您已經在使用YAML並熟悉Python,則可以使用YAML的標記工具在分析時檢查對象。

假設你有一個文件input.yaml

successive: 
    worker: 
    cds_process_number: !nonneg 0 
    spider_interval: !pos 10 
    run_worker_sh: !path /home/lmakeev/CDS/releases/master/scripts/run_worker.sh 
    allow: 
     - !regex "*" 
    deny: 
     - !regex "^[A-Z]{3}_.+$" 

,您可以創建並註冊使用以下program¹是檢查值的四個班(除去和標籤插入評論您的示例文件):

import sys 
import os 
import re 
import ruamel.yaml 
import pathlib 

class NonNeg: 
    yaml_tag = u"!nonneg" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = int(node.value) # this creates/returns an int 
     assert val >= 0 
     return val 

class Pos(int): 
    yaml_tag = u"!pos" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = cls(node.value) # this creates/return a Pos() 
     assert val > 0 
     return val 

class Path: 
    yaml_tag = u"!path" 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = pathlib.Path(node.value) 
     assert os.path.exists(val) 
     return val 


class Regex: 
    yaml_tag = u"!regex" 
    def __init__(self, val, comp): 
     # store original string and compile() of that string 
     self._val = val 
     self._compiled = comp 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     val = str(node.value) 
     try: 
      comp = re.compile(val) 
     except Exception as e: 
      comp = None 
      print("Incorrect regex", node.start_mark) 
      print(" ", node.tag, node.value) 
     return cls(val, comp) 


yaml = ruamel.yaml.YAML(typ="safe") 
yaml.register_class(NonNeg) 
yaml.register_class(Pos) 
yaml.register_class(Path) 
yaml.register_class(Regex) 

data = yaml.load(pathlib.Path('input.yaml')) 

個人from_yaml classmethods中的實際檢查應該適合您的需要(我必須刪除Path的斷言,因爲我沒有該文件)。

如果你運行上面的你會注意它打印:

Incorrect regex in "input.yaml", line 7, column 9 
    !regex * 

因爲"*"不是有效的正則表達式。您的意思是:".*"


¹這是使用ruamel.yaml,一個YAML 1.2分析器,其中我的作者來完成。您可以使用PyYAML實現相同的結果,例如通過子類化ObjectDict(默認情況下不安全,因此請確保在代碼中正確)

相關問題