代码之家  ›  专栏  ›  技术社区  ›  user541

PyYaml事件结构中不必要的子键引用和通过主键的迭代

  •  0
  • user541  · 技术社区  · 8 年前

    我有下一个代码:

    import gnupg
    import re
    import textwrap
    from pprint import pprint
    import yaml
    from yaml.events import *
    
    class AppendableEvents:
      def __init__(self, path, events):
        self.path = path
        self.events = events
    
      def correct_position(self, levels):
        if len(self.path) != len(levels):
          return False
        for index, expected in enumerate(self.path):
          if expected != levels[index].cur_id:
            return False
        return True
    
    class Level:
      def __init__(self, mode):
        self.mode = mode
        self.cur_id = -1 if mode == "item" else ""
    
    def append_to_yaml(yamlFile, targetFile, items):
      events = []
      levels = []
      with open(yamlFile, 'r') as handle:
        for event in yaml.parse(handle):
          if isinstance(event, StreamStartEvent) or \
             isinstance(event, StreamEndEvent) or \
             isinstance(event, DocumentStartEvent) or \
             isinstance(event, DocumentEndEvent):
            pass
          elif isinstance(event, CollectionStartEvent):
            if len(levels) > 0:
              if levels[-1].mode == "key":
                # we can only handle scalar keys
                raise ValueError("encountered complex key!")
              else:
                if levels[-1].mode == "value":
                  levels[-1].mode = "key"
            if isinstance(event, MappingStartEvent):
              levels.append(Level("key"))
            else: # SequenceStartEvent
              levels.append(Level("item"))
          elif isinstance(event, ScalarEvent):
            if len(levels) > 0:
              if levels[-1].mode == "item":
                levels[-1].cur_id += 1
              elif levels[-1].mode == "key":
                levels[-1].cur_id = event.value
                levels[-1].mode = "value"
              else: # mode == "value"
                levels[-1].mode = "key"
          elif isinstance(event, CollectionEndEvent):
            # here we check whether we want to append anything
            levels.pop()
            for item in items:
              if item.correct_position(levels):
                for additional_event in item.events:
                  events.append(additional_event)
          events.append(event)
      with open(targetFile, mode="w") as handle:
        yaml.emit(events, handle,line_break=True)
    
    def key(name):
      return ScalarEvent(None, None, (True, True), name)
    
    def literal_value(content):
      return ScalarEvent(None, None, (False, True), content, style="|")
    
    def map(*scalarValues):
      return [MappingStartEvent(None, None, True)] + \
        [ScalarEvent(None, None, (False, True), v, style="|") for v in scalarValues] + \
        [MappingEndEvent()]
    
    
    gpg = gnupg.GPG(gnupghome='~/.gnupg')
    gpg.encoding = 'utf-8'
    
    def ExistingFile():
        with open(creds) as sensitive_data:
            for line in sensitive_data:
                encrypted_value = gpg.encrypt(
                    re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1),
                    recipients="test", always_trust=True)
                if not encrypted_value.ok:
                    print(encrypted_value.status, '\n', encrypted_value.stderr)
                    break
                line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
                append_to_yaml(f1, f1, [
                  AppendableEvents(["global","app1"], [
                    key("app2")] + map(line, encrypted_value.data.decode()))])
                    #key(line), literal_value(encrypted_value.data.decode())])])
    
    ExistingFile()
    

    creds文件的内容为:

    1=1
    sadsa=ars
    

    f1文件的内容为:

    global:
        app1:
          test: |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE----- 
    

    在这段代码中,必要的键、子键和值被附加到yaml文件中的相应块中。

    但问题是,我在关键方法中传递的值正在被迭代,因此会根据creds文件中的内容追加两次或更多:

    global:
        app1:
          test: |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----     
        app2:
          "1": |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----
        app2:
          "sadsa": |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----
    

    此外,子键“1”和“sadsa”还附加了双引号。

    我想去掉双引号,当我将其与map方法结合使用时,我在key方法中传递的值只会附加到文件中一次。

    因此,最终结果将是,例如:

    global:
        app1:
          test: |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----     
        app2:
          1: |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----
          sadsa: |
            -----BEGIN PGP MESSAGE-----
            Version: GnuPG v1
            -----END PGP MESSAGE-----
    

    笔记 :带literal\u value方法的注释行工作得很好,所以我不想破坏它的逻辑,用map方法更改case。

    1 回复  |  直到 8 年前
        1
  •  1
  •   flyx    8 年前

    首先,请提供 最小的 提问时的示例。我删除了 gnupg 代码中的内容,因为它与您的问题根本不相关。您的责任是只提供实际代码的相关部分,以便试图帮助您的人不需要深入挖掘不相关的行。

    现在,要解决您的问题:您只需要适当地构造输出的事件。这里有一个解决方案(没有 gnupg公司 材料):

    def ExistingFile():
      with open(creds) as sensitive_data:
        additions = [key("app2"), MappingStartEvent(None, None, True)]
        for line in sensitive_data:
          encrypted_value = re.sub(r'^( +?|[A-Za-z0-9]|[A-Za]|[0-9])+( +)?' + '=' + '( +)?', '', line, 1)
          line = re.sub(r'^( +)?|( +)?' + '=' + '.*', '', line.rstrip('\n'))
          additions.extend(
            [ScalarEvent(None, None, (True, False), line),
             ScalarEvent(None, None, (False, True), encrypted_value, style='|')])
        additions.append(MappingEndEvent())
        append_to_yaml(f1, f1_mod, [AppendableEvents(["global", "app1"], additions)])
    

    如您所见,我为键构造的标量事件与为值构造的标量事件不同,因此值表示为文字标量,键表示为普通标量(不带引号)。

    我也打电话 append_to_yaml 只有一次这样 app2 仅创建一次。

    推荐文章