Changes between Version 2 and Version 3 of PyYAML


Ignore:
Timestamp:
04/10/06 21:22:36 (9 years ago)
Author:
xi
Comment:

Reflect recent changes.

Legend:

Unmodified
Added
Removed
Modified
  • PyYAML

    v2 v3  
    3333Note that PyYAML3000 is still young and may have some bugs. In particular, 
    3434there are two major drawbacks: 
    35  * There in no '''YAML emitter''' yet. 
     35 * ~~There in no '''YAML emitter''' yet.~~ 
    3636 * PyYAML3000 is written in Python and is slow comparing to C based parsers. 
    3737 
     
    6161Now convert it to a native Python object: 
    6262{{{ 
    63 >>> yaml.load_document(data) 
     63>>> yaml.load(data) 
    6464['YAML', 'is', 'fun!'] 
     65}}} 
     66 
     67Conversely, you may convert a Python object into a YAML document: 
     68{{{ 
     69>>> print yaml.dump(['YAML', 'is', 'fun!']) 
     70- YAML 
     71- is 
     72- fun! 
    6573}}} 
    6674 
     
    7684... - pairs: !!pairs [1: 2, 3: 4, 5: 6] 
    7785... """ 
    78 >>> for x in yaml.load_document(data): print x 
     86>>> for x in yaml.load(data): print x 
    7987None 
    8088True 
     
    8492{'primes (sort of)': set([2, 3, 5, 7, 11, 13])} 
    8593{'pairs': [(1, 2), (3, 4), (5, 6)]} 
     94>>> print yaml.dump([None, True, False, 123, 123.456, 'a string', 
     95... {'a': 'dictionary'}, ['a', 'list']]) 
     96- null 
     97- true 
     98- false 
     99- 123 
     100- 123.456 
     101- a string 
     102- a: dictionary 
     103- - a 
     104  - list 
    86105}}} 
    87106 
     
    91110'''!!value'''. 
    92111 
    93 === Defining custon tags === 
     112=== Defining custom tags === 
    94113 
    95114You may define constructors for your own application-specific tags. You may use 
     
    98117 
    99118If you use '''yaml.YAMLObject''', you need to define the class attribute '''yaml_tag''' 
    100 and the class method '''from_yaml''': 
    101 {{{ 
    102 #!python 
    103 >>> class Person(yaml.YAMLObject): 
    104 ...     yaml_tag = '!Person' 
    105 ...     @classmethod 
    106 ...     def from_yaml(cls, constructor, node): 
    107 ...         # Convert the node to a dictionary 
    108 ...         attributes = constructor.construct_mapping(node) 
    109 ...         # Convert spaces into underlines. 
    110 ...         for key in attributes: 
    111 ...             if ' ' in key: 
    112 ...                 value = attributes[key] 
    113 ...                 del attributes[key] 
    114 ...                 key = key.replace(' ', '_') 
    115 ...                 attributes[key] = value 
    116 ...         # Create an object 
    117 ...         return cls(**attributes) 
    118 ...     def __init__(self, first_name, last_name, email=None, birthday=None): 
    119 ...         self.first_name = first_name 
    120 ...         self.last_name = last_name 
    121 ...         self.email = email 
    122 ...         self.birthday = birthday 
    123 }}} 
    124  
    125 If you don't want to use metaclass magic, you may define the constructor 
    126 as a function and register it: 
    127 {{{ 
    128 #!python 
    129 >>> def construct_person(constructor, node): 
    130 ...     # ... 
    131 >>> yaml.Constructor.add_constructor('!Person', construct_person) 
    132 }}} 
    133  
    134 After that, PyYAML 3000 will understand the '''!Person''' tag and convert it into the '''Person''' object: 
    135 {{{ 
    136 #!python 
    137 >>> data = """ 
    138 ... --- !Person 
     119and the class methods '''from_yaml''', '''to_yaml''': 
     120{{{ 
     121#!python 
     122class Person(yaml.YAMLObject): 
     123    yaml_tag = '!Person' 
     124    @classmethod 
     125    def from_yaml(cls, constructor, node): 
     126        # Convert the node to a dictionary 
     127        attributes = constructor.construct_mapping(node) 
     128        # Convert spaces into underlines 
     129        for key in attributes: 
     130            if ' ' in key: 
     131                value = attributes[key] 
     132                del attributes[key] 
     133                key = key.replace(' ', '_') 
     134                attributes[key] = value 
     135        # Create an object 
     136        return cls(**attributes) 
     137    @classmethod 
     138    def to_yaml(cls, representer, person): 
     139        # Create mapping node 
     140        mapping = {} 
     141        for attribute in person.__dict__: 
     142            key = attribute.replace('_', ' ') 
     143            value = getattr(person, attribute) 
     144            if value is not None: 
     145                mapping[key] = getattr(person, attribute) 
     146        return representer.represent_mapping(cls.yaml_tag, mapping) 
     147    def __init__(self, first_name=None, last_name=None, email=None, birthday=None): 
     148        self.first_name = first_name 
     149        self.last_name = last_name 
     150        self.email = email 
     151        self.birthday = birthday 
     152}}} 
     153 
     154After that, PyYAML 3000 will convert '''!Person'''-tagged nodes to '''Person''' objects and vice versa. 
     155{{{ 
     156#!python 
     157>>> p = yaml.load(""" 
     158... !Person 
    139159... first name: Kirill 
    140160... last name: Simonov 
    141161... email: xi(at)resolvent.net 
    142 ... """ 
    143 >>> p = yaml.load_document(data) 
    144 >>> p 
    145 <__main__.Person object at 0xb7de408c> 
     162... """) 
     163>>> print p 
     164<__main__.Person object at 0xb7b5e44c> 
    146165>>> p.first_name, p.last_name, p.email, p.birthday 
    147166('Kirill', 'Simonov', 'xi(at)resolvent.net', None) 
     167>>> print yaml.dump(p) 
     168!Person 
     169first name: Kirill 
     170last name: Simonov 
     171email: xi(at)resolvent.net 
     172}}} 
     173 
     174If you don't want to use metaclass magic, you may define the constructor 
     175and representer as functions and register them: 
     176{{{ 
     177#!python 
     178def construct_person(constructor, node): 
     179    # ... 
     180def represent_person(representer, person): 
     181    # ... 
     182yaml.Constructor.add_constructor('!Person', construct_person) 
     183yaml.Representer.add_representer(Person, represent_person) 
    148184}}} 
    149185 
    150186=== Loading all documents === 
    151187 
    152 If an input stream contains several documents, you may load all of them using the '''yaml.load''' function. 
     188If an input stream contains several documents, you may load all of them using the '''yaml.load_all''' function. 
    153189{{{ 
    154190#!python 
     
    161197...   last: document 
    162198... """ 
    163 >>> for document in yaml.load(data): print document 
     199>>> for document in yaml.load_all(data): print document 
    164200This is the first document 
    165201None 
     
    167203}}} 
    168204 
     205You may also dump several documents into the same stream using the '''yaml.dump_all''' function. 
     206{{{ 
     207#!python 
     208>>> print yaml.dump_all(["The first document", None, ["The", "last", "document"]]) 
     209The first document 
     210--- null 
     211--- 
     212- The 
     213- last 
     214- document 
     215}}} 
     216 
    169217There are more features, check the source to find out. 
    170218 
    171219== Low-level API == 
    172220 
    173 PyYAML 3000 provides low-level event-based and easy-to-use parser API. 
    174  
    175 Example: 
     221PyYAML 3000 provides low-level event-based and easy-to-use parser and emitter API. 
     222 
     223Parser example: 
    176224{{{ 
    177225#!python 
     
    192240>>> for event in yaml.parse(data): print event 
    193241 
     242StreamStartEvent() 
     243 
     244DocumentStartEvent() 
    194245ScalarEvent(anchor=None, tag=u'!tag', value=u'scalar') 
    195  
    196 SequenceEvent(anchor=None, tag=u'!') 
     246DocumentEndEvent() 
     247 
     248DocumentStartEvent() 
     249SequenceStartEvent(anchor=None, tag=None) 
    197250ScalarEvent(anchor=u'anchor', tag=None, value=u'item') 
    198251ScalarEvent(anchor=None, tag=None, value=u'another item') 
    199252AliasEvent(anchor=u'anchor') 
    200 CollectionEndEvent() 
    201  
    202 MappingEvent(anchor=None, tag=u'!') 
     253SequenceEndEvent() 
     254DocumentEndEvent() 
     255 
     256DocumentStartEvent() 
     257MappingStartEvent(anchor=None, tag=None) 
    203258ScalarEvent(anchor=None, tag=None, value=u'key') 
    204259ScalarEvent(anchor=None, tag=None, value=u'value') 
    205 SequenceEvent(anchor=None, tag=u'!') 
     260SequenceStartEvent(anchor=None, tag=None) 
    206261ScalarEvent(anchor=None, tag=None, value=u'complex') 
    207262ScalarEvent(anchor=None, tag=None, value=u'key') 
    208 CollectionEndEvent() 
    209 SequenceEvent(anchor=None, tag=u'!') 
     263SequenceEndEvent() 
     264SequenceStartEvent(anchor=None, tag=None) 
    210265ScalarEvent(anchor=None, tag=None, value=u'complex') 
    211266ScalarEvent(anchor=None, tag=None, value=u'value') 
    212 CollectionEndEvent() 
    213 CollectionEndEvent() 
     267SequenceEndEvent() 
     268MappingEndEvent() 
     269DocumentEndEvent() 
    214270 
    215271StreamEndEvent() 
     272 
     273>>> events = [ 
     274... yaml.StreamStartEvent(encoding='utf-8'), 
     275... yaml.DocumentStartEvent(explicit=True), 
     276... yaml.MappingStartEvent(anchor=None, tag=None), 
     277... yaml.ScalarEvent(anchor=None, tag=None, value=u'flow sequence', implicit=True), 
     278... yaml.SequenceStartEvent(anchor=None, tag=None, flow_style=True), 
     279... yaml.ScalarEvent(anchor=None, tag=None, value=u'123', implicit=True), 
     280... yaml.ScalarEvent(anchor=None, tag=None, value=u'456', implicit=True), 
     281... yaml.SequenceEndEvent(), 
     282... yaml.ScalarEvent(anchor=None, tag=None, value=u'block scalar', implicit=True), 
     283... yaml.ScalarEvent(anchor=None, tag=None, value=u'YAML\nis\nfun!\n', style='|'), 
     284... yaml.MappingEndEvent(), 
     285... yaml.DocumentEndEvent(explicit=True), 
     286... yaml.StreamEndEvent(), 
     287... ] 
     288 
     289>>> print yaml.emit(events) 
     290--- 
     291flow sequence: [123, 456] 
     292block scalar: | 
     293  YAML 
     294  is 
     295  fun! 
     296... 
    216297}}} 
    217298 
    218299== To Do == 
    219300 
    220 For the initial release we need website and documentation. 
     301For the initial release we need ~~website~~ and documentation. 
    221302 
    222303Long-term goals: 
    223  * fix tabs, indentation for flow collections, indentation for scalars (min=1?), 'y' is '''!!bool''', 
    224  * emitter 
     304 * fix tabs, i~~ndentation for flow collections, indentation for scalars (min=1?), 'y' is '''!!bool'''~~, 
     305 * ~~emitter~~ 
    225306 * libyaml3000 
    226307 
     
    233314   are considered as parts of the content. It can be fixed, but it's not 
    234315   really important now. 
    235  * Empty plain scalars are not allowed if alias or tag is specified. This 
     316 * ~~Empty plain scalars are not allowed if alias or tag is specified.~~ This 
    236317   is done to prevent anomalities like '''[ !tag, value]''', which can be 
    237318   interpreted both as '''[ !<!tag,> value ]''' and '''[ !<!tag> "", "value" ]'''.