pyyaml并仅使用字符串引号

时间:2016-07-14 08:59:39

标签: python quotes pyyaml

我有以下YAML文件:

---
my_vars:
  my_env: "dev"
  my_count: 3

当我用PyYAML读取它并再次转储它时,我得到以下输出:

---
my_vars:
  my_env: dev
  my_count: 3

有问题的代码:

with open(env_file) as f:
    env_dict = yaml.load(f)
    print(yaml.dump(env_dict, indent=4, default_flow_style=False, explicit_start=True))

我尝试使用default_style参数:

with open(env_file) as f:
    env_dict = yaml.load(f)
    print(yaml.dump(env_dict, indent=4, default_flow_style=False, explicit_start=True, default_style='"'))

但现在我明白了:

---
"my_vars":
  "my_env": "dev"
  "my_count": !!int "3"

我需要做些什么来保持原始格式,没有对YAML文件中的变量名做出任何假设?

3 个答案:

答案 0 :(得分:7)

我建议您使用向后兼容的ruamel.yaml包更新为使用YAML 1.2(2009年发布),而不是使用实现大部分YAML 1.1(2005)的PyYAML。 (免责声明:我是该套餐的作者)。

然后,您只需在加载YAML文件的往返时指定preserve_quotes=True

import sys
import ruamel.yaml

yaml_str = """\
---
my_vars:
  my_env: "dev"    # keep "dev" quoted
  my_count: 3
"""

data = ruamel.yaml.round_trip_load(yaml_str, preserve_quotes=True)
ruamel.yaml.round_trip_dump(data, sys.stdout, explicit_start=True)

输出(包括保留的评论):

---
my_vars:
  my_env: "dev"    # keep "dev" quoted
  my_count: 3

加载字符串后,标量符号将成为字符串的子类,以便能够容纳引用信息,但对于所有其他目的,它将像普通字符串一样工作。如果你想要替换这样的字符串(devfgw) 你必须将字符串强制转换为此子类(DoubleQuotedScalarString的{​​{1}})。

默认情况下,往返ruamel.yaml.scalarstring会保留按键的顺序(通过插入)。

答案 1 :(得分:3)

是的,所以从this answer大量借用,你可以这样做:

import yaml

# define a custom representer for strings
def quoted_presenter(dumper, data):
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')

yaml.add_representer(str, quoted_presenter)


env_file = 'input.txt'
with open(env_file) as f:
    env_dict = yaml.load(f)
    print yaml.dump(env_dict, default_flow_style=False)

但是,这只会在字典中的所有字符串类型上重载它,因此它也会引用键,而不仅仅是值。

打印:

"my_vars":
  "my_count": 3
  "my_env": "dev"
这是你想要的吗?不确定你的变量名是什么意思,你的意思是键吗?

答案 2 :(得分:0)

您可以使用以下方法在 double quoted scalar 中保留您的 yaml 对象:

以你的 yaml 为例:

---
my_vars:
  my_env: "dev"
  my_count: 3

将其加载到 env_dict(字典)中:

myyaml = '''
---
my_vars:
  my_env: "dev"
  my_count: 3
'''

env_dict = yaml.load(myyaml, yaml.FullLoader) # loading yaml

print(env_dict)
{'my_vars': {'my_env': 'dev', 'my_count': 3}}

# Define a quoted class, which uses style = '"' and add representer to yaml

class quoted(str):
    pass

def quoted_presenter(dumper, data):
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
yaml.add_representer(quoted, quoted_presenter)


# Now, we update the dictionary env_dict as follows for the "dev" 
# value which needs to be a double quoted scalar

env_dict['my_vars'].update(my_env = quoted("dev")) # this makes "dev"
# a double quoted scalar

# Now, we dump the yaml as before

yaml.dump(env_dict, sys.stdout, indent=4, default_flow_style=False, explicit_start=True)

# which outputs

---
my_vars:
    my_count: 3
    my_env: "dev"

这些链接帮助我得出了这个答案:Any yaml libraries in Python that support dumping of long strings as block literals or folded blocks?

How can I control what scalar form PyYAML uses for my data?

此外,这是一篇值得在 To Quote or not to Quote?

上阅读的好文章

希望,这会有所帮助!