如何用Python的ruamel.yaml保留YAML原有格式(引号、布尔值大小写)
解决ruamel.yaml导出时引号丢失、布尔值小写的问题
我用Python的ruamel.yaml库加载YAML文件,仅需添加若干键值对后原样导出,但导出后出现两个问题:原有字符串的引号丢失,布尔值True被转为小写true。
输入YAML文件
--- # *REQUIRED* person: name: 'John Doe' age: '30' city: 'Sample City' apis: - 'bigquery' - 'bigquerydatatransfer' - 'bigquerystorage' - 'bigtableadmin' - 'cloudbuild' - 'cloudkms' preferences: theme: 'dark' language: en_US test: '77' shared_vpc_service: 'shared-vpc-admin' ################################################################# ################################################################# # *OPTIONAL* - Add Project to VPC Service Controls Security Perimeter # Default: True # If Set to False - Project will not be added to VPC Service Controls enable_vpc_svc_ctrls: True #################################################################
导出后异常的YAML文件
--- # *REQUIRED* person: name: John Doe age: '30' city: Sample City apis: - bigquery - bigquerydatatransfer - bigquerystorage - bigtableadmin - cloudbuild - cloudkms preferences: theme: dark language: en_US test: '77' shared_vpc_service: shared-vpc-admin ################################################################# ################################################################# # *OPTIONAL* - Add Project to VPC Service Controls Security Perimeter # Default: True # If Set to False - Project will not be added to VPC Service Controls enable_vpc_svc_ctrls: true #################################################################
我尝试过的无效代码
def add_quotes(value): # Add single quotes if the value is a string and not a boolean if isinstance(value, str) and not value.lower() == 'true': return f"{value}" # Convert boolean values to title case and keep them without quotes elif isinstance(value, bool): if str(value).lower() == 'true': return True else: return False else: return value def process_yaml(node): if isinstance(node, dict): for key, value in node.items(): node[key] = process_yaml(value) elif isinstance(node, list): for i, item in enumerate(node): node[i] = process_yaml(item) else: node = add_quotes(node) return node
问题核心原因
ruamel.yaml默认加载时会把带引号的字符串转为普通Python字符串,布尔值转为Python原生bool类型,导出时会按YAML默认规则输出(无需引号的字符串自动去掉引号,布尔值统一小写)。要保留原格式,必须利用ruamel.yaml的格式保留特性,而非手动修改字符串。
正确实现代码
from ruamel.yaml import YAML from ruamel.yaml.scalarstring import SingleQuotedScalarString from ruamel.yaml.scalarbool import BoolScalar def load_yaml_with_format(input_path): yaml = YAML() yaml.preserve_quotes = True # 开启引号保留功能 # 自定义布尔值加载逻辑,保留原大小写格式 def bool_loader(loader, node): raw_value = loader.construct_scalar(node) return BoolScalar(raw_value == 'True') yaml.constructor.add_constructor('tag:yaml.org,2002:bool', bool_loader) with open(input_path, 'r', encoding='utf-8') as f: return yaml.load(f), yaml def add_custom_keys(data): # 示例:添加带单引号的新键值对 data['person']['email'] = SingleQuotedScalarString('john.doe@example.com') return data def save_yaml_with_format(data, yaml, output_path): # 自定义布尔值导出逻辑,输出大写True/False def bool_dumper(dumper, value): return dumper.represent_scalar('tag:yaml.org,2002:bool', 'True' if value else 'False') yaml.representer.add_representer(BoolScalar, bool_dumper) with open(output_path, 'w', encoding='utf-8') as f: yaml.dump(data, f) # 执行流程 input_file = 'input.yaml' output_file = 'output.yaml' yaml_data, yaml_obj = load_yaml_with_format(input_file) yaml_data = add_custom_keys(yaml_data) save_yaml_with_format(yaml_data, yaml_obj, output_file)
代码说明
yaml.preserve_quotes = True:让ruamel.yaml自动保留原有字符串的引号格式,无需手动拼接引号。- 自定义布尔值加载器:将YAML中的
True/False转为BoolScalar类型(而非原生bool),保留原始大小写信息。 - 自定义布尔值导出器:导出时将
BoolScalar类型转为大写的True/False字符串,匹配原文件格式。 - 新增字符串处理:用
SingleQuotedScalarString包裹新增字符串,确保新内容也遵循原文件的引号风格。
内容的提问来源于stack exchange,提问作者evidCoder
相关产品推荐
相关产品推荐

