CommentedMap.update() 不保留评论

CommentedMap.update() not preserving comments

我不确定我是否从正确的角度解决了这个问题,如果您有其他看法,请告诉我。

使用 ruamel.yaml 模块,我想在将它们转储并保留其注释之前获得一些配置文件的表示。

为此我基本上有:

#!/usr/bin/env python3.5

from ruamel.yaml import YAML
class MyYaml():
  def __init__(self, cm):
    self.yaml = YAML()
    self.yaml.default_flow_style = False
    self.cm = cm
    
  def load_main_config_file(self, path):
    if isinstance(path, str):
      with open(path, 'r') as config_file:
        self.cm.update(self.yaml.load(config_file))
        # cannot be self.cm = self.yaml.load(config_file)
        # because it would change the id of self.cm
        # the dict would not be accessible from outside anymore
        
  def load_config_file(self, path_key_list, target_dict = None):
    for file_path,key_list in path_key_list:
      with open(file_path, 'r') as config_file:
        self.update_dict((target_dict if target_dict is not None else self.cm), key_list, self.yaml.load(config_file))
        
  def update_dict(self, my_dict, key_list, value):
    """
    Works fine to preserve comments but cannot be used for the main config file as the dict is empty
    """
    for k in key_list[:-1]:
      my_dict = my_dict.setdefault(k, {})
    my_dict[key_list[-1]] = value
    
from ruamel.yaml.comments import CommentedMap 
from copy import deepcopy
class Parent():
  def __init__(self):
    self.__cm = CommentedMap() # private so users cannot modify
    self.Yaml = MyYaml(self.__cm)

  @property
  def cm(self):
    return deepcopy(self.__cm)
    
from ruamel.yaml import YAML
import sys
class Child(Parent):
  def __init__(self):
    super().__init__()
    yaml = YAML()
    self.Yaml.load_main_config_file("path_to_file")
    print("\n\n############################")
    print("Main load : ")
    print("############################")
    yaml.dump(self.cm, sys.stdout)
    print("\n\n############################")
    print("Other load :")
    print("############################")
    self.Yaml.load_config_file([("path_to_file",["other_file"])])
    yaml.dump(self.cm, sys.stdout)
    
if __name__ == "__main__":
   ch = Child()

我得到了这个输出:

############################
Main load :
############################
key1: val1
key2: val2
key3:
  key31: val31
  key32: val32

key4:
  key41: val41


############################
Other load :
############################
key1: val1
key2: val2
key3:
  key31: val31
  key32: val32

key4:
  key41: val41
other_file:
############
# ! TEST ! #
############
  key1: val1

# Comment 1
  key2: val2

#this is a comment
  key3:
    key31: val31
    key32: val32

  key4:
    key41: val41

有什么建议可以让第一个配置文件保留注释吗?

PS :这是我第一次 post 在这里,我希望它足够清楚。感谢您的宝贵时间!

在线:

  self.cm.update(self.yaml.load(config_file))

load()returns一个CommentedMap(),从中更新只使用key 值对。如果你想复制评论:

  tmp_cm = self.yaml.load(config_file)
  self.cm.update(tmp_cm)
  tmp_cm.copy_attributes(self.cm)

如果您想保留 self.cm 上任何已经存在的评论,对于键 不会更新的,您应该检查 .ca 属性并执行 更新相关项目,而不是完全覆盖评论。

请注意,此“内部数据”不保证保持稳定, 所以固定你的 ruamel.yaml 版本,并在更改该版本之前进行测试。 您还应该考虑更新 Python 版本,因为 3.5 已停产 ruamel.yaml 中的支持将随着下一次次要版本升级而下降。

完整节目:

import sys
from ruamel.yaml import YAML

class MyYaml():
  def __init__(self, cm):
    self.yaml = YAML()
    self.yaml.default_flow_style = False
    self.cm = cm

  def load_main_config_file(self, path):
    if isinstance(path, str):
      with open(path, 'r') as config_file:
        tmp_cm = self.yaml.load(config_file)
        self.cm.update(tmp_cm)
        tmp_cm.copy_attributes(self.cm)
        # cannot be self.cm = self.yaml.load(config_file)
        # because it would change the id of self.cm
        # the dict would not be accessible from outside anymore
    
  def load_config_file(self, path_key_list, target_dict = None):
    for file_path,key_list in path_key_list:
      with open(file_path, 'r') as config_file:
        self.update_dict((target_dict if target_dict is not None else self.cm), key_list, self.yaml.load(config_file))
    
  def update_dict(self, my_dict, key_list, value):
    """
    Works fine to preserve comments but cannot be used for the main config file as the dict is empty
    """
    for k in key_list[:-1]:
      my_dict = my_dict.setdefault(k, {})
    my_dict[key_list[-1]] = value

from ruamel.yaml.comments import CommentedMap 
from copy import deepcopy
class Parent():
  def __init__(self):
    self.__cm = CommentedMap() # private so users cannot modify
    self.Yaml = MyYaml(self.__cm)

  @property
  def cm(self):
    return deepcopy(self.__cm)

from ruamel.yaml import YAML
import sys
class Child(Parent):
  def __init__(self):
    super().__init__()
    yaml = YAML()
    self.Yaml.load_main_config_file("path_to_file")
    print("\n\n############################")
    print("Main load : ")
    print("############################")
    yaml.dump(self.cm, sys.stdout)
    print("\n\n############################")
    print("Other load :")
    print("############################")
    self.Yaml.load_config_file([("path_to_file",["other_file"])])
    yaml.dump(self.cm, sys.stdout)

if __name__ == "__main__":
   ch = Child()

给出:

############################
Main load : 
############################
key1: val1

# Comment 1
key2: val2

#this is a comment
key3:
  key31: val31
  key32: val32

key4:
  key41: val41


############################
Other load :
############################
key1: val1

# Comment 1
key2: val2

#this is a comment
key3:
  key31: val31
  key32: val32

key4:
  key41: val41
other_file:
  key1: val1

# Comment 1
  key2: val2

#this is a comment
  key3:
    key31: val31
    key32: val32

  key4:
    key41: val41

请注意,“嵌套”文件中的注释不会缩进,您 将不得不遍历各个评论并更改他们的开始列来实现这一点。