Python / yaml === ###### tags: `Python` ###### tags: `Python`, `PyPi`, `yaml`, `load`, `safe_load`, `safe_load_all`, `default_flow_style` <br> [TOC] <br> ## multi-yaml to JSON ```python= import yaml import json filename = 'slurmcluster-crd.yaml' with open(filename) as f: docs = yaml.safe_load_all(f) docs = [doc for doc in docs] # check field: spec.slurmNodes.worker.slurmd info = docs[3]['spec']['versions'][0]['schema']['openAPIV3Schema']['properties']['spec']['properties']['slurmNodes']['properties']['worker']['properties']['slurmd'] print(json.dumps(info, indent=4)) ``` <br> ## Q&A - ### [Can PyYAML dump dict items in non-alphabetical order?](https://stackoverflow.com/questions/16782112/) ``` yaml.dump(data, sort_keys=False) ``` <br> ## 討論 ### 讀取 k8s yaml 檔 - ### Question 要透過 python 讀取 yaml 檔 但 yaml 檔中,包含 "---" ,主要是因為 k8s 允許多份設定 這樣的 yaml 內容要如何讀取? - ### gpt-o1-preview 要在 Python 中讀取包含多個 YAML 文件的檔案(使用 `---` 分隔符,例如 Kubernetes 的設定檔),您可以使用 `yaml.safe_load_all()` 方法。這個方法會返回一個生成器,您可以迭代它來處理每個文件。 以下是範例程式碼: ```python= import yaml with open('your_file.yaml', 'r') as file: documents = yaml.safe_load_all(file) for doc in documents: # 在這裡處理每個文件 print(doc) ``` 如果您的 YAML 內容是一個字串而不是檔案,您可以直接傳遞字串: ```python= import yaml yaml_content = ''' --- apiVersion: v1 kind: Pod metadata: name: mypod --- apiVersion: v1 kind: Service metadata: name: myservice ''' documents = yaml.safe_load_all(yaml_content) for doc in documents: print(doc) ``` 這樣,您就可以成功讀取並處理包含多個文件的 YAML 檔案。 **總結**:使用 `yaml.safe_load_all()` 方法來讀取包含 `---` 分隔符的多文件 YAML 檔案。 <br> ### 動態執行 YAML 中 script 程式碼的範例 - Question ```python= import yaml s = """ display-name: Llama-3.3-70B-Instruct-8k-vLLM-L40S model: name: Llama-3.3-70B-Instruct engine: name: vLLM required: '>=v0.6.3.post1' version: latest gpu: name: L40S tp: 2 precision: BF16 context-length: 8192 max-num-seqs: 16 gpu-memory-utilization: 0.95 script: | import yaml def hello(): print('hello') """ yaml.safe_load(s) ``` 我要如何動態執行當前 `script` 中所定義的程式碼? - ### gpt-o3-mini-high (2025/02/09) 在 Python 中,可以先將 YAML 解析後,取出其中的 `script` 欄位字串,並使用 Python 的內建函式 `exec` 進行動態執行。例如: ```python= import yaml s = """ display-name: Llama-3.3-70B-Instruct-8k-vLLM-L40S model: name: Llama-3.3-70B-Instruct engine: name: vLLM required: '>=v0.6.3.post1' version: latest gpu: name: L40S tp: 2 precision: BF16 context-length: 8192 max-num-seqs: 16 gpu-memory-utilization: 0.95 script: | import yaml def hello(): print('hello') """ # 1. 載入 YAML data = yaml.safe_load(s) # 2. 取出 script 欄位的程式碼 script_code = data["script"] # 3. 動態執行程式碼 exec(script_code, globals()) # 4. 執行剛剛在 script 中定義的函式 hello() ``` 如上範例程式所示: 1. 先使用 `yaml.safe_load(s)` 將字串載入為 Python dict。 2. 把 `data["script"]` 取出來,該欄位就是 YAML 裡的多行字串程式碼。 3. 使用內建函式` exec(script_code, globals())` 即可動態執行這段程式碼。 4. 由於在 `script` 中定義了 `def hello(): ...`,我們就可以直接呼叫 `hello()`。 **注意**:在真實的生產環境中,`exec` 屬於潛在高風險的動態執行方式,必須確保程式碼來源是信任的,否則有執行惡意程式碼的安全疑慮。 <br> ### 參數 default_flow_style 用途為何? - ### question ``` with open('xxx.yaml', 'w') as f: yaml.dump(yaml.safe_load(s), f, default_flow_style=False) ``` 參數 `default_flow_style` 用途為何? - ### gpt-o1 在 PyYAML 中,`default_flow_style` 參數主要用來控制 YAML 輸出的風格: - **`default_flow_style=True`**:會使用所謂的「flow style」,也就是比較像 JSON 風格的 inline 格式。例如: ```yaml data: {key1: val1, key2: val2} ``` - **`default_flow_style=False`**:會使用「block style」,也就是較為常見、多行縮排的 YAML 格式,例如: ```yaml data: key1: val1 key2: val2 ``` - **`default_flow_style=None`**:PyYAML 會根據資料結構自動判斷。 一般來說,如果想產生可讀性更高、較接近傳統 YAML 格式的輸出,就會設定成 `False`。 <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}