2017-05-03 1 views
2

YAML 파일을 읽고 처리 한 후 나중에 덤프하는 YAML 필터를 만들고 싶습니다.PyYAML : yaml 파일로드 및 덤프 (! CustomTag)

이 (상자 밖으로 잘 이미 작동) 어떤 별칭을 해결해야합니다 :

>>> yaml.dump(yaml.load(""" 
Foo: &bar 
    name: bar 
Foo2: 
    <<: *bar 
""")) 

'Foo: {name: bar}\nFoo2: {name: bar}\n' 

을 그러나 그것은 또한 처럼!CustomTag: foo 표현의 모든 종류를 유지해야한다 :

>>> yaml.dump(yaml.load("Name: !Foo bar ")) 
yaml.constructor.ConstructorError: could not determine a constructor for the tag '!Foo' in "<unicode string>", line 1, column 7: 
Name: !Foo bar 
    ^

나는 pyYAML Errors on "!" in a string을 읽었으며 이것은 필자가 필요로하는 것과 가깝다. UTS 문자열 인용 로 사용자 정의 태그는, 따라서 그것은 태그는 더 이상되지 않습니다 :

>>> def default_ctor(loader, tag_suffix, node): ... return tag_suffix + ' ' + node.value >>> yaml.add_multi_constructor('', default_ctor) >>> yaml.dump(yaml.load("Name: !Foo bar "), default_flow_style=False) "Name: '!Foo bar'\n" 

나는 더없는,하지만 거기 추측? 태그가 포함 된 파일을로드하고 나중에 덤프하려면 어떻게합니까?

+0

'yaml.load()'를 사용하면 안전하지 않습니다. YAML 파일을 제어 할 수있는 사용자는 임의의 코드를 실행할 수 있으며 PyYAML은 위험에 대해 경고하지 않습니다. – Anthon

답변

3

default_ctor()은 문자열 (태그와 스칼라의 연결 일뿐입니다)을 반환하기 때문에 덤프되는 내용입니다. 그리고 태그가 !으로 시작하기 때문에 문자열을 스칼라에 덤핑하면 따옴표가 붙습니다.

당신은 일반적으로 그 유형 (즉 루틴을 덤핑)는 특수한 유형의 사람들 (그리고 "정상적인"파이썬 문자열)를 저장하고 representer를 제공하는 데 필요한 태그와 값을 유지하려면 :

import sys 
import yaml 

yaml_str = """\ 
Name: !Foo bar 
Alt: !Bar foo 
""" 


class GenericScalar: 
    def __init__(self, value, tag, style=None): 
     self._value = value 
     self._tag = tag 
     self._style = style 

    @staticmethod 
    def to_yaml(dumper, data): 
     # data is a GenericScalar 
     return dumper.represent_scalar(data._tag, data._value, style=data._style) 


def default_constructor(loader, tag_suffix, node): 
    if isinstance(node, yaml.ScalarNode): 
     return GenericScalar(node.value, tag_suffix, style=node.style) 
    else: 
     raise NotImplementedError('Node: ' + str(type(node))) 


yaml.add_multi_constructor('', default_constructor, Loader=yaml.SafeLoader) 

yaml.add_representer(GenericScalar, GenericScalar.to_yaml, Dumper=yaml.SafeDumper) 

data = yaml.safe_load(yaml_str) 
yaml.safe_dump(data, sys.stdout, default_flow_style=False, allow_unicode=True) 

이 제공 :

Alt: !Bar 'foo' 
Name: !Foo 'bar' 

주 :

  • 이 PyYAML의을 사용하는 것이 안전하다. 을 사용하지 마십시오. (코드에서와 같이) 필요하지 않습니다. 더 나쁜 것은 PyYAML로부터 위험이 있다는 의견이 없다는 것입니다.
  • PyYAML은 내가하는 것처럼 노드 스타일을 유지하더라도 (또는 빈 문자열을 강제로), 따옴표가있는 태그가있는 모든 스칼라를 덤프합니다. 그런 일이 일어나지 않도록 노드 직렬화를 깊이 파헤쳐 야합니다. 나는이 문제를 해결하기 위해 ruamel.yaml 패키지에서 작업하고있다. 따옴표는 매우 자주 필요하지 않다.
  • 앵커와 별칭이 해석되지 않습니다. PyYAML이로드 시간에 merge key을 확장 할 수있을 정도로 똑똑하지 않다는 것입니다. YAML에 정상적인 자체 참조가있는 경우 덤프 된 YAML에 앵커와 별칭이 생깁니다.
  • 위의 설명은 태그 다음의 노드가 스칼라 (즉, 매핑 또는 시퀀스) 이외의 것이라면 오류가 발생합니다. 일반적으로로드/덤프하는 것도 가능합니다. 일부 유형을 추가하고 의 일부를 elif isinstance(node, yaml.MappingNode)elif isinstance(node, yaml.SequenceNode)으로 확장하면됩니다. 나는 그것들이 다른 타입을 만들도록 만들 것이고 (만약 당신이 dict resp list처럼 행동하는), 당신이 그 경로를 가면, 그것들을 생성하는 것이 두 단계 과정에서 일어날 필요가 있다는 것을 알아야한다. (yield 생성 된 객체. 하위 노드 값 및 채우기 개체), 그렇지 않으면 자체 참조 구조 (예 : 노드 내에서 별칭)를 사용할 수 없습니다.
  • PyYAML 당신은 콜론으로 끝나는 태그 !CustomTag:을 가질 수
  • 매핑에서 요소의 순서를 보존하지 않습니다,하지만이처럼 많이 보이는 나는 !CustomTag: foo을 읽기 쉬운 그것 때문에 인간의 못 했습 블록 스타일 매핑의 키 - 값 쌍
관련 문제