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 %}