字典转YAML对象引号丢失:Stubby配置文件生成异常求助
解决PyYAML safe_dump移除Stubby配置所需引号的问题
我明白你遇到的麻烦了——Stubby要求appdata_dir和tls_auth_name的字符串值必须带双引号才能正常工作,但PyYAML的safe_dump默认会把这些不必要的引号去掉,导致配置失效。下面给你两个可行的解决方案:
方案1:给PyYAML加自定义代表器,强制特定键带引号
我们可以通过重写PyYAML的字符串序列化逻辑,让它在遇到指定的键时,自动给对应的值加上双引号。修改你的代码如下:
import yaml from yaml.representer import Representer import logging import json # 定义需要强制保留引号的键 REQUIRE_QUOTES = {'appdata_dir', 'tls_auth_name'} def quoted_str_representer(dumper, value): # 检查当前正在序列化的键是否在需要引号的列表里 if hasattr(dumper, 'key') and dumper.key in REQUIRE_QUOTES: return dumper.represent_scalar('tag:yaml.org,2002:str', value, style='"') # 其他字符串保持默认处理 return dumper.represent_scalar('tag:yaml.org,2002:str', value) # 注册自定义的代表器 yaml.add_representer(str, quoted_str_representer, Representer) def get_dns_config(dns_option) -> str: with open('dns.yml', 'r') as f: data = yaml.safe_load(f) with open('dns_template.yml', 'r') as f: template = yaml.safe_load(f) template['upstream_recursive_servers'] = data[dns_option]['servers'] logging.debug(json.dumps(template, indent=4)) yaml_output = yaml.safe_dump(template, default_flow_style=False, indent=2) logging.debug(yaml_output) return yaml_output
这个方法的核心是拦截字符串的序列化过程,当检测到目标键时,强制使用双引号包裹值。
方案2:改用ruamel.yaml(更省心的选择)
PyYAML在处理这类格式细节上确实不够灵活,而ruamel.yaml是它的增强版,专门为保留YAML格式细节设计,用它来解决这个问题会更简单。
首先安装库:
pip install ruamel.yaml
然后修改你的代码:
from ruamel.yaml import YAML from ruamel.yaml.scalarstring import DoubleQuotedScalarString import logging import json def get_dns_config(dns_option) -> str: yaml = YAML() yaml.indent(mapping=2, sequence=4, offset=2) yaml.default_flow_style = False with open('dns.yml', 'r') as f: data = yaml.load(f) with open('dns_template.yml', 'r') as f: template = yaml.load(f) # 给新增的tls_auth_name值加上双引号标记 for server in data[dns_option]['servers']: server['tls_auth_name'] = DoubleQuotedScalarString(server['tls_auth_name']) template['upstream_recursive_servers'] = data[dns_option]['servers'] # 如果模板里的appdata_dir加载后没有引号,也手动标记 template['appdata_dir'] = DoubleQuotedScalarString(template['appdata_dir']) logging.debug(json.dumps(template, indent=4)) # 生成YAML输出 output = [] yaml.dump(template, output) yaml_output = ''.join(output) logging.debug(yaml_output) return yaml_output
用DoubleQuotedScalarString包装字符串后,ruamel.yaml在输出时会自动保留双引号,完全符合Stubby的要求。
最终效果验证
无论用哪个方案,你都会得到符合要求的YAML输出:
resolution_type: GETDNS_RESOLUTION_STUB dns_transport_list: - GETDNS_TRANSPORT_TLS tls_authentication: GETDNS_AUTHENTICATION_REQUIRED tls_query_padding_blocksize: 128 edns_client_subnet_private: 1 round_robin_upstreams: 1 idle_timeout: 10000 listen_addresses: - 10.7.0.1 appdata_dir: "/var/cache/stubby" upstream_recursive_servers: - address_data: 185.228.168.168 tls_auth_name: "family-filter-dns.cleanbrowsing.org" - address_data: 185.228.169.168 tls_auth_name: "family-filter-dns.cleanbrowsing.org"
内容的提问来源于stack exchange,提问作者karnage
相关产品推荐
相关产品推荐

