2016-01-05 18 views
5

Używamy PyYAML do przygotowywania plików konfiguracyjnych dla różnych środowisk. Ale nasze bloki YAML tracą integralność.Czy można zachować strukturę bloków YAML podczas wysypywania analizowanego dokumentu?

Daj input.yml ...

pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 

... realizacji tego programu przy użyciu python3 ...

import yaml 

with open('input.yml', mode='r') as f: 
    parsed = yaml.safe_load(f) 

with open('output.yml', mode='w') as f: 
    yaml.dump(parsed, f) 

... produkuje ten output.yml ...

pubkey: '-----BEGIN PUBLIC KEY----- 

    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 

    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 

    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 

    EsUgJHXcpw7OPxRrCQIDAQAB 

    -----END PUBLIC KEY----- 

    ' 

Czy możliwe jest zachowanie struktury mojego bloku za pomocą PyYAML?

Odpowiedz

5

Tak to jest możliwe z pyyaml, ale trzeba dostarczyć własne ulepszone wersje przynajmniej skanera Parser i konstruktor, które są wykorzystywane przez safe_load, Emiter, serializer i Representer wykorzystywane przez wysypisko, oraz zapewnienie wyspecjalizowana klasa podobna do łańcucha, przechowująca informacje o oryginalnym formatowaniu.

Jest to część tego, co zostało dodane do ruamel.yaml (zrzeczenie: ja jestem autorem tego pakietu), ponieważ pochodzi od PyYAML i nadal utrzymuje podobną konfigurację. Korzystanie ruamel.yaml:

import ruamel.yaml as yaml 

yaml_str = """\ 
pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 
""" 

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader) 
print(yaml.dump(data, Dumper=yaml.RoundTripDumper, indent=4)) 

daje:

pubkey: | 
    -----BEGIN PUBLIC KEY----- 
    MIGfMA0GCSq7OPxRrQEBAQUAA4GNADCBiQKBgQCvRVUKp6pr4qBEnE9lviuyfiNq 
    QtG/OCyBDXL4Bh3FmUzfNI+Z4Bh3FmUx+z2n0FCv/4BpgHTDl8D95NPopWVo1RH2 
    UfhyMd6dQ/x9T5m+y38JMzmSVAk+Fqu8ya18+yQVOEyEIx3Gxpsgegow33gcxfjK 
    EsUgJHXcpw7OPxRrCQIDAQAB 
    -----END PUBLIC KEY----- 

przynajmniej w Pythonie 2.7 i 3.5.

indent=4 jest konieczna, ponieważ RoundTripDumper domyślnie dwóch miejscach wcięcia, przy myślnik plik nie jest zachowana (nie robić ułatwia ponowne wcięcia plik YAML).

Jeśli nie możesz przełączyć na ruamel.yaml, powinieneś być w stanie użyć jego źródła, aby wyodrębnić wszystkie potrzebne zmiany, ale jeśli możesz, możesz również użyć innych funkcji, takich jak komentowanie i zachowanie nazwy klucza scalającego.

+0

Dobra robota. Przeglądałem źródło pyyaml, próbując dowiedzieć się, gdzie dodawana jest dodatkowa nowa linia, więc mam nadzieję, że ją podklasuję, ale nie miałem szczęścia, zanim poszłam spać. – MattDMo

+0

@MattDMo Dodatkowa linia w "normalnej" wywrotce polega na tym, że ciąg zawiera znaki nowej linii. Istnieje wiele sposobów przedstawiania ciągów znaków specjalnych i zaznaczeń PyYAML. Wybór jest w 'emitter.choose_scaler_style()' na podstawie analizy skalarnej, ale jak to naprawdę działa naprawdę trudno jest prześledzić. Omijam to wszystko, tworząc specjalny typ podczas czytania i ustawiając wyraźnie styl węzła podczas zrzucania. – Anthon

+0

Właśnie zainstalowałem 'ruamel.yaml' i bawiłem się nim trochę: bardzo ładnie. Dwa krótkie pytania (poza tematem): skąd się wzięła ta nazwa i czy planujesz wesprzeć YAML 1.2? Pytam, ponieważ mam kilka plików, z którymi chciałbym pracować, które mają jako pierwszy wiersz '% YAML 1.2'. Nie mam pojęcia, jakie są różnice między specyfikacjami (nawet po przeczytaniu pierwszej części specyfikacji 1.2), a nawet czy pliki wykorzystują nowe funkcje w wersji 1.2 - są to głównie klucze tekstowe z wartościami łańcuchowymi lub boolowskimi (bez obiektów). Oto jeden na github: http://bit.ly/1JXLVbf – MattDMo