2017-02-24 2 views
1

Ich versuche, verankerte Daten durch einen Konstruktor in einem Alias ​​verwendet, aber der Alias ​​möchte die Pre-Konstruktor Daten verwenden.mit einem Pyyaml ​​oder Ruamel.Yaml-Konstruktor als Achor für einen Alias ​​

Ich habe Inspiration von Anthon Is there a way to construct an object using PyYAML construct_mapping after all nodes complete loading? genommen, aber immer noch keine Freude gefunden.

Nachfolgend finden Sie einige Beispielcode:

class L2D(dict): 
    def __repr__(self): 
     return('L2D({})'.format(dict.__repr__(self))) 

def l2d_constructor(loader, node): 
    print("constructing") 
    instance = L2D.__new__(L2D) 
    yield instance 
    state = loader.construct_sequence(node, deep=True) 
    instance.__init__(state) 

yaml.add_constructor(u'!l2d', l2d_constructor) 

print(yaml.load(''' 
a: !l2d 
    - [e, f] 
    - [g, h] 
''')) 

print("============") 

print(yaml.load(''' 
a: &other !l2d 
    - [e, f] 
    - [g, h] 
b: 
    <<: *other 
    a: b 
    c: d 
''')) 

Die ersten Arbeiten Last aber während ich die zweite Lasten Ausgang

constructing 
{'a': L2D({'g': 'h', 'e': 'f'}), 'b': {'a': 'b', 'g': 'h', 'e': 'f', 'c': 'd'}} 

statt I

constructing 
Traceback (most recent call last): 
    File "test2.py", line 41, in <module> 
    ''')) 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/main.py", line 86, in load 
    return loader.get_single_data() 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 56, in get_single_data 
    return self.construct_document(node) 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 65, in construct_document 
    for dummy in generator: 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 494, in construct_yaml_map 
    value = self.construct_mapping(node) 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 265, in construct_mapping 
    self.flatten_mapping(node) 
    File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 240, in flatten_mapping 
    % subnode.id, subnode.start_mark) 
ruamel.yaml.constructor.ConstructorError: while constructing a mapping 
    in "<unicode string>", line 8, column 3: 
     <<: *other 
    ^(line: 8) 
expected a mapping for merging, but found sequence 
    in "<unicode string>", line 5, column 5: 
     - [e, f] 
     ^(line: 5) 

bekommen zu erwarten wäre Der Druck constructing schlägt vor, dass der Konstruktor seine Arbeit getan hat, aber mein Verdacht ist, dass der Alias es versucht, die Daten aus dem unveränderten Yaml-Baum zu erhalten, anstatt die resultierenden Daten aus dem Konstruktor.

Gibt es eine Möglichkeit, wie ich das schaffen kann?

Antwort

0

Um die Zusammenführungsfunktion von YAML zu verwenden, muss Ihr verankerter "Typ" eine Zuordnung sein (Python dict) und die Schlüssel/Wert-Paare dieser Zuordnung werden in die andere Zuordnung an dem Punkt eingefügt, an dem Sie Folgendes tun:

<<: *other 

Ihr verankerter Typ ist eine Sequenz, die bei Verwendung der Zusammenführungsfunktion nicht zulässig ist.

Sie sollten die merge documentation überprüfen, wo Sie sehen können, dass der verankerte Typ immer Zuordnungen sind.

+0

Ich verstehe, wie die Mapping-Funktion funktioniert, das '! L2d'-Tag und' l2d_constructor'-Funktion ändert die 'a'-Sequenz in ein dict, wie Sie im resultierenden Python-Objekt sehen können. Meine Hoffnung war, dass die Mutation der Konstruktorfunktion von Sequenz zu Mapping bedeuten würde, dass ich den 'a'-Wert wie ein Mapping im yaml behandeln könnte, aber ich denke immer mehr, dass es zu diesem Zeitpunkt im Parsing zu spät ist <'wird vor'! l2d' und der entsprechenden Konstruktorfunktion verarbeitet. – tommyvn

+0

Ja, das Übersetzen wird vom Parser ausgeführt, es dauert nicht die Sequenz, was das Tag daraus gemacht hat. Eine Sache, die Sie tun können, ist die '' '' in etwas anderes, das eindeutig ist (z. B. '>>') und markieren Sie die Zuordnung, um ein Diktat wie Objekt zu laden, das den Wert für '>>' interpretiert. Oder Sie können die Zusammenführungsfunktion in 'constructor.py' ersetzen, um das Richtige zu tun. – Anthon