【问题标题】:How can I distinguish end of line comments from full line comments in ruamel.yaml?如何区分 ruamel.yaml 中的行尾注释和整行注释?
【发布时间】:2021-06-25 21:40:57
【问题描述】:

为了使复杂的 Azure DevOps 管道自记录,我尝试自动从 YAML 文件中读取 cmets。我决定使用ruamel.yaml python 库。

阅读cmets效果很好,但是我还没有找到如何区分行尾的cmets和全行的cmets:

  - book # This is an end-of-the-line comment
    # This is a full line comment

有谁知道我如何做到这一点?

代码示例,读取所有stage的stage级cmets,不包含stage的子实体的cmets:

from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap, CommentedSeq

file_name = 'test.yaml'

yaml=YAML()
with open(file_name) as doc:
    data = yaml.load(doc)

i = 0
for item in data['stages']:
    i+=1
    print("*** stage", i, item['stage'])
    if isinstance(item, CommentedMap):
        comment_token = item.ca.items.get('stage')
        stage_help = {"stage_id": i}
        current_key = "Comment"
        if comment_token:
            for tab in comment_token:
                if tab:
                    vals = tab.value.split('\n')

                    for line in vals:
                        if line[1:1] == "#":
                            line = line[1:]
                        else:
                            line = line.strip()[1:].strip()
                        if len(line) == 0:
                            continue
                        if line[0:1] == "@":
                            current_key = line[1:line.index(':')]
                            content = line[line.index(':')+1:].strip()
                        else:
                            content = line
                        if current_key not in stage_help:
                            stage_help[current_key] = f"{content}"
                        else:
                            stage_help[current_key] = f"{stage_help[current_key]}\n{content}"

                    print(stage_help)

YAML:

stages:
  - stage: TestA
    # @Comment: I write what it does
    # @Link: https://documentation
  - stage: TestB # My favorite stage!
    # @Comment: We can also write
    # Multiline docs
    # @Link: https://doc2
    displayName: Test B # The displayName is shown in the pipeline's GUI

运行它给了我:

*** stage 1 TestA
{'stage_id': 1, 'Comment': 'I write what it does', 'Link': 'https://documentation'}
*** stage 2 TestB
{'stage_id': 2, 'Comment': 'My favorite stage!\nWe can also write\nMultiline docs', 'Link': 'https://doc2'}

【问题讨论】:

    标签: python-3.x azure-devops yaml ruamel.yaml


    【解决方案1】:

    首先,indicates那个ruamel.yaml包:

    0.17 系列还将看到 cmets 连接方式的变化 往返。这将导致.ca 数据向后不兼容 对于处理 cmets 的文档化方法,它甚至可能是必要的。

    所以您当然应该在代码中测试已安装的 ruamel.yaml 的版本。

    在 ruamel.yaml

    import sys
    import ruamel.yaml
    
    assert ruamel.yaml.version_info < (0, 17)
    
    yaml_str = """\
    stages:
      - stage: TestA
        # @Comment: I write what it does
        # @Link: https://documentation
      - stage: TestB # My favorite stage!
        # @Comment: We can also write
        # Multiline docs
        # @Link: https://doc2
        displayName: Test B # The displayName is shown in the pipeline's GUI
    """
    
    def comment_splitter(comment_list):
         """ expects the list that is a comment attached to key/index as argument
         returns a tuple containing;
         - the eol comment for the key/index (empty string if not available)
         - a list of, non-empty, full comments lines following the key/index
         """
         token = comment_list[2]
         # print(token)
         eol, rest = token.value.split('\n', 1)
         return eol.strip(), [y for y in [x.strip() for x in rest.split('\n')] if y]
    
    yaml = ruamel.yaml.YAML()
    data = yaml.load(yaml_str)
    print(comment_splitter(data['stages'][0].ca.items.get('stage')))
    print(comment_splitter(data['stages'][1].ca.items.get('stage')))
    

    给出:

    ('', ['# @Comment: I write what it does', '# @Link: https://documentation'])
    ('# My favorite stage!', ['# @Comment: We can also write', '# Multiline docs', '# @Link: https://doc2'])
    

    因为您立即在程序中拆分 CommentToken(如果可用)的值并跳过 如果该行的长度为零,您可能错过了这一点。如果您取消注释 # print(token),这应该会变得清晰。


    我建议不要以这种方式滥用 YAML cmets,而是要求考虑 生成 azure 管道的文件 期望通过使用小型 python 程序从更完整的 YAML 文件中提取信息。我就是这样克服的 docker-compose.yaml 文件格式的不足。

    无论您是签入生成的(更简单的)YAML,还是始终生成 它在运行中取决于管道 cq 的功能。你如何调用它。

    我可能会从以下内容开始,然后处理:

    stages:
      - @Stage
        name: TestA
        comment: I write what it does
        link: https://documentation
      - @Stage
        name: TestB # My favorite stage!
        Comment: |
            We can also write
            Multiline docs
        link: https://doc2
        displayName: Test B # The displayName is shown in the pipeline's GUI
    

    这样您就不必处理在未来版本的 ruamel.yaml 中附加 cmets 的方式的任何更改。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2013-10-05
      • 2022-01-14
      • 1970-01-01
      • 2018-08-20
      • 2017-04-03
      相关资源
      最近更新 更多