2016-10-01 5 views
1

Ruamel Python 라이브러리를 사용하여 사람이 편집 한 YAML 파일을 프로그래밍 방식으로 편집하고 있습니다.Ruamel.yaml의 키 앞에 주석을 삽입하십시오.

구조화 된 데이터에 주석을 삽입하는 방법을 이해하는 데 어려움을 겪고 있습니다.

나는 일부 데이터를 가지고 :

a: 
    b: banana 
    c: apple 
    d: orange 

내가 코멘트와 새 키 추가하고 싶습니다 :

a: 
    b: banana 
    c: apple 
    d: orange 
    # This is my comment 
    e: pear 

그것이 ruamel.yaml를 사용하여이 작업을 수행 할 수 있으며, 만약 그렇다면, 어떻게?

import sys 
import ruamel.yaml 

with open('your_input.yaml') as fp: 
    data = ruamel.yaml.round_trip_load(yaml_str) 
ruamel.yaml.round_trip_dump(data, sys.stdout) 

가 인쇄 된 출력이 입력과 일치합니다, 그래서 어떻게 든 주석 보존, 구조의 data 계층 구조에 삽입 : 당신은 왕복을 수행하여 확인할 수

답변

2

예 즉, 수 덤핑 할 때 작성되었습니다.

ruamel.yaml에서 의견은 당신이 print(type(data['a']) 확인 lists 또는 dict들에 대한 래퍼 클래스에 연결되어 : 그것은 (ruamel.yaml.comment.py에서)를 CommentedMap이다. 당신이 재산 ca를 통해 액세스 할 수있는 속성 _yaml_commenta 중단의 값에 대한 코멘트 정보 :

cm = data['a'] 
print(cm.ca) 

을 제공합니다

items={'e': [None, [CommentToken(value='# This is my comment\n')], None, None]}) 

이것은 코멘트가 키 e와 관련된 보여줍니다 의견을 따르고 있습니다. 불행히도 CommentToken은 표현 된 것처럼 (즉, CommentToken(value='# This is my comment\n')) 호출하여 만들 수 없으며 최소한 시작 번호 Mark이 필요하므로 좀 더 많은 작업이 필요합니다.

다음 ¹ 가지고 올 수 CommentedBase하지만 CommentedMap 및 기본 클래스에보고하여 이러한 의견을 생성 할 "도우미"루틴이 없습니다 : CommentedMap

import sys 
import ruamel.yaml 

if not hasattr(ruamel.yaml.comments.CommentedMap, "yaml_set_comment_before_key"): 
    def my_yaml_set_comment_before_key(self, key, comment, column=None, 
             clear=False): 
     """ 
     append comment to list of comment lines before key, '# ' is inserted 
      before the comment 
     column: determines indentation, if not specified take indentation from 
       previous comment, otherwise defaults to 0 
     clear: if True removes any existing comments instead of appending 
     """ 
     key_comment = self.ca.items.setdefault(key, [None, [], None, None]) 
     if clear: 
      key_comment[1] = [] 
     comment_list = key_comment[1] 
     if comment: 
      comment_start = '# ' 
      if comment[-1] == '\n': 
       comment = comment[:-1] # strip final newline if there 
     else: 
      comment_start = '#' 
     if column is None: 
      if comment_list: 
       # if there already are other comments get the column from them 
       column = comment_list[-1].start_mark.column 
      else: 
       column = 0 
     start_mark = ruamel.yaml.error.Mark(None, None, None, column, None, None) 
     comment_list.append(ruamel.yaml.tokens.CommentToken(
      comment_start + comment + '\n', start_mark, None)) 
     return self 

    ruamel.yaml.comments.CommentedMap.yaml_set_comment_before_key = \ 
     my_yaml_set_comment_before_key 

이 방법으로 확장하면 다음 수행 할 수 있습니다

yaml_str = """\ 
a: 
    b: banana 
    c: apple 
    d: orange 
    e: pear 
""" 

data = ruamel.yaml.round_trip_load(yaml_str) 
cm = data['a'] 

cm.yaml_set_comment_before_key('e', "This is Alex' comment", column=2) 
cm.yaml_set_comment_before_key('e', 'and this mine') 
ruamel.yaml.round_trip_dump(data, sys.stdout) 

는 얻을 :

a: 
    b: banana 
    c: apple 
    d: orange 
    # This is Alex' comment 
    # and this mine one 
    e: pear 
,

주석을 읽지 않는 한 열이 e (데이터 구조 작성시 결정됨)으로 정렬되도록 열을 쿼리 할 방법이 없습니다. 특수 값 (-1?)을 저장하고 출력 중에 이것을 확인하려고 할 수 있지만 스트리밍하는 동안 컨텍스트는 거의 없습니다.당신은 물론 중첩 수준 (1)에 열을 설정/확인하고 들여 쓰기 (당신이 round_trip_dump에주는 하나, 2 기본값)에 의해

코멘트 시설 원형 -에 보존 의미가 있다고 곱할 수 트리핑이 필요하지 않으며 처음에는 수정이나 새 인터페이스를 삽입하지 않으므로 인터페이스가 안정적으로 보장되지 않습니다. 이를 염두에두고 yaml_set_comment_before_key() 주위에 단일 루틴이나 일련의 루틴을 만들어 변경하면 인터페이스가 변경된 경우 업데이트 할 단일 모듈 만 있습니다 (주석을 첨부 할 수있는 기능은 수행되지 않습니다. 멀리, 그렇게하는 방법은 그러나


은 어쩌면 당신을 을 ¹,하지만 난 ruamel.yaml의 저자 오전부터, 나는 underdocumented 코드 내 방법을 찾을 수 있어야합니다) 변경 될 수 있습니다.

+1

대단히 감사합니다. @Anthon. 그러나, 당신은 key_comment를 시작하는 라인에 디버깅 라인을 남겨 두었습니다. 여기서 ''e '는'key '여야합니다. 또한이 메서드는 빈 주석 줄을 원할 경우 줄 끝에 공백을 추가해야합니다. 그래서 나는 사용자가 #의 바로 뒤에 공백을 넣을 필요가 있도록 그것을 바 꾸기를 원했다. –

+0

디버깅은 물론 기능을 먼저 얻은 다음 메서드로 변환하여 on value-> 매개 변수 변환을 잊어 버렸습니다. 그것을 잡아 주셔서 감사합니다. 또한 빈 문자열 (예외로 이어질 수 있음)이 아닌 주석을 테스트하도록 갱신되었지만 개행하기 전에 공백을받지 못했습니다 (즉,'#'다음에 바로). 그것을 잡아 주셔서 감사합니다. – Anthon