Changeset 136

Show
Ignore:
Timestamp:
04/15/06 19:54:52 (6 years ago)
Author:
xi
Message:

Major refactoring.

Location:
pyyaml/trunk
Files:
2 added
2 removed
27 modified

Legend:

Unmodified
Added
Removed
  • pyyaml/trunk/examples/yaml-hl/yaml_hl.py

    r119 r136  
    22 
    33import yaml, codecs, sys, optparse 
     4 
     5 
     6 
     7yaml.add_resolver(u'!Config', []) 
     8yaml.add_resolver(u'!TokensConfig', [u'tokens']) 
     9yaml.add_resolver(u'!EventsConfig', [u'events']) 
     10yaml.add_resolver(u'!StartEndConfig', [u'tokens', None]) 
     11yaml.add_resolver(u'!StartEndConfig', [u'events', None]) 
    412 
    513class YAMLHighlight: 
  • pyyaml/trunk/lib/yaml/__init__.py

    r135 r136  
    66from parser import * 
    77from composer import * 
    8 from resolver import * 
    98from constructor import * 
    109 
     
    1918from nodes import * 
    2019 
    21 from yaml_object import * 
    22  
    23 def parse(data, Reader=Reader, Scanner=Scanner, Parser=Parser): 
    24     reader = Reader(data) 
    25     scanner = Scanner(reader) 
    26     parser = Parser(scanner) 
    27     return parser 
    28  
    29 def load_all(data, Reader=Reader, Scanner=Scanner, Parser=Parser, 
    30         Composer=Composer, Resolver=Resolver, Constructor=Constructor): 
    31     reader = Reader(data) 
    32     scanner = Scanner(reader) 
    33     parser = Parser(scanner) 
    34     composer = Composer(parser) 
    35     resolver = Resolver(composer) 
    36     constructor = Constructor(resolver) 
    37     return constructor 
    38  
    39 def safe_load_all(data, Reader=Reader, Scanner=Scanner, Parser=Parser, 
    40         Composer=Composer, Resolver=Resolver, Constructor=SafeConstructor): 
    41     return load_all(data, Reader, Scanner, Parser, Composer, Resolver, 
    42             Constructor) 
    43  
    44 def load(data, *args, **kwds): 
    45     for document in load_all(data, *args, **kwds): 
    46         return document 
    47  
    48 def safe_load(data, *args, **kwds): 
    49     for document in safe_load_all(data, *args, **kwds): 
    50         return document 
    51  
    52 def emit(events, writer=None, Emitter=Emitter): 
    53     if writer is None: 
     20from loader import * 
     21from dumper import * 
     22 
     23def scan(stream, Loader=Loader): 
     24    """ 
     25    Scan a YAML stream and produce scanning tokens. 
     26    """ 
     27    loader = Loader(stream) 
     28    while loader.check_token(): 
     29        yield loader.get_token() 
     30 
     31def parse(stream, Loader=Loader): 
     32    """ 
     33    Parse a YAML stream and produce parsing events. 
     34    """ 
     35    loader = Loader(stream) 
     36    while loader.check_event(): 
     37        yield loader.get_event() 
     38 
     39def compose(stream, Loader=Loader): 
     40    """ 
     41    Parse the first YAML document in a stream 
     42    and produce the corresponding representation tree. 
     43    """ 
     44    loader = Loader(stream) 
     45    if loader.check_node(): 
     46        return loader.get_node() 
     47 
     48def compose_all(stream, Loader=Loader): 
     49    """ 
     50    Parse all YAML documents in a stream 
     51    and produce corresponsing representation trees. 
     52    """ 
     53    loader = Loader(stream) 
     54    while loader.check_node(): 
     55        yield loader.get_node() 
     56 
     57def load_all(stream, Loader=Loader): 
     58    """ 
     59    Parse all YAML documents in a stream 
     60    and produce corresponding Python objects. 
     61    """ 
     62    loader = Loader(stream) 
     63    while loader.check_data(): 
     64        yield loader.get_data() 
     65 
     66def load(stream, Loader=Loader): 
     67    """ 
     68    Parse the first YAML document in a stream 
     69    and produce the corresponding Python object. 
     70    """ 
     71    loader = Loader(stream) 
     72    if loader.check_data(): 
     73        return loader.get_data() 
     74 
     75def safe_load_all(stream): 
     76    """ 
     77    Parse all YAML documents in a stream 
     78    and produce corresponding Python objects. 
     79    Resolve only basic YAML tags. 
     80    """ 
     81    return load_all(stream, SafeLoader) 
     82 
     83def safe_load(stream): 
     84    """ 
     85    Parse the first YAML document in a stream 
     86    and produce the corresponding Python object. 
     87    Resolve only basic YAML tags. 
     88    """ 
     89    return load(stream, SafeLoader) 
     90 
     91def emit(events, stream=None, Dumper=Dumper, 
     92        canonical=None, indent=None, width=None, 
     93        allow_unicode=None, line_break=None): 
     94    """ 
     95    Emit YAML parsing events into a stream. 
     96    If stream is None, return the produced string instead. 
     97    """ 
     98    getvalue = None 
     99    if stream is None: 
    54100        try: 
    55101            from cStringIO import StringIO 
    56102        except ImportError: 
    57103            from StringIO import StringIO 
    58         writer = StringIO() 
    59         return_value = True 
    60     else: 
    61         return_value = False 
    62     emitter = Emitter(writer) 
     104        stream = StringIO() 
     105        getvalue = stream.getvalue 
     106    dumper = Dumper(stream, canonical=canonical, indent=indent, width=width, 
     107            allow_unicode=allow_unicode, line_break=line_break) 
    63108    for event in events: 
    64         emitter.emit(event) 
    65     if return_value: 
    66         return writer.getvalue() 
    67  
    68 def dump_all(natives, writer=None, Emitter=Emitter, 
    69         Serializer=Serializer, Representer=Representer, 
    70         encoding='utf-8', line_break=None, canonical=None, 
    71         indent=None, width=None, allow_unicode=None): 
    72     if writer is None: 
     109        dumper.emit(event) 
     110    if getvalue: 
     111        return getvalue() 
     112 
     113def serialize_all(nodes, stream=None, Dumper=Dumper, 
     114        canonical=None, indent=None, width=None, 
     115        allow_unicode=None, line_break=None, 
     116        encoding='utf-8', explicit_start=None, explicit_end=None, 
     117        version=None, tags=None): 
     118    """ 
     119    Serialize a sequence of representation trees into a YAML stream. 
     120    If stream is None, return the produced string instead. 
     121    """ 
     122    getvalue = None 
     123    if stream is None: 
    73124        try: 
    74125            from cStringIO import StringIO 
    75126        except ImportError: 
    76127            from StringIO import StringIO 
    77         writer = StringIO() 
    78         return_value = True 
    79     else: 
    80         return_value = False 
    81     emitter = Emitter(writer) 
    82     serializer = Serializer(emitter, encoding=encoding, line_break=line_break, 
    83             canonical=canonical, indent=indent, width=width, 
    84             allow_unicode=allow_unicode) 
    85     representer = Representer(serializer) 
    86     for native in natives: 
    87         representer.represent(native) 
    88     representer.close() 
    89     if return_value: 
    90         return writer.getvalue() 
    91  
    92 def safe_dump_all(natives, writer=None, Emitter=Emitter, 
    93         Serializer=Serializer, Representer=SafeRepresenter, 
    94         encoding='utf-8', line_break=None, canonical=None, 
    95         indent=None, width=None, allow_unicode=None): 
    96     return dump_all(natives, writer, Emitter, Serializer, Representer, 
    97             encoding, line_break, canonical, indent, width, allow_unicode) 
    98  
    99 def dump(native, *args, **kwds): 
    100     return dump_all([native], *args, **kwds) 
    101  
    102 def safe_dump(native, *args, **kwds): 
    103     return safe_dump_all([native], *args, **kwds) 
    104  
     128        stream = StringIO() 
     129        getvalue = stream.getvalue 
     130    dumper = Dumper(stream, canonical=canonical, indent=indent, width=width, 
     131            allow_unicode=allow_unicode, line_break=line_break, 
     132            encoding=encoding, version=version, tags=tags, 
     133            explicit_start=explicit_start, explicit_end=explicit_end) 
     134    dumper.open() 
     135    for node in nodes: 
     136        dumper.serialize(node) 
     137    dumper.close() 
     138    if getvalue: 
     139        return getvalue() 
     140 
     141def serialize(node, stream=None, Dumper=Dumper, **kwds): 
     142    """ 
     143    Serialize a representation tree into a YAML stream. 
     144    If stream is None, return the produced string instead. 
     145    """ 
     146    return serialize_all([node], stream, Dumper=Dumper, **kwds) 
     147 
     148def dump_all(documents, stream=None, Dumper=Dumper, 
     149        canonical=None, indent=None, width=None, 
     150        allow_unicode=None, line_break=None, 
     151        encoding='utf-8', explicit_start=None, explicit_end=None, 
     152        version=None, tags=None): 
     153    """ 
     154    Serialize a sequence of Python objects into a YAML stream. 
     155    If stream is None, return the produced string instead. 
     156    """ 
     157    getvalue = None 
     158    if stream is None: 
     159        try: 
     160            from cStringIO import StringIO 
     161        except ImportError: 
     162            from StringIO import StringIO 
     163        stream = StringIO() 
     164        getvalue = stream.getvalue 
     165    dumper = Dumper(stream, canonical=canonical, indent=indent, width=width, 
     166            allow_unicode=allow_unicode, line_break=line_break, 
     167            encoding=encoding, version=version, tags=tags, 
     168            explicit_start=explicit_start, explicit_end=explicit_end) 
     169    dumper.open() 
     170    for data in documents: 
     171        dumper.represent(data) 
     172    dumper.close() 
     173    if getvalue: 
     174        return getvalue() 
     175 
     176def dump(data, stream=None, Dumper=Dumper, **kwds): 
     177    """ 
     178    Serialize a Python object into a YAML stream. 
     179    If stream is None, return the produced string instead. 
     180    """ 
     181    return dump_all([data], stream, Dumper=Dumper, **kwds) 
     182 
     183def safe_dump_all(documents, stream=None, **kwds): 
     184    """ 
     185    Serialize a sequence of Python objects into a YAML stream. 
     186    Produce only basic YAML tags. 
     187    If stream is None, return the produced string instead. 
     188    """ 
     189    return dump_all(documents, stream, Dumper=SafeDumper, **kwds) 
     190 
     191def safe_dump(data, stream=None, **kwds): 
     192    """ 
     193    Serialize a Python object into a YAML stream. 
     194    Produce only basic YAML tags. 
     195    If stream is None, return the produced string instead. 
     196    """ 
     197    return dump_all([data], stream, Dumper=SafeDumper, **kwds) 
     198 
     199def add_detector(tag, regexp, first=None, Loader=Loader, Dumper=Dumper): 
     200    """ 
     201    Add an implicit scalar detector. 
     202    If an implicit scalar value matches the given regexp, 
     203    the corresponding tag is assigned to the scalar. 
     204    first is a sequence of possible initial characters or None. 
     205    """ 
     206    Loader.add_detector(tag, regexp, first) 
     207    Dumper.add_detector(tag, regexp, first) 
     208 
     209def add_resolver(tag, path, Loader=Loader): 
     210    """ 
     211    Add a path based resolver for the given tag. 
     212    A path is a list of keys that forms a path 
     213    to a node in the representation tree. 
     214    Keys can be string values, integers, or None. 
     215    """ 
     216    Loader.add_resolver(tag, path) 
     217 
     218def add_constructor(tag, constructor, Loader=Loader): 
     219    """ 
     220    Add a constructor for the given tag. 
     221    Constructor is a function that accepts a Loader instance 
     222    and a node object and produces the corresponding Python object. 
     223    """ 
     224    Loader.add_constructor(tag, constructor) 
     225 
     226def add_multi_constructor(tag_prefix, multi_constructor, Loader=Loader): 
     227    """ 
     228    Add a multi-constructor for the given tag prefix. 
     229    Multi-constructor is called for a node if its tag starts with tag_prefix. 
     230    Multi-constructor accepts a Loader instance, a tag suffix, 
     231    and a node object and produces the corresponding Python object. 
     232    """ 
     233    Loader.add_multi_constructor(tag_prefix, multi_constructor) 
     234 
     235class YAMLObjectMetaclass(type): 
     236    """ 
     237    The metaclass for YAMLObject. 
     238    """ 
     239    def __init__(cls, name, bases, kwds): 
     240        super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds) 
     241        if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None: 
     242            cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml) 
     243            cls.yaml_dumper.add_representer(cls, cls.to_yaml) 
     244 
     245class YAMLObject(object): 
     246    """ 
     247    An object that can dump itself to a YAML stream 
     248    and load itself from a YAML stream. 
     249    """ 
     250 
     251    __metaclass__ = YAMLObjectMetaclass 
     252 
     253    yaml_loader = Loader 
     254    yaml_dumper = Dumper 
     255 
     256    yaml_tag = None 
     257    yaml_flow_style = None 
     258 
     259    def from_yaml(cls, loader, node): 
     260        """ 
     261        Convert a representation node to a Python object. 
     262        """ 
     263        return loader.construct_yaml_object(node, cls) 
     264    from_yaml = classmethod(from_yaml) 
     265 
     266    def to_yaml(cls, dumper, data): 
     267        """ 
     268        Convert a Python object to a representation node. 
     269        """ 
     270        return dumper.represent_yaml_object(cls.yaml_tag, data, cls, 
     271                flow_style=cls.yaml_flow_style) 
     272    to_yaml = classmethod(to_yaml) 
     273 
  • pyyaml/trunk/lib/yaml/composer.py

    r133 r136  
    11 
    2 __all__ = ['Composer', 'ComposerError'] 
     2__all__ = ['BaseComposer', 'Composer', 'ComposerError'] 
    33 
    44from error import MarkedYAMLError 
     
    99    pass 
    1010 
    11 class Composer: 
     11class BaseComposer: 
    1212 
    13     def __init__(self, parser): 
    14         self.parser = parser 
     13    yaml_resolvers = {} 
     14 
     15    def __init__(self): 
    1516        self.all_anchors = {} 
    1617        self.complete_anchors = {} 
     18        self.resolver_tags = [] 
     19        self.resolver_paths = [] 
    1720 
    18         # Drop the STREAM-START event. 
    19         self.parser.get() 
     21    def check_node(self): 
     22        # If there are more documents available? 
     23        return not self.check_event(StreamEndEvent) 
    2024 
    21     def check(self): 
    22         # If there are more documents available? 
    23         return not self.parser.check(StreamEndEvent) 
    24  
    25     def get(self): 
     25    def get_node(self): 
    2626        # Get the root node of the next document. 
    27         if not self.parser.check(StreamEndEvent): 
     27        if not self.check_event(StreamEndEvent): 
    2828            return self.compose_document() 
    2929 
    3030    def __iter__(self): 
    3131        # Iterator protocol. 
    32         while not self.parser.check(StreamEndEvent): 
     32        while not self.check_event(StreamEndEvent): 
    3333            yield self.compose_document() 
    3434 
    3535    def compose_document(self): 
    3636 
     37        # Drop the STREAM-START event. 
     38        if self.check_event(StreamStartEvent): 
     39            self.get_event() 
     40 
    3741        # Drop the DOCUMENT-START event. 
    38         self.parser.get() 
     42        self.get_event() 
    3943 
    4044        # Compose the root node. 
    41         node = self.compose_node() 
     45        node = self.compose_node([]) 
    4246 
    4347        # Drop the DOCUMENT-END event. 
    44         self.parser.get() 
     48        self.get_event() 
    4549 
    4650        self.all_anchors = {} 
    4751        self.complete_anchors = {} 
     52        self.resolver_tags = [] 
     53        self.resolver_paths = [] 
    4854        return node 
    4955 
    50     def compose_node(self): 
    51         if self.parser.check(AliasEvent): 
    52             event = self.parser.get() 
     56    def increase_resolver_depth(self, path): 
     57        depth = len(path) 
     58        tag = None 
     59        paths = [] 
     60        if not depth: 
     61            for resolver_path in self.yaml_resolvers.keys(): 
     62                if resolver_path: 
     63                    paths.append(resolver_path) 
     64                else: 
     65                    tag = self.yaml_resolvers[resolver_path] 
     66        else: 
     67            base, index = path[-1] 
     68            if isinstance(index, ScalarNode)    \ 
     69                    and index.tag == self.DEFAULT_SCALAR_TAG: 
     70                index = index.value 
     71            elif isinstance(index, Node): 
     72                index = None 
     73            for resolver_path in self.resolver_paths[-1]: 
     74                resolver_index = resolver_path[depth-1] 
     75                if resolver_index is None or resolver_index == index: 
     76                    if len(resolver_index) > depth: 
     77                        paths.append(resolver_path) 
     78                    else: 
     79                        tag = self.yaml_resolvers[resolver_path] 
     80        self.resolver_tags.append(tag) 
     81        self.resolver_paths.append(paths) 
     82 
     83    def decrease_resolver_depth(self): 
     84        del self.resolver_tags[-1] 
     85        del self.resolver_paths[-1] 
     86 
     87    def compose_node(self, path): 
     88        if self.check_event(AliasEvent): 
     89            event = self.get_event() 
    5390            anchor = event.anchor 
    5491            if anchor not in self.all_anchors: 
     
    6299                        event.start_mark) 
    63100            return self.complete_anchors[anchor] 
    64         event = self.parser.peek() 
     101        self.increase_resolver_depth(path) 
     102        event = self.peek_event() 
    65103        anchor = event.anchor 
    66104        if anchor is not None: 
     
    70108                        "second occurence", event.start_mark) 
    71109            self.all_anchors[anchor] = event 
    72         if self.parser.check(ScalarEvent): 
    73             node = self.compose_scalar_node() 
    74         elif self.parser.check(SequenceStartEvent): 
    75             node = self.compose_sequence_node() 
    76         elif self.parser.check(MappingStartEvent): 
    77             node = self.compose_mapping_node() 
     110        if self.check_event(ScalarEvent): 
     111            node = self.compose_scalar_node(path) 
     112        elif self.check_event(SequenceStartEvent): 
     113            node = self.compose_sequence_node(path) 
     114        elif self.check_event(MappingStartEvent): 
     115            node = self.compose_mapping_node(path) 
    78116        if anchor is not None: 
    79117            self.complete_anchors[anchor] = node 
     118        self.decrease_resolver_depth() 
    80119        return node 
    81120 
    82     def compose_scalar_node(self): 
    83         event = self.parser.get() 
    84         return ScalarNode(event.tag, event.value, event.implicit, 
     121    def compose_scalar_node(self, path): 
     122        event = self.get_event() 
     123        tag = self.resolve_scalar(path, event.tag, event.implicit, event.value) 
     124        return ScalarNode(tag, event.value, 
    85125                event.start_mark, event.end_mark, style=event.style) 
    86126 
    87     def compose_sequence_node(self): 
    88         start_event = self.parser.get() 
    89         value = [] 
    90         while not self.parser.check(SequenceEndEvent): 
    91             value.append(self.compose_node()) 
    92         end_event = self.parser.get() 
    93         return SequenceNode(start_event.tag, value, 
    94                 start_event.start_mark, end_event.end_mark, 
     127    def compose_sequence_node(self, path): 
     128        start_event = self.get_event() 
     129        tag = self.resolve_sequence(path, start_event.tag) 
     130        node = SequenceNode(tag, [], 
     131                start_event.start_mark, None, 
    95132                flow_style=start_event.flow_style) 
     133        index = 0 
     134        while not self.check_event(SequenceEndEvent): 
     135            node.value.append(self.compose_node(path+[(node, index)])) 
     136            index += 1 
     137        end_event = self.get_event() 
     138        node.end_mark = end_event.end_mark 
     139        return node 
    96140 
    97     def compose_mapping_node(self): 
    98         start_event = self.parser.get() 
    99         value = {} 
    100         while not self.parser.check(MappingEndEvent): 
    101             key_event = self.parser.peek() 
    102             item_key = self.compose_node() 
    103             item_value = self.compose_node() 
    104             if item_key in value: 
     141    def compose_mapping_node(self, path): 
     142        start_event = self.get_event() 
     143        tag = self.resolve_mapping(path, start_event.tag) 
     144        node = MappingNode(tag, {}, 
     145                start_event.start_mark, None, 
     146                flow_style=start_event.flow_style) 
     147        while not self.check_event(MappingEndEvent): 
     148            key_event = self.peek_event() 
     149            item_key = self.compose_node(path+[(node, None)]) 
     150            item_value = self.compose_node(path+[(node, item_key)]) 
     151            if item_key in node.value: 
    105152                raise ComposerError("while composing a mapping", start_event.start_mark, 
    106153                        "found duplicate key", key_event.start_mark) 
    107             value[item_key] = item_value 
    108         end_event = self.parser.get() 
    109         return MappingNode(start_event.tag, value, 
    110                 start_event.start_mark, end_event.end_mark, 
    111                 flow_style=start_event.flow_style) 
     154            node.value[item_key] = item_value 
     155        end_event = self.get_event() 
     156        node.end_mark = end_event.end_mark 
     157        return node 
    112158 
     159    def resolve_scalar(self, path, tag, implicit, value): 
     160        if implicit: 
     161            tag = self.detect(value) 
     162        if tag is None and self.resolver_tags[-1]: 
     163            tag = self.resolver_tags[-1] 
     164        if tag is None or tag == u'!': 
     165            tag = self.DEFAULT_SCALAR_TAG 
     166        return tag 
     167 
     168    def resolve_sequence(self, path, tag): 
     169        if tag is None and self.resolver_tags[-1]: 
     170            tag = self.resolver_tags[-1] 
     171        if tag is None or tag == u'!': 
     172            tag = self.DEFAULT_SEQUENCE_TAG 
     173        return tag 
     174 
     175    def resolve_mapping(self, path, tag): 
     176        if tag is None and self.resolver_tags[-1]: 
     177            tag = self.resolver_tags[-1] 
     178        if tag is None or tag == u'!': 
     179            tag = self.DEFAULT_MAPPING_TAG 
     180        return tag 
     181 
     182    def add_resolver(self, tag, path): 
     183        if not 'yaml_resolvers' in cls.__dict__: 
     184            cls.yaml_resolvers = cls.yaml_resolvers.copy() 
     185        cls.yaml_resolvers[tuple(path)] = tag 
     186    add_resolver = classmethod(add_resolver) 
     187 
     188class Composer(BaseComposer): 
     189    pass 
     190 
  • pyyaml/trunk/lib/yaml/constructor.py

    r133 r136  
    55from error import * 
    66from nodes import * 
     7from composer import * 
    78 
    89try: 
     
    2223    pass 
    2324 
    24 class BaseConstructor: 
    25  
    26     def __init__(self, resolver): 
    27         self.resolver = resolver 
     25class BaseConstructor(Composer): 
     26 
     27    yaml_constructors = {} 
     28    yaml_multi_constructors = {} 
     29 
     30    def __init__(self): 
    2831        self.constructed_objects = {} 
    2932 
    30     def check(self): 
     33    def check_data(self): 
    3134        # If there are more documents available? 
    32         return self.resolver.check() 
    33  
    34     def get(self): 
     35        return self.check_node() 
     36 
     37    def get_data(self): 
    3538        # Construct and return the next document. 
    36         if self.resolver.check(): 
    37             return self.construct_document(self.resolver.get()) 
     39        if self.check_node(): 
     40            return self.construct_document(self.get_node()) 
    3841 
    3942    def __iter__(self): 
    4043        # Iterator protocol. 
    41         while self.resolver.check(): 
    42             yield self.construct_document(self.resolver.get()) 
     44        while self.check_node(): 
     45            yield self.construct_document(self.get_node()) 
    4346 
    4447    def construct_document(self, node): 
    45         native = self.construct_object(node) 
     48        data = self.construct_object(node) 
    4649        self.constructed_objects = {} 
    47         return native 
     50        return data 
    4851 
    4952    def construct_object(self, node): 
    5053        if node in self.constructed_objects: 
    5154            return self.constructed_objects[node] 
     55        constructor = None 
    5256        if node.tag in self.yaml_constructors: 
    53             native = self.yaml_constructors[node.tag](self, node) 
    54         elif None in self.yaml_constructors: 
    55             native = self.yaml_constructors[None](self, node) 
    56         elif isinstance(node, ScalarNode): 
    57             native = self.construct_scalar(node) 
    58         elif isinstance(node, SequenceNode): 
    59             native = self.construct_sequence(node) 
    60         elif isinstance(node, MappingNode): 
    61             native = self.construct_mapping(node) 
    62         self.constructed_objects[node] = native 
    63         return native 
     57            constructor = lambda node: self.yaml_constructors[node.tag](self, node) 
     58        else: 
     59            for tag_prefix in self.yaml_multi_constructors: 
     60                if node.tag.startswith(tag_prefix): 
     61                    tag_suffix = node.tag[len(tag_prefix):] 
     62                    constructor = lambda node:  \ 
     63                            self.yaml_multi_constructors[tag_prefix](self, tag_suffix, node) 
     64                break 
     65            else: 
     66                if None in self.yaml_multi_constructors: 
     67                    constructor = lambda node:  \ 
     68                            self.yaml_multi_constructors[None](self, node.tag, node) 
     69                elif None in self.yaml_constructors: 
     70                    constructor = lambda node:  \ 
     71                            self.yaml_constructors[None](self, node) 
     72                elif isinstance(node, ScalarNode): 
     73                    constructor = self.construct_scalar 
     74                elif isinstance(node, SequenceNode): 
     75                    constructor = self.construct_sequence 
     76                elif isinstance(node, MappingNode): 
     77                    constructor = self.construct_mapping 
     78        data = constructor(node) 
     79        self.constructed_objects[node] = data 
     80        return data 
    6481 
    6582    def construct_scalar(self, node): 
     
    153170    add_constructor = classmethod(add_constructor) 
    154171 
    155     yaml_constructors = {} 
     172    def add_multi_constructor(cls, tag_prefix, multi_constructor): 
     173        if not 'yaml_multi_constructors' in cls.__dict__: 
     174            cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy() 
     175        cls.yaml_multi_constructors[tag_prefix] = multi_constructor 
     176    add_multi_constructor = classmethod(add_multi_constructor) 
    156177 
    157178class SafeConstructor(BaseConstructor): 
     
    328349        return self.construct_mapping(node) 
    329350 
     351    def construct_yaml_object(self, node, cls): 
     352        mapping = self.construct_mapping(node) 
     353        state = {} 
     354        for key in mapping: 
     355            state[key.replace('-', '_')] = mapping[key] 
     356        data = cls.__new__(cls) 
     357        if hasattr(data, '__setstate__'): 
     358            data.__setstate__(mapping) 
     359        else: 
     360            data.__dict__.update(mapping) 
     361        return data 
     362 
    330363    def construct_undefined(self, node): 
    331364        raise ConstructorError(None, None, 
  • pyyaml/trunk/lib/yaml/detector.py

    r133 r136  
    66class BaseDetector: 
    77 
     8    DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str' 
     9    DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq' 
     10    DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' 
     11 
    812    yaml_detectors = {} 
     13 
     14    def __init__(self): 
     15        pass 
    916 
    1017    def add_detector(cls, tag, regexp, first): 
  • pyyaml/trunk/lib/yaml/emitter.py

    r133 r136  
    1212from events import * 
    1313 
     14import re 
     15 
    1416class EmitterError(YAMLError): 
    1517    pass 
     
    1820    def __init__(self, scalar, empty, multiline, 
    1921            allow_flow_plain, allow_block_plain, 
    20             allow_single_quoted, allow_double_quoted, allow_block): 
     22            allow_single_quoted, allow_double_quoted, 
     23            allow_block): 
    2124        self.scalar = scalar 
    2225        self.empty = empty 
     
    3538    } 
    3639 
    37     def __init__(self, writer): 
    38  
    39         # The writer should have the methods `write` and possibly `flush`. 
    40         self.writer = writer 
    41  
    42         # Encoding is provided by STREAM-START. 
     40    def __init__(self, stream, canonical=None, indent=None, width=None, 
     41            allow_unicode=None, line_break=None): 
     42 
     43        # The stream should have the methods `write` and possibly `flush`. 
     44        self.stream = stream 
     45 
     46        # Encoding can be overriden by STREAM-START. 
    4347        self.encoding = None 
    4448 
     
    7680 
    7781        # Formatting details. 
    78         self.canonical = False 
    79         self.allow_unicode = False 
     82        self.canonical = canonical 
     83        self.allow_unicode = allow_unicode 
     84        self.best_indent = 2 
     85        if indent and 1 < indent < 10: 
     86            self.best_indent = indent 
     87        self.best_width = 80 
     88        if width and width > self.best_indent*2: 
     89            self.best_width = width 
    8090        self.best_line_break = u'\n' 
    81         self.best_indent = 2 
    82         self.best_width = 80 
     91        if line_break in [u'\r', u'\n', u'\r\n']: 
     92            self.best_line_break = line_break 
     93 
     94        # Tag prefixes. 
    8395        self.tag_prefixes = None 
    8496 
    85         # Analyses cache. 
    86         self.anchor_text = None 
    87         self.tag_text = None 
    88         self.scalar_analysis = None 
    89         self.scalar_style = None 
     97        # Prepared anchor and tag. 
     98        self.prepared_anchor = None 
     99        self.prepared_tag = None 
     100 
     101        # Scalar analysis and style. 
     102        self.analysis = None 
     103        self.style = None 
    90104 
    91105    def emit(self, event): 
     
    140154    def expect_stream_start(self): 
    141155        if isinstance(self.event, StreamStartEvent): 
    142             self.encoding = self.event.encoding 
    143             self.canonical = self.event.canonical 
    144             self.allow_unicode = self.event.allow_unicode 
    145             if self.event.indent and self.event.indent > 1: 
    146                 self.best_indent = self.event.indent 
    147             if self.event.width and self.event.width > self.best_indent: 
    148                 self.best_width = self.event.width 
    149             if self.event.line_break in [u'\r', u'\n', u'\r\n']: 
    150                 self.best_line_break = self.event.line_break 
     156            if self.event.encoding: 
     157                self.encoding = self.event.encoding 
    151158            self.write_stream_start() 
    152159            self.state = self.expect_first_document_start 
     
    166173        if isinstance(self.event, DocumentStartEvent): 
    167174            if self.event.version: 
    168                 version_text = self.analyze_version(self.event.version) 
     175                version_text = self.prepare_version(self.event.version) 
    169176                self.write_version_directive(version_text) 
    170177            self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy() 
     
    175182                    prefix = self.event.tags[handle] 
    176183                    self.tag_prefixes[prefix] = handle 
    177                     handle_text = self.analyze_tag_handle(handle) 
    178                     prefix_text = self.analyze_tag_prefix(prefix) 
     184                    handle_text = self.prepare_tag_handle(handle) 
     185                    prefix_text = self.prepare_tag_prefix(prefix) 
    179186                    self.write_tag_directive(handle_text, prefix_text) 
    180187            implicit = (first and not self.event.explicit and not self.canonical 
     
    200207                self.write_indicator(u'...', True) 
    201208                self.write_indent() 
     209            self.flush_stream() 
    202210            self.state = self.expect_document_start 
    203211        else: 
     
    419427        length = 0 
    420428        if isinstance(self.event, NodeEvent) and self.event.anchor is not None: 
    421             if self.anchor_text is None: 
    422                 self.anchor_text = self.analyze_anchor(self.event.anchor) 
    423             length += len(self.anchor_text) 
     429            if self.prepared_anchor is None: 
     430                self.prepared_anchor = self.prepare_anchor(self.event.anchor) 
     431            length += len(self.prepared_anchor) 
    424432        if isinstance(self.event, (ScalarEvent, CollectionStartEvent))  \ 
    425433                and self.event.tag is not None: 
    426             if self.tag_text is None: 
    427                 self.tag_text = self.analyze_tag(self.event.tag) 
    428             length += len(self.tag_text) 
     434            if self.prepared_tag is None: 
     435                self.prepared_tag = self.prepare_tag(self.event.tag) 
     436            length += len(self.prepared_tag) 
    429437        if isinstance(self.event, ScalarEvent): 
    430             if self.scalar_analysis is None: 
    431                 self.scalar_analysis = self.analyze_scalar(self.event.value) 
    432             length += len(self.scalar_analysis.scalar) 
     438            if self.analysis is None: 
     439                self.analysis = self.analyze_scalar(self.event.value) 
     440            length += len(self.analysis.scalar) 
    433441        return (length < 128 and (isinstance(self.event, AliasEvent) 
    434             or (isinstance(self.event, ScalarEvent) and not self.scalar_analysis.multiline) 
     442            or (isinstance(self.event, ScalarEvent) 
     443                    and not self.analysis.empty and not self.analysis.multiline) 
    435444            or self.check_empty_sequence() or self.check_empty_mapping())) 
    436445 
     
    439448    def process_anchor(self, indicator): 
    440449        if self.event.anchor is None: 
     450            self.prepared_anchor = None 
    441451            return 
    442         if self.anchor_text is None: 
    443             self.anchor_text = self.analyze_anchor(self.event.anchor) 
    444         if self.anchor_text: 
    445             self.write_indicator(indicator+self.anchor_text, True) 
    446         self.anchor_text = None 
     452        if self.prepared_anchor is None: 
     453            self.prepared_anchor = self.prepare_anchor(self.event.anchor) 
     454        if self.prepared_anchor: 
     455            self.write_indicator(indicator+self.prepared_anchor, True) 
     456        self.prepared_anchor = None 
    447457 
    448458    def process_tag(self): 
    449         if self.event.tag is None: 
     459        tag = self.event.tag 
     460        if isinstance(self.event, ScalarEvent): 
     461            if self.style is None: 
     462                self.style = self.choose_scalar_style() 
     463            if self.style == '': 
     464                self.prepared_tag = None 
     465                return 
     466            if self.event.implicit and not tag: 
     467                tag = u'!' 
     468                self.prepared_tag = None 
     469        if not tag: 
     470            self.prepared_tag = None 
    450471            return 
    451         if isinstance(self.event, ScalarEvent) and self.best_scalar_style() == '': 
    452             return 
    453         if self.tag_text is None: 
    454             self.tag_text = self.analyze_tag(self.event.tag) 
    455         if self.tag_text: 
    456             self.write_indicator(self.tag_text, True) 
    457         self.tag_text = None 
    458  
    459     def best_scalar_style(self): 
    460         if self.scalar_analysis is None: 
    461             self.scalar_analysis = self.analyze_scalar(self.event.value) 
    462         if self.canonical: 
     472        if self.prepared_tag is None: 
     473            self.prepared_tag = self.prepare_tag(tag) 
     474        if self.prepared_tag: 
     475            self.write_indicator(self.prepared_tag, True) 
     476        self.prepared_tag = None 
     477 
     478    def choose_scalar_style(self): 
     479        if self.analysis is None: 
     480            self.analysis = self.analyze_scalar(self.event.value) 
     481        if self.event.style == '"' or self.canonical: 
    463482            return '"' 
    464         if (self.event.implicit and not self.event.style 
    465                 and ((self.flow_level and self.scalar_analysis.allow_flow_plain) 
    466                     or (not self.flow_level and self.scalar_analysis.allow_block_plain)) 
    467                 and (len(self.scalar_analysis.scalar) > 0 
    468                     or (not self.flow_level and not self.simple_key_context))): 
    469             return '' 
    470         elif self.event.style == '\'' and self.scalar_analysis.allow_single_quoted: 
    471             return '\'' 
    472         elif self.event.style in ['|', '>'] and not self.flow_level and self.scalar_analysis.allow_block: 
    473             return self.event.style 
    474         else: 
    475             return '"' 
    476         return style 
     483        if not self.event.style and self.event.implicit: 
     484            if (not (self.simple_key_context and 
     485                    (self.analysis.empty or self.analysis.multiline)) 
     486                and (self.flow_level and self.analysis.allow_flow_plain 
     487                    or (not self.flow_level and self.analysis.allow_block_plain))): 
     488                return '' 
     489        if self.event.style and self.event.style in '|>': 
     490            if not self.flow_level and self.analysis.allow_block: 
     491                return self.event.style 
     492        if not self.event.style or self.event.style == '\'': 
     493            if (self.analysis.allow_single_quoted and 
     494                    not (self.simple_key_context and self.analysis.multiline)): 
     495                return '\'' 
     496        return '"' 
    477497 
    478498    def process_scalar(self): 
    479         if self.scalar_analysis is None: 
    480             self.scalar_analysis = self.analyze_scalar(self.event.value) 
    481         style = self.best_scalar_style() 
    482         if self.scalar_analysis.multiline and not self.simple_key_context   \ 
    483                 and style not in ['|', '>']: 
    484             self.write_indent() 
    485         if style == '"': 
    486             self.write_double_quoted(self.scalar_analysis.scalar, 
    487                     split=(not self.simple_key_context)) 
    488         elif style == '\'': 
    489             self.write_single_quoted(self.scalar_analysis.scalar, 
    490                     split=(not self.simple_key_context)) 
    491         elif style == '>': 
    492             self.write_folded(self.scalar_analysis.scalar) 
    493         elif style == '|': 
    494             self.write_literal(self.scalar_analysis.scalar) 
    495         else: 
    496             self.write_plain(self.scalar_analysis.scalar, 
    497                     split=(not self.simple_key_context)) 
    498         self.scalar_analysis = None 
     499        if self.analysis is None: 
     500            self.analysis = self.analyze_scalar(self.event.value) 
     501        if self.style is None: 
     502            self.style = self.choose_scalar_style() 
     503        split = (not self.simple_key_context) 
     504        #if self.analysis.multiline and split    \ 
     505        #        and (not self.style or self.style in '\'\"'): 
     506        #    self.write_indent() 
     507        if self.style == '"': 
     508            self.write_double_quoted(self.analysis.scalar, split) 
     509        elif self.style == '\'': 
     510            self.write_single_quoted(self.analysis.scalar, split) 
     511        elif self.style == '>': 
     512            self.write_folded(self.analysis.scalar) 
     513        elif self.style == '|': 
     514            self.write_literal(self.analysis.scalar) 
     515        else: 
     516            self.write_plain(self.analysis.scalar, split) 
     517        self.analysis = None 
     518        self.style = None 
    499519 
    500520    # Analyzers. 
    501521 
    502     def analyze_version(self, version): 
     522    def prepare_version(self, version): 
    503523        major, minor = version 
    504524        if major != 1: 
     
    506526        return u'%d.%d' % (major, minor) 
    507527 
    508     def analyze_tag_handle(self, handle): 
     528    def prepare_tag_handle(self, handle): 
    509529        if not handle: 
    510530            raise EmitterError("tag handle must not be empty") 
     
    519539        return handle 
    520540 
    521     def analyze_tag_prefix(self, prefix): 
     541    def prepare_tag_prefix(self, prefix): 
    522542        if not prefix: 
    523543            raise EmitterError("tag prefix must not be empty") 
     
    542562        return u''.join(chunks) 
    543563 
    544     def analyze_tag(self, tag): 
     564    def prepare_tag(self, tag): 
    545565        if not tag: 
    546566            raise EmitterError("tag must not be empty") 
     567        if tag == u'!': 
     568            return tag 
    547569        handle = None 
    548570        suffix = tag 
     
    575597            return u'!<%s>' % suffix_text 
    576598 
    577     def analyze_anchor(self, anchor): 
     599    def prepare_anchor(self, anchor): 
    578600        if not anchor: 
    579601            raise EmitterError("anchor must not be empty") 
     
    585607        return anchor 
    586608 
    587     def analyze_scalar(self, scalar):   # It begs for refactoring. 
     609    def analyze_scalar(self, scalar): 
     610 
     611        # Empty scalar is a special case. 
    588612        if not scalar: 
    589613            return ScalarAnalysis(scalar=scalar, empty=True, multiline=False, 
     
    591615                    allow_single_quoted=True, allow_double_quoted=True, 
    592616                    allow_block=False) 
    593         contains_block_indicator = False 
    594         contains_flow_indicator = False 
    595         contains_line_breaks = False 
    596         contains_unicode_characters = False 
    597         contains_special_characters = False 
    598         contains_inline_spaces = False          # non-space space+ non-space 
    599         contains_inline_breaks = False          # non-space break+ non-space 
    600         contains_leading_spaces = False         # ^ space+ (non-space | $) 
    601         contains_leading_breaks = False         # ^ break+ (non-space | $) 
    602         contains_trailing_spaces = False        # non-space space+ $ 
    603         contains_trailing_breaks = False        # non-space break+ $ 
    604         contains_inline_breaks_spaces = False   # non-space break+ space+ non-space 
    605         contains_mixed_breaks_spaces = False    # anything else 
     617 
     618        # Indicators and special characters. 
     619        block_indicators = False 
     620        flow_indicators = False 
     621        line_breaks = False 
     622        special_characters = False 
     623 
     624        # Whitespaces. 
     625        inline_spaces = False          # non-space space+ non-space 
     626        inline_breaks = False          # non-space break+ non-space 
     627        leading_spaces = False         # ^ space+ (non-space | $) 
     628        leading_breaks = False         # ^ break+ (non-space | $) 
     629        trailing_spaces = False        # (^ | non-space) space+ $ 
     630        trailing_breaks = False        # (^ | non-space) break+ $ 
     631        inline_breaks_spaces = False   # non-space break+ space+ non-space 
     632        mixed_breaks_spaces = False    # anything else 
     633 
     634        # Check document indicators. 
    606635        if scalar.startswith(u'---') or scalar.startswith(u'...'): 
    607             contains_block_indicator = True 
    608             contains_flow_indicator = True 
    609         first = True 
    610         last = (len(scalar) == 1) 
    611         preceeded_by_space = False 
    612         followed_by_space = (len(scalar) > 1 and 
     636            block_indicators = True 
     637            flow_indicators = True 
     638 
     639        # First character or preceded by a whitespace. 
     640        preceeded_by_space = True 
     641 
     642        # Last character or followed by a whitespace. 
     643        followed_by_space = (len(scalar) == 1 or 
    613644                scalar[1] in u'\0 \t\r\n\x85\u2028\u2029') 
    614         spaces = breaks = mixed = leading = False 
     645 
     646        # The current series of whitespaces contain plain spaces. 
     647        spaces = False 
     648 
     649        # The current series of whitespaces contain line breaks. 
     650        breaks = False 
     651 
     652        # The current series of whitespaces contain a space followed by a 
     653        # break. 
     654        mixed = False 
     655 
     656        # The current series of whitespaces start at the beginning of the 
     657        # scalar. 
     658        leading = False 
     659 
    615660        index = 0 
    616661        while index < len(scalar): 
    617662            ch = scalar[index] 
    618             if first: 
     663 
     664            # Check for indicators. 
     665 
     666            if index == 0: 
     667                # Leading indicators are special characters. 
    619668                if ch in u'#,[]{}#&*!|>\'\"%@`':  
    620                     contains_flow_indicator = True 
    621                     contains_block_indicator = True 
     669                    flow_indicators = True 
     670                    block_indicators = True 
    622671                if ch in u'?:': 
    623                     contains_flow_indicator = True 
    624                     if followed_by_space or last: 
    625                         contains_block_indicator = True 
    626                 if ch == u'-' and (followed_by_space or last): 
    627                     contains_flow_indicator = True 
    628                     contains_block_indicator = True 
     672                    flow_indicators = True 
     673                    if followed_by_space: 
     674                        block_indicators = True 
     675                if ch == u'-' and followed_by_space: 
     676                    flow_indicators = True 
     677                    block_indicators = True 
    629678            else: 
     679                # Some indicators cannot appear within a scalar as well. 
    630680                if ch in u',?[]{}': 
    631                     contains_flow_indicator = True 
     681                    flow_indicators = True 
    632682                if ch == u':': 
    633                     contains_flow_indicator = True 
    634                     if followed_by_space or last: 
    635                         contains_block_indicator = True 
    636                 if ch == u'#' and (preceeded_by_space or first): 
    637                     contains_flow_indicator = True 
    638                     contains_block_indicator = True 
     683                    flow_indicators = True 
     684                    if followed_by_space: 
     685                        block_indicators = True 
     686                if ch == u'#' and preceeded_by_space: 
     687                    flow_indicators = True 
     688                    block_indicators = True 
     689 
     690            # Check for line breaks, special, and unicode characters. 
     691 
    639692            if ch in u'\n\x85\u2028\u2029': 
    640                 contains_line_breaks = True 
     693                line_breaks = True 
    641694            if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'): 
    642                 if ch < u'\x80': 
    643                     contains_special_characters = True 
     695                if ch < u'\x80' or ch == u'\uFEFF': # '\uFEFF' is BOM. 
     696                    special_characters = True 
    644697                else: 
    645                     contains_unicode_characters = True 
    646             if ch == u' ': 
    647                 if not spaces and not breaks: 
    648                     leading = first 
    649                 spaces = True 
    650             elif ch in u'\n\x85\u2028\u2029': 
    651                 if not spaces and not breaks: 
    652                     leading = first 
    653                 breaks = True 
    654                 if spaces: 
    655                     mixed = True 
    656             if ch not in u' \n\x85\u2028\u2029': 
     698                    unicode_characters = True 
     699                    if not self.allow_unicode: 
     700                        special_characters = True 
     701 
     702            # Spaces, line breaks, and how they are mixed. State machine. 
     703 
     704            # Start or continue series of whitespaces. 
     705            if ch in u' \n\x85\u2028\u2029': 
     706                if spaces and breaks: 
     707                    if ch != u' ':      # break+ (space+ break+)    => mixed 
     708                        mixed = True 
     709                elif spaces: 
     710                    if ch != u' ':      # (space+ break+)   => mixed 
     711                        breaks = True 
     712                        mixed = True 
     713                elif breaks: 
     714                    if ch == u' ':      # break+ space+ 
     715                        spaces = True 
     716                else: 
     717                    leading = (index == 0) 
     718                    if ch == u' ':      # space+ 
     719                        spaces = True 
     720                    else:               # break+ 
     721                        breaks = True 
     722 
     723            # Series of whitespaces ended with a non-space. 
     724            elif spaces or breaks: 
    657725                if leading: 
    658726                    if spaces and breaks: 
    659                         contains_mixed_breaks_spaces = True 
     727                        mixed_breaks_spaces = True 
    660728                    elif spaces: 
    661                         contains_leading_spaces = True 
     729                        leading_spaces = True 
    662730                    elif breaks: 
    663                         contains_leading_breaks = True 
     731                        leading_breaks = True 
    664732                else: 
    665733                    if mixed: 
    666                         contains_mixed_break_spaces = True 
     734                        mixed_breaks_spaces = True 
    667735                    elif spaces and breaks: 
    668                         contains_inline_breaks_spaces = True 
     736                        inline_breaks_spaces = True 
    669737                    elif spaces: 
    670                         contains_inline_spaces = True 
     738                        inline_spaces = True 
    671739                    elif breaks: 
    672                         contains_inline_breaks = True 
     740                        inline_breaks = True 
    673741                spaces = breaks = mixed = leading = False 
    674             elif last: 
     742 
     743            # Series of whitespaces reach the end. 
     744            if (spaces or breaks) and (index == len(scalar)-1): 
    675745                if spaces and breaks: 
    676                     contains_mixed_break_spaces = True 
     746                    mixed_breaks_spaces = True 
    677747                elif spaces: 
     748                    trailing_spaces = True 
    678749                    if leading: 
    679                         contains_leading_spaces = True 
    680                     else: 
    681                         contains_trailing_spaces = True 
     750                        leading_spaces = True 
    682751                elif breaks: 
     752                    trailing_breaks = True 
    683753                    if leading: 
    684                         contains_leading_breaks = True 
    685                     else: 
    686                         contains_trailing_breaks = True 
     754                        leading_breaks = True 
     755                spaces = breaks = mixed = leading = False 
     756 
     757            # Prepare for the next character. 
    687758            index += 1 
    688             first = False 
    689             last = (index+1 == len(scalar)) 
    690759            preceeded_by_space = (ch in u'\0 \t\r\n\x85\u2028\u2029') 
    691             followed_by_space = (index+1 < len(scalar) and 
     760            followed_by_space = (index+1 >= len(scalar) or 
    692761                    scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029') 
    693         if contains_unicode_characters and not self.allow_unicode: 
    694             contains_special_characters = True 
    695         allow_flow_plain = not (contains_flow_indicator or contains_special_characters 
    696             or contains_leading_spaces or contains_leading_breaks 
    697             or contains_trailing_spaces or contains_trailing_breaks 
    698             or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 
    699         allow_block_plain = not (contains_block_indicator or contains_special_characters 
    700             or contains_leading_spaces or contains_leading_breaks 
    701             or contains_trailing_spaces or contains_trailing_breaks 
    702             or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 
    703         allow_single_quoted = not (contains_special_characters 
    704             or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 
     762 
     763        # Let's decide what styles are allowed. 
     764        allow_flow_plain = True 
     765        allow_block_plain = True 
     766        allow_single_quoted = True 
    705767        allow_double_quoted = True 
    706         allow_block = not (contains_special_characters 
    707             or contains_leading_spaces or contains_leading_breaks 
    708             or contains_trailing_spaces or contains_mixed_breaks_spaces) 
    709         return ScalarAnalysis(scalar=scalar, empty=False, multiline=contains_line_breaks, 
    710                 allow_flow_plain=allow_flow_plain, allow_block_plain=allow_block_plain, 
    711                 allow_single_quoted=allow_single_quoted, allow_double_quoted=allow_double_quoted, 
     768        allow_block = True 
     769 
     770        # Leading and trailing whitespace are bad for plain scalars. We also 
     771        # do not want to mess with leading whitespaces for block scalars. 
     772        if leading_spaces or leading_breaks or trailing_spaces: 
     773            allow_flow_plain = allow_block_plain = allow_block = False 
     774 
     775        # Trailing breaks are fine for block scalars, but unacceptable for 
     776        # plain scalars. 
     777        if trailing_breaks: 
     778            allow_flow_plain = allow_block_plain = False 
     779 
     780        # The combination of (space+ break+) is only acceptable for block 
     781        # scalars. 
     782        if inline_breaks_spaces: 
     783            allow_flow_plain = allow_block_plain = allow_single_quoted = False 
     784 
     785        # Mixed spaces and breaks, as well as special character are only 
     786        # allowed for double quoted scalars. 
     787        if mixed_breaks_spaces or special_characters: 
     788            allow_flow_plain = allow_block_plain =  \ 
     789            allow_single_quoted = allow_block = False 
     790 
     791        # We don't emit multiline plain scalars. 
     792        if line_breaks: 
     793            allow_flow_plain = allow_block_plain = False 
     794 
     795        # Flow indicators are forbidden for flow plain scalars. 
     796        if flow_indicators: 
     797            allow_flow_plain = False 
     798 
     799        # Block indicators are forbidden for block plain scalars. 
     800        if block_indicators: 
     801            allow_block_plain = False 
     802 
     803        return ScalarAnalysis(scalar=scalar, 
     804                empty=False, multiline=line_breaks, 
     805                allow_flow_plain=allow_flow_plain, 
     806                allow_block_plain=allow_block_plain, 
     807                allow_single_quoted=allow_single_quoted, 
     808                allow_double_quoted=allow_double_quoted, 
    712809                allow_block=allow_block) 
    713810 
    714811    # Writers. 
     812 
     813    def flush_stream(self): 
     814        if hasattr(self.stream, 'flush'): 
     815            self.stream.flush() 
    715816 
    716817    def write_stream_start(self): 
    717818        # Write BOM if needed. 
    718819        if self.encoding and self.encoding.startswith('utf-16'): 
    719             self.writer.write(u'\xFF\xFE'.encode(self.encoding)) 
     820            self.stream.write(u'\xFF\xFE'.encode(self.encoding)) 
    720821 
    721822    def write_stream_end(self): 
    722         if hasattr(self.writer, 'flush'): 
    723             self.writer.flush() 
     823        self.flush_stream() 
    724824 
    725825    def write_indicator(self, indicator, need_whitespace, 
     
    734834        if self.encoding: 
    735835            data = data.encode(self.encoding) 
    736         self.writer.write(data) 
     836        self.stream.write(data) 
    737837 
    738838    def write_indent(self): 
     
    747847            if self.encoding: 
    748848                data = data.encode(self.encoding) 
    749             self.writer.write(data) 
     849            self.stream.write(data) 
    750850 
    751851    def write_line_break(self, data=None): 
     
    758858        if self.encoding: 
    759859            data = data.encode(self.encoding) 
    760         self.writer.write(data) 
     860        self.stream.write(data) 
    761861 
    762862    def write_version_directive(self, version_text): 
     
    764864        if self.encoding: 
    765865            data = data.encode(self.encoding) 
    766         self.writer.write(data) 
     866        self.stream.write(data) 
    767867        self.write_line_break() 
    768868 
     
    771871        if self.encoding: 
    772872            data = data.encode(self.encoding) 
    773         self.writer.write(data) 
     873        self.stream.write(data) 
    774874        self.write_line_break() 
    775875 
    776     # Scalar writers. 
     876    # Scalar streams. 
    777877 
    778878    def write_single_quoted(self, text, split=True): 
     
    795895                        if self.encoding: 
    796896                            data = data.encode(self.encoding) 
    797                         self.writer.write(data) 
     897                        self.stream.write(data) 
    798898                    start = end 
    799899            elif breaks: 
     
    815915                        if self.encoding: 
    816916                            data = data.encode(self.encoding) 
    817                         self.writer.write(data) 
     917                        self.stream.write(data) 
    818918                        start = end 
    819919                    if ch == u'\'': 
     
    822922                        if self.encoding: 
    823923                            data = data.encode(self.encoding) 
    824                         self.writer.write(data) 
     924                        self.stream.write(data) 
    825925                        start = end + 1 
    826926            if ch is not None: 
     
    864964                    if self.encoding: 
    865965                        data = data.encode(self.encoding) 
    866                     self.writer.write(data) 
     966                    self.stream.write(data) 
    867967                    start = end 
    868968                if ch is not None: 
     
    878978                    if self.encoding: 
    879979                        data = data.encode(self.encoding) 
    880                     self.writer.write(data) 
     980                    self.stream.write(data) 
    881981                    start = end+1 
    882982            if 0 < end < len(text)-1 and (ch == u' ' or start >= end)   \ 
     
    888988                if self.encoding: 
    889989                    data = data.encode(self.encoding) 
    890                 self.writer.write(data) 
     990                self.stream.write(data) 
    891991                self.write_indent() 
    892992                self.whitespace = False 
     
    897997                    if self.encoding: 
    898998                        data = data.encode(self.encoding) 
    899                     self.writer.write(data) 
     999                    self.stream.write(data) 
    9001000            end += 1 
    9011001        self.write_indicator(u'"', False) 
     
    9481048                        if self.encoding: 
    9491049                            data = data.encode(self.encoding) 
    950                         self.writer.write(data) 
     1050                        self.stream.write(data) 
    9511051                    start = end 
    9521052            else: 
     
    9551055                    if self.encoding: 
    9561056                        data = data.encode(self.encoding) 
    957                     self.writer.write(data) 
     1057                    self.stream.write(data) 
    9581058                    if ch is None: 
    9591059                        self.write_line_break() 
     
    9891089                    if self.encoding: 
    9901090                        data = data.encode(self.encoding) 
    991                     self.writer.write(data) 
     1091                    self.stream.write(data) 
    9921092                    if ch is None: 
    9931093                        self.write_line_break() 
     
    10051105            if self.encoding: 
    10061106                data = data.encode(self.encoding) 
    1007             self.writer.write(data) 
     1107            self.stream.write(data) 
    10081108        self.writespace = False 
    10091109        self.indention = False 
     
    10261126                        if self.encoding: 
    10271127                            data = data.encode(self.encoding) 
    1028                         self.writer.write(data) 
     1128                        self.stream.write(data) 
    10291129                    start = end 
    10301130            elif breaks: 
     
    10471147                    if self.encoding: 
    10481148                        data = data.encode(self.encoding) 
    1049                     self.writer.write(data) 
     1149                    self.stream.write(data) 
    10501150                    start = end 
    10511151            if ch is not None: 
  • pyyaml/trunk/lib/yaml/error.py

    r119 r136  
    4949 
    5050    def __init__(self, context=None, context_mark=None, 
    51             problem=None, problem_mark=None): 
     51            problem=None, problem_mark=None, note=None): 
    5252        self.context = context 
    5353        self.context_mark = context_mark 
    5454        self.problem = problem 
    5555        self.problem_mark = problem_mark 
     56        self.note = note 
    5657 
    5758    def __str__(self): 
    5859        lines = [] 
    59         #for (place, mark) in [(self.context, self.context_mark), 
    60         #                        (self.problem, self.problem_mark)]: 
    61         #    if place is not None: 
    62         #        lines.append(place) 
    63         #        if mark is not None: 
    64         #            lines.append(str(mark)) 
    6560        if self.context is not None: 
    6661            lines.append(self.context) 
     
    7570        if self.problem_mark is not None: 
    7671            lines.append(str(self.problem_mark)) 
     72        if self.note is not None: 
     73            lines.append(self.note) 
    7774        return '\n'.join(lines) 
    7875 
    79  
    80  
  • pyyaml/trunk/lib/yaml/events.py

    r133 r136  
    3434 
    3535class StreamStartEvent(Event): 
    36     def __init__(self, start_mark=None, end_mark=None, 
    37             encoding=None, line_break=None, canonical=None, 
    38             indent=None, width=None, allow_unicode=None): 
     36    def __init__(self, start_mark=None, end_mark=None, encoding=None): 
    3937        self.start_mark = start_mark 
    4038        self.end_mark = end_mark 
    4139        self.encoding = encoding 
    42         self.line_break = line_break 
    43         self.canonical = canonical 
    44         self.indent = indent 
    45         self.width = width 
    46         self.allow_unicode = allow_unicode 
    4740 
    4841class StreamEndEvent(Event): 
     
    6962 
    7063class ScalarEvent(NodeEvent): 
    71     def __init__(self, anchor, tag, value, start_mark=None, end_mark=None, 
    72             implicit=None, style=None): 
     64    def __init__(self, anchor, tag, implicit, value, 
     65            start_mark=None, end_mark=None, style=None): 
    7366        self.anchor = anchor 
    7467        self.tag = tag 
     68        self.implicit = implicit 
    7569        self.value = value 
    7670        self.start_mark = start_mark 
    7771        self.end_mark = end_mark 
    78         self.implicit = implicit 
    7972        self.style = style 
    8073 
  • pyyaml/trunk/lib/yaml/nodes.py

    r133 r136  
    2424class ScalarNode(Node): 
    2525    id = 'scalar' 
    26     def __init__(self, tag, value, implicit, 
     26    def __init__(self, tag, value, 
    2727            start_mark=None, end_mark=None, style=None): 
    2828        self.tag = tag 
    2929        self.value = value 
    30         self.implicit = implicit 
    3130        self.start_mark = start_mark 
    3231        self.end_mark = end_mark 
  • pyyaml/trunk/lib/yaml/parser.py

    r132 r136  
    2525# stream ::= (BOM? implicit_document)? (BOM? explicit_document)* STREAM-END 
    2626 
    27 # Note that there is a slight deviation from the specification. We require a 
    28 # non-empty node content if ANCHOR or TAG is specified. This disallow such 
    29 # documents as 
    30 # 
    31 #   key:    !!str   # empty value 
    32 # 
    33 # This is done to prevent ambiguity in parsing tags and aliases: 
    34 # 
    35 #   {   !!perl/YAML::Parser:    value } 
    36 # 
    37 # What is it? Should it be interpreted as 
    38 #   {   ? !<tag:yaml.org,2002:perl/YAML::Parser> '' : value } 
    39 # or 
    40 #   {   ? !<tag:yaml.org,2002:perl/YAML::Parser:> value : '' } 
    41 # Since we disallow non-empty node content, tags are always followed by spaces 
    42 # or line breaks. 
    43  
    4427# FIRST sets: 
    4528# stream: { STREAM-START } 
     
    6750from tokens import * 
    6851from events import * 
     52from scanner import * 
    6953 
    7054class ParserError(MarkedYAMLError): 
     
    7256 
    7357class Parser: 
    74     # Since writing an LL(1) parser is a straightforward task, we do not give 
    75     # many comments here. 
     58    # Since writing a recursive-descendant parser is a straightforward task, we 
     59    # do not give many comments here. 
    7660    # Note that we use Python generators. If you rewrite the parser in another 
    7761    # language, you may replace all 'yield'-s with event handler calls. 
     
    8266    } 
    8367 
    84     def __init__(self, scanner): 
    85         self.scanner = scanner 
     68    def __init__(self): 
    8669        self.current_event = None 
    8770        self.yaml_version = None 
     
    8972        self.event_generator = self.parse_stream() 
    9073 
    91     def check(self, *choices): 
     74    def check_event(self, *choices): 
    9275        # Check the type of the next event. 
    9376        if self.current_event is None: 
     
    9780                pass 
    9881        if self.current_event is not None: 
     82            if not choices: 
     83                return True 
    9984            for choice in choices: 
    10085                if isinstance(self.current_event, choice): 
     
    10287        return False 
    10388 
    104     def peek(self): 
     89    def peek_event(self): 
    10590        # Get the next event. 
    10691        if self.current_event is None: 
     
    11196        return self.current_event 
    11297 
    113     def get(self): 
     98    def get_event(self): 
    11499        # Get the next event. 
    115100        if self.current_event is None: 
     
    130115 
    131116        # Parse start of stream. 
    132         token = self.scanner.get() 
     117        token = self.get_token() 
    133118        yield StreamStartEvent(token.start_mark, token.end_mark, 
    134119                encoding=token.encoding) 
    135120 
    136121        # Parse implicit document. 
    137         if not self.scanner.check(DirectiveToken, DocumentStartToken, 
     122        if not self.check_token(DirectiveToken, DocumentStartToken, 
    138123                StreamEndToken): 
    139124            self.tag_handles = self.DEFAULT_TAGS 
    140             token = self.scanner.peek() 
     125            token = self.peek_token() 
    141126            start_mark = end_mark = token.start_mark 
    142127            yield DocumentStartEvent(start_mark, end_mark, 
     
    144129            for event in self.parse_block_node(): 
    145130                yield event 
    146             token = self.scanner.peek() 
     131            token = self.peek_token() 
    147132            start_mark = end_mark = token.start_mark 
    148133            explicit = False 
    149             while self.scanner.check(DocumentEndToken): 
    150                 token = self.scanner.get() 
     134            while self.check_token(DocumentEndToken): 
     135                token = self.get_token() 
    151136                end_mark = token.end_mark 
    152137                explicit = True 
     
    155140 
    156141        # Parse explicit documents. 
    157         while not self.scanner.check(StreamEndToken): 
    158             token = self.scanner.peek() 
     142        while not self.check_token(StreamEndToken): 
     143            token = self.peek_token() 
    159144            start_mark = token.start_mark 
    160145            version, tags = self.process_directives() 
    161             if not self.scanner.check(DocumentStartToken): 
     146            if not self.check_token(DocumentStartToken): 
    162147                raise ParserError(None, None, 
    163148                        "expected '<document start>', but found %r" 
    164                         % self.scanner.peek().id, 
    165                         self.scanner.peek().start_mark) 
    166             token = self.scanner.get() 
     149                        % self.peek_token().id, 
     150                        self.peek_token().start_mark) 
     151            token = self.get_token() 
    167152            end_mark = token.end_mark 
    168153            yield DocumentStartEvent(start_mark, end_mark, 
    169154                    explicit=True, version=version, tags=tags) 
    170             if self.scanner.check(DirectiveToken, 
     155            if self.check_token(DirectiveToken, 
    171156                    DocumentStartToken, DocumentEndToken, StreamEndToken): 
    172157                yield self.process_empty_scalar(token.end_mark) 
     
    174159                for event in self.parse_block_node(): 
    175160                    yield event 
    176             token = self.scanner.peek() 
     161            token = self.peek_token() 
    177162            start_mark = end_mark = token.start_mark 
    178163            explicit = False 
    179             while self.scanner.check(DocumentEndToken): 
    180                 token = self.scanner.get() 
     164            while self.check_token(DocumentEndToken): 
     165                token = self.get_token() 
    181166                end_mark = token.end_mark 
    182167                explicit=True 
     
    185170 
    186171        # Parse end of stream. 
    187         token = self.scanner.get() 
     172        token = self.get_token() 
    188173        yield StreamEndEvent(token.start_mark, token.end_mark) 
    189174 
     
    192177        self.yaml_version = None 
    193178        self.tag_handles = {} 
    194         while self.scanner.check(DirectiveToken): 
    195             token = self.scanner.get() 
     179        while self.check_token(DirectiveToken): 
     180            token = self.get_token() 
    196181            if token.name == u'YAML': 
    197182                if self.yaml_version is not None: 
     
    238223        # block_node_or_indentless_sequence ::= ALIAS | properties? 
    239224        #                                       (block_content | indentless_block_sequence) 
    240         if self.scanner.check(AliasToken): 
    241             token = self.scanner.get() 
     225        if self.check_token(AliasToken): 
     226            token = self.get_token() 
    242227            yield AliasEvent(token.value, token.start_mark, token.end_mark) 
    243228        else: 
     
    245230            tag = None 
    246231            start_mark = end_mark = tag_mark = None 
    247             if self.scanner.check(AnchorToken): 
    248                 token = self.scanner.get() 
     232            if self.check_token(AnchorToken): 
     233                token = self.get_token() 
    249234                start_mark = token.start_mark 
    250235                end_mark = token.end_mark 
    251236                anchor = token.value 
    252                 if self.scanner.check(TagToken): 
    253                     token = self.scanner.get() 
     237                if self.check_token(TagToken): 
     238                    token = self.get_token() 
    254239                    tag_mark = token.start_mark 
    255240                    end_mark = token.end_mark 
    256241                    tag = token.value 
    257             elif self.scanner.check(TagToken): 
    258                 token = self.scanner.get() 
     242            elif self.check_token(TagToken): 
     243                token = self.get_token() 
    259244                start_mark = tag_mark = token.start_mark 
    260245                end_mark = token.end_mark 
    261246                tag = token.value 
    262                 if self.scanner.check(AnchorToken): 
    263                     token = self.scanner.get() 
     247                if self.check_token(AnchorToken): 
     248                    token = self.get_token() 
    264249                    end_mark = token.end_mark 
    265250                    anchor = token.value 
    266             if tag is not None: 
     251            if tag is not None and tag != u'!': 
    267252                handle, suffix = tag 
    268253                if handle is not None: 
     
    274259                else: 
    275260                    tag = suffix 
    276             #if tag is None: 
    277             #    if not (self.scanner.check(ScalarToken) and 
    278             #            self.scanner.peek().implicit): 
    279             #        tag = u'!' 
     261            #if tag == u'!': 
     262            #    raise ParserError("while parsing a node", start_mark, 
     263            #            "found non-specific tag '!'", tag_mark, 
     264            #            "Please check 'http://pyyaml.org/wiki/YAMLNonSpecificTag' and share your opinion.") 
    280265            if start_mark is None: 
    281                 start_mark = end_mark = self.scanner.peek().start_mark 
     266                start_mark = end_mark = self.peek_token().start_mark 
    282267            event = None 
    283268            collection_events = None 
    284             if indentless_sequence and self.scanner.check(BlockEntryToken): 
    285                 end_mark = self.scanner.peek().end_mark 
     269            if indentless_sequence and self.check_token(BlockEntryToken): 
     270                end_mark = self.peek_token().end_mark 
    286271                event = SequenceStartEvent(anchor, tag, start_mark, end_mark) 
    287272                collection_events = self.parse_indentless_sequence() 
    288273            else: 
    289                 if self.scanner.check(ScalarToken): 
    290                     token = self.scanner.get() 
     274                if self.check_token(ScalarToken): 
     275                    token = self.get_token() 
    291276                    end_mark = token.end_mark 
    292                     implicit = (tag is None and token.implicit) 
    293                     event = ScalarEvent(anchor, tag, token.value, 
    294                             start_mark, end_mark, 
    295                             implicit=implicit, style=token.style) 
    296                 elif self.scanner.check(FlowSequenceStartToken): 
    297                     end_mark = self.scanner.peek().end_mark 
     277                    implicit = ((tag is None or tag == u'!') and token.implicit) 
     278                    event = ScalarEvent(anchor, tag, implicit, token.value, 
     279                            start_mark, end_mark, style=token.style) 
     280                elif self.check_token(FlowSequenceStartToken): 
     281                    end_mark = self.peek_token().end_mark 
    298282                    event = SequenceStartEvent(anchor, tag, start_mark, end_mark, 
    299283                            flow_style=True) 
    300284                    collection_events = self.parse_flow_sequence() 
    301                 elif self.scanner.check(FlowMappingStartToken): 
    302                     end_mark = self.scanner.peek().end_mark 
     285                elif self.check_token(FlowMappingStartToken): 
     286                    end_mark = self.peek_token().end_mark 
    303287                    event = MappingStartEvent(anchor, tag, start_mark, end_mark, 
    304288                            flow_style=True) 
    305289                    collection_events = self.parse_flow_mapping() 
    306                 elif block and self.scanner.check(BlockSequenceStartToken): 
    307                     end_mark = self.scanner.peek().start_mark 
     290                elif block and self.check_token(BlockSequenceStartToken): 
     291                    end_mark = self.peek_token().start_mark 
    308292                    event = SequenceStartEvent(anchor, tag, start_mark, end_mark, 
    309293                            flow_style=False) 
    310294                    collection_events = self.parse_block_sequence() 
    311                 elif block and self.scanner.check(BlockMappingStartToken): 
    312                     end_mark = self.scanner.peek().start_mark 
     295                elif block and self.check_token(BlockMappingStartToken): 
     296                    end_mark = self.peek_token().start_mark 
    313297                    event = MappingStartEvent(anchor, tag, start_mark, end_mark, 
    314298                            flow_style=False) 
     
    317301                    # Empty scalars are allowed even if a tag or an anchor is 
    318302                    # specified. 
    319                     event = ScalarEvent(anchor, tag, u'', start_mark, end_mark, 
    320                             implicit=True) 
     303                    implicit = (tag is None or tag == u'!') 
     304                    event = ScalarEvent(anchor, tag, implicit, u'', 
     305                            start_mark, end_mark) 
    321306                else: 
    322307                    if block: 
     
    324309                    else: 
    325310                        node = 'flow' 
    326                     token = self.scanner.peek() 
     311                    token = self.peek_token() 
    327312                    raise ParserError("while scanning a %s node" % node, start_mark, 
    328313                            "expected the node content, but found %r" % token.id, 
     
    335320    def parse_block_sequence(self): 
    336321        # BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END 
    337         token = self.scanner.get() 
     322        token = self.get_token() 
    338323        start_mark = token.start_mark 
    339         while self.scanner.check(BlockEntryToken): 
    340             token = self.scanner.get() 
    341             if not self.scanner.check(BlockEntryToken, BlockEndToken): 
     324        while self.check_token(BlockEntryToken): 
     325            token = self.get_token() 
     326            if not self.check_token(BlockEntryToken, BlockEndToken): 
    342327                for event in self.parse_block_node(): 
    343328                    yield event 
    344329            else: 
    345330                yield self.process_empty_scalar(token.end_mark) 
    346         if not self.scanner.check(BlockEndToken): 
    347             token = self.scanner.peek() 
     331        if not self.check_token(BlockEndToken): 
     332            token = self.peek_token() 
    348333            raise ParserError("while scanning a block collection", start_mark, 
    349334                    "expected <block end>, but found %r" % token.id, token.start_mark) 
    350         token = self.scanner.get() 
     335        token = self.get_token() 
    351336        yield SequenceEndEvent(token.start_mark, token.end_mark) 
    352337 
    353338    def parse_indentless_sequence(self): 
    354339        # (BLOCK-ENTRY block_node?)+ 
    355         while self.scanner.check(BlockEntryToken): 
    356             token = self.scanner.get() 
    357             if not self.scanner.check(BlockEntryToken, 
     340        while self.check_token(BlockEntryToken): 
     341            token = self.get_token() 
     342            if not self.check_token(BlockEntryToken, 
    358343                    KeyToken, ValueToken, BlockEndToken): 
    359344                for event in self.parse_block_node(): 
     
    361346            else: 
    362347                yield self.process_empty_scalar(token.end_mark) 
    363         token = self.scanner.peek() 
     348        token = self.peek_token() 
    364349        yield SequenceEndEvent(token.start_mark, token.start_mark) 
    365350 
     
    369354        #   (VALUE block_node_or_indentless_sequence?)?)* 
    370355        # BLOCK-END 
    371         token = self.scanner.get() 
     356        token = self.get_token() 
    372357        start_mark = token.start_mark 
    373         while self.scanner.check(KeyToken, ValueToken): 
    374             if self.scanner.check(KeyToken): 
    375                 token = self.scanner.get() 
    376                 if not self.scanner.check(KeyToken, ValueToken, BlockEndToken): 
     358        while self.check_token(KeyToken, ValueToken): 
     359            if self.check_token(KeyToken): 
     360                token = self.get_token() 
     361                if not self.check_token(KeyToken, ValueToken, BlockEndToken): 
    377362                    for event in self.parse_block_node_or_indentless_sequence(): 
    378363                        yield event 
    379364                else: 
    380365                    yield self.process_empty_scalar(token.end_mark) 
    381             if self.scanner.check(ValueToken): 
    382                 token = self.scanner.get() 
    383                 if not self.scanner.check(KeyToken, ValueToken, BlockEndToken): 
     366            if self.check_token(ValueToken): 
     367                token = self.get_token() 
     368                if not self.check_token(KeyToken, ValueToken, BlockEndToken): 
    384369                    for event in self.parse_block_node_or_indentless_sequence(): 
    385370                        yield event 
     
    387372                    yield self.process_empty_scalar(token.end_mark) 
    388373            else: 
    389                 token = self.scanner.peek() 
     374                token = self.peek_token() 
    390375                yield self.process_empty_scalar(token.start_mark) 
    391         if not self.scanner.check(BlockEndToken): 
    392             token = self.scanner.peek() 
     376        if not self.check_token(BlockEndToken): 
     377            token = self.peek_token() 
    393378            raise ParserError("while scanning a block mapping", start_mark, 
    394379                    "expected <block end>, but found %r" % token.id, token.start_mark) 
    395         token = self.scanner.get() 
     380        token = self.get_token() 
    396381        yield MappingEndEvent(token.start_mark, token.end_mark) 
    397382 
     
    407392        # For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?` 
    408393        # generate an inline mapping (set syntax). 
    409         token = self.scanner.get() 
     394        token = self.get_token() 
    410395        start_mark = token.start_mark 
    411         while not self.scanner.check(FlowSequenceEndToken): 
    412             if self.scanner.check(KeyToken): 
    413                 token = self.scanner.get() 
     396        while not self.check_token(FlowSequenceEndToken): 
     397            if self.check_token(KeyToken): 
     398                token = self.get_token() 
    414399                yield MappingStartEvent(None, None, # u'!', 
    415400                        token.start_mark, token.end_mark, 
    416401                        flow_style=True) 
    417                 if not self.scanner.check(ValueToken, 
     402                if not self.check_token(ValueToken, 
    418403                        FlowEntryToken, FlowSequenceEndToken): 
    419404                    for event in self.parse_flow_node(): 
     
    421406                else: 
    422407                    yield self.process_empty_scalar(token.end_mark) 
    423                 if self.scanner.check(ValueToken): 
    424                     token = self.scanner.get() 
    425                     if not self.scanner.check(FlowEntryToken, FlowSequenceEndToken): 
     408                if self.check_token(ValueToken): 
     409                    token = self.get_token() 
     410                    if not self.check_token(FlowEntryToken, FlowSequenceEndToken): 
    426411                        for event in self.parse_flow_node(): 
    427412                            yield event 
     
    429414                        yield self.process_empty_scalar(token.end_mark) 
    430415                else: 
    431                     token = self.scanner.peek() 
     416                    token = self.peek_token() 
    432417                    yield self.process_empty_scalar(token.start_mark) 
    433                 token = self.scanner.peek() 
     418                token = self.peek_token() 
    434419                yield MappingEndEvent(token.start_mark, token.start_mark) 
    435420            else: 
    436421                for event in self.parse_flow_node(): 
    437422                    yield event 
    438             if not self.scanner.check(FlowEntryToken, FlowSequenceEndToken): 
    439                 token = self.scanner.peek() 
     423            if not self.check_token(FlowEntryToken, FlowSequenceEndToken): 
     424                token = self.peek_token() 
    440425                raise ParserError("while scanning a flow sequence", start_mark, 
    441426                        "expected ',' or ']', but got %r" % token.id, token.start_mark) 
    442             if self.scanner.check(FlowEntryToken): 
    443                 self.scanner.get() 
    444         token = self.scanner.get() 
     427            if self.check_token(FlowEntryToken): 
     428                self.get_token() 
     429        token = self.get_token() 
    445430        yield SequenceEndEvent(token.start_mark, token.end_mark) 
    446431 
     
    451436        #                       FLOW-MAPPING-END 
    452437        # flow_mapping_entry    ::= flow_node | KEY flow_node? (VALUE flow_node?)? 
    453         token = self.scanner.get() 
     438        token = self.get_token() 
    454439        start_mark = token.start_mark 
    455         while not self.scanner.check(FlowMappingEndToken): 
    456             if self.scanner.check(KeyToken): 
    457                 token = self.scanner.get() 
    458                 if not self.scanner.check(ValueToken, 
     440        while not self.check_token(FlowMappingEndToken): 
     441            if self.check_token(KeyToken): 
     442                token = self.get_token() 
     443                if not self.check_token(ValueToken, 
    459444                        FlowEntryToken, FlowMappingEndToken): 
    460445                    for event in self.parse_flow_node(): 
     
    462447                else: 
    463448                    yield self.process_empty_scalar(token.end_mark) 
    464                 if self.scanner.check(ValueToken): 
    465                     token = self.scanner.get() 
    466                     if not self.scanner.check(FlowEntryToken, FlowMappingEndToken): 
     449                if self.check_token(ValueToken): 
     450                    token = self.get_token() 
     451                    if not self.check_token(FlowEntryToken, FlowMappingEndToken): 
    467452                        for event in self.parse_flow_node(): 
    468453                            yield event 
     
    470455                        yield self.process_empty_scalar(token.end_mark) 
    471456                else: 
    472                     token = self.scanner.peek() 
     457                    token = self.peek_token() 
    473458                    yield self.process_empty_scalar(token.start_mark) 
    474459            else: 
    475460                for event in self.parse_flow_node(): 
    476461                    yield event 
    477                 yield self.process_empty_scalar(self.scanner.peek().start_mark) 
    478             if not self.scanner.check(FlowEntryToken, FlowMappingEndToken): 
    479                 token = self.scanner.peek() 
     462                yield self.process_empty_scalar(self.peek_token().start_mark) 
     463            if not self.check_token(FlowEntryToken, FlowMappingEndToken): 
     464                token = self.peek_token() 
    480465                raise ParserError("while scanning a flow mapping", start_mark, 
    481466                        "expected ',' or '}', but got %r" % token.id, token.start_mark) 
    482             if self.scanner.check(FlowEntryToken): 
    483                 self.scanner.get() 
    484         if not self.scanner.check(FlowMappingEndToken): 
    485             token = self.scanner.peek() 
     467            if self.check_token(FlowEntryToken): 
     468                self.get_token() 
     469        if not self.check_token(FlowMappingEndToken): 
     470            token = self.peek_token() 
    486471            raise ParserError("while scanning a flow mapping", start_mark, 
    487472                    "expected '}', but found %r" % token.id, token.start_mark) 
    488         token = self.scanner.get() 
     473        token = self.get_token() 
    489474        yield MappingEndEvent(token.start_mark, token.end_mark) 
    490475 
    491476    def process_empty_scalar(self, mark): 
    492         return ScalarEvent(None, None, u'', mark, mark, 
    493                 implicit=True) 
    494  
     477        return ScalarEvent(None, None, True, u'', mark, mark) 
     478 
  • pyyaml/trunk/lib/yaml/reader.py

    r130 r136  
    9292    # Yeah, it's ugly and slow. 
    9393 
    94     def __init__(self, data): 
     94    def __init__(self, stream): 
    9595        self.name = None 
    9696        self.stream = None 
     
    105105        self.line = 0 
    106106        self.column = 0 
    107         if isinstance(data, unicode): 
     107        if isinstance(stream, unicode): 
    108108            self.name = "<unicode string>" 
    109             self.check_printable(data) 
    110             self.buffer = data+u'\0' 
    111         elif isinstance(data, str): 
     109            self.check_printable(stream) 
     110            self.buffer = stream+u'\0' 
     111        elif isinstance(stream, str): 
    112112            self.name = "<string>" 
    113             self.raw_buffer = data 
     113            self.raw_buffer = stream 
    114114            self.determine_encoding() 
    115115        else: 
    116             self.stream = data 
    117             self.name = getattr(data, 'name', "<file>") 
     116            self.stream = stream 
     117            self.name = getattr(stream, 'name', "<file>") 
    118118            self.eof = False 
    119119            self.raw_buffer = '' 
  • pyyaml/trunk/lib/yaml/representer.py

    r135 r136  
    2121    pass 
    2222 
    23 class BaseRepresenter(BaseDetector): 
    24  
    25     DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str' 
    26     DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq' 
    27     DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map' 
    28  
    29     def __init__(self, serializer): 
    30         self.serializer = serializer 
     23class BaseRepresenter: 
     24 
     25    yaml_representers = {} 
     26 
     27    def __init__(self): 
    3128        self.represented_objects = {} 
    3229 
    33     def close(self): 
    34         self.serializer.close() 
    35  
    36     def represent(self, native): 
    37         node = self.represent_object(native) 
    38         self.serializer.serialize(node) 
     30    def represent(self, data): 
     31        node = self.represent_object(data) 
     32        self.serialize(node) 
    3933        self.represented_objects = {} 
    4034 
    41     def represent_object(self, native): 
    42         if self.ignore_aliases(native): 
     35    def represent_object(self, data): 
     36        if self.ignore_aliases(data): 
    4337            alias_key = None 
    4438        else: 
    45             alias_key = id(native) 
     39            alias_key = id(data) 
    4640        if alias_key is not None: 
    4741            if alias_key in self.represented_objects: 
    4842                node = self.represented_objects[alias_key] 
    4943                if node is None: 
    50                     raise RepresenterError("recursive objects are not allowed: %r" % native) 
     44                    raise RepresenterError("recursive objects are not allowed: %r" % data) 
    5145                return node 
    5246            self.represented_objects[alias_key] = None 
    53         for native_type in type(native).__mro__: 
    54             if native_type in self.yaml_representers: 
    55                 node = self.yaml_representers[native_type](self, native) 
     47        for data_type in type(data).__mro__: 
     48            if data_type in self.yaml_representers: 
     49                node = self.yaml_representers[data_type](self, data) 
    5650                break 
    5751        else: 
    5852            if None in self.yaml_representers: 
    59                 node = self.yaml_representers[None](self, native) 
     53                node = self.yaml_representers[None](self, data) 
    6054            else: 
    61                 node = ScalarNode(None, unicode(native)) 
     55                node = ScalarNode(None, unicode(data)) 
    6256        if alias_key is not None: 
    6357            self.represented_objects[alias_key] = node 
    6458        return node 
    6559 
    66     def add_representer(cls, native_type, representer): 
     60    def add_representer(cls, data_type, representer): 
    6761        if not 'yaml_representers' in cls.__dict__: 
    6862            cls.yaml_representers = cls.yaml_representers.copy() 
    69         cls.yaml_representers[native_type] = representer 
     63        cls.yaml_representers[data_type] = representer 
    7064    add_representer = classmethod(add_representer) 
    7165 
    72     yaml_representers = {} 
    73  
    7466    def represent_scalar(self, tag, value, style=None): 
    75         detected_tag = self.detect(value) 
    76         if detected_tag is None: 
    77             detected_tag = self.DEFAULT_SCALAR_TAG 
    78         implicit = (tag == detected_tag) 
    79         if tag == self.DEFAULT_SCALAR_TAG: 
    80             tag = None 
    81         return ScalarNode(tag, value, implicit=implicit, style=style) 
     67        return ScalarNode(tag, value, style=style) 
    8268 
    8369    def represent_sequence(self, tag, sequence, flow_style=None): 
    84         if tag == self.DEFAULT_SEQUENCE_TAG: 
    85             tag = None 
    8670        value = [] 
    8771        for item in sequence: 
     
    9074 
    9175    def represent_mapping(self, tag, mapping, flow_style=None): 
    92         if tag == self.DEFAULT_MAPPING_TAG: 
    93             tag = None 
    9476        value = {} 
    9577        if hasattr(mapping, 'keys'): 
     
    10486        return MappingNode(tag, value, flow_style=flow_style) 
    10587 
    106     def ignore_aliases(self, native): 
     88    def ignore_aliases(self, data): 
    10789        return False 
    10890 
    109 class SafeRepresenter(Detector, BaseRepresenter): 
    110  
    111     def ignore_aliases(self, native): 
    112         if native in [None, ()]: 
     91class SafeRepresenter(BaseRepresenter): 
     92 
     93    def ignore_aliases(self, data): 
     94        if data in [None, ()]: 
    11395            return True 
    114         if isinstance(native, (str, unicode, bool, int, float)): 
     96        if isinstance(data, (str, unicode, bool, int, float)): 
    11597            return True 
    11698 
    117     def represent_none(self, native): 
     99    def represent_none(self, data): 
    118100        return self.represent_scalar(u'tag:yaml.org,2002:null', 
    119101                u'null') 
    120102 
    121     def represent_str(self, native): 
     103    def represent_str(self, data): 
    122104        encoding = None 
    123105        try: 
    124             unicode(native, 'ascii') 
     106            unicode(data, 'ascii') 
    125107            encoding = 'ascii' 
    126108        except UnicodeDecodeError: 
    127109            try: 
    128                 unicode(native, 'utf-8') 
     110                unicode(data, 'utf-8') 
    129111                encoding = 'utf-8' 
    130112            except UnicodeDecodeError: 
     
    132114        if encoding: 
    133115            return self.represent_scalar(u'tag:yaml.org,2002:str', 
    134                     unicode(native, encoding)) 
     116                    unicode(data, encoding)) 
    135117        else: 
    136118            return self.represent_scalar(u'tag:yaml.org,2002:binary', 
    137                     unicode(native.encode('base64')), style='|') 
    138  
    139     def represent_unicode(self, native): 
    140         return self.represent_scalar(u'tag:yaml.org,2002:str', native) 
    141  
    142     def represent_bool(self, native): 
    143         if native: 
     119                    unicode(data.encode('base64')), style='|') 
     120 
     121    def represent_unicode(self, data): 
     122        return self.represent_scalar(u'tag:yaml.org,2002:str', data) 
     123 
     124    def represent_bool(self, data): 
     125        if data: 
    144126            value = u'true' 
    145127        else: 
     
    147129        return self.represent_scalar(u'tag:yaml.org,2002:bool', value) 
    148130 
    149     def represent_int(self, native): 
    150         return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(native)) 
    151  
    152     def represent_long(self, native): 
    153         return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(native)) 
     131    def represent_int(self, data): 
     132        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data)) 
     133 
     134    def represent_long(self, data): 
     135        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data)) 
    154136 
    155137    inf_value = 1e300000 
    156138    nan_value = inf_value/inf_value 
    157139 
    158     def represent_float(self, native): 
    159         if native == self.inf_value: 
     140    def represent_float(self, data): 
     141        if data == self.inf_value: 
    160142            value = u'.inf' 
    161         elif native == -self.inf_value: 
     143        elif data == -self.inf_value: 
    162144            value = u'-.inf' 
    163         elif native == self.nan_value or native != native: 
     145        elif data == self.nan_value or data != data: 
    164146            value = u'.nan' 
    165147        else: 
    166             value = unicode(native) 
     148            value = unicode(data) 
    167149        return self.represent_scalar(u'tag:yaml.org,2002:float', value) 
    168150 
    169     def represent_list(self, native): 
    170         pairs = (len(native) > 0) 
    171         for item in native: 
     151    def represent_list(self, data): 
     152        pairs = (len(data) > 0) 
     153        for item in data: 
    172154            if not isinstance(item, tuple) or len(item) != 2: 
    173155                pairs = False 
    174156                break 
    175157        if not pairs: 
    176             return self.represent_sequence(u'tag:yaml.org,2002:seq', native) 
     158            return self.represent_sequence(u'tag:yaml.org,2002:seq', data) 
    177159        value = [] 
    178         for item_key, item_value in native: 
     160        for item_key, item_value in data: 
    179161            value.append(self.represent_mapping(u'tag:yaml.org,2002:map', 
    180162                [(item_key, item_value)])) 
    181163        return SequenceNode(u'tag:yaml.org,2002:pairs', value) 
    182164 
    183     def represent_dict(self, native): 
    184         return self.represent_mapping(u'tag:yaml.org,2002:map', native) 
    185  
    186     def represent_set(self, native): 
     165    def represent_dict(self, data): 
     166        return self.represent_mapping(u'tag:yaml.org,2002:map', data) 
     167 
     168    def represent_set(self, data): 
    187169        value = {} 
    188         for key in native: 
     170        for key in data: 
    189171            value[key] = None 
    190172        return self.represent_mapping(u'tag:yaml.org,2002:set', value) 
    191173 
    192     def represent_date(self, native): 
    193         value = u'%04d-%02d-%02d' % (native.year, native.month, native.day) 
     174    def represent_date(self, data): 
     175        value = u'%04d-%02d-%02d' % (data.year, data.month, data.day) 
    194176        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) 
    195177 
    196     def represent_datetime(self, native): 
     178    def represent_datetime(self, data): 
    197179        value = u'%04d-%02d-%02d %02d:%02d:%02d' \ 
    198                 % (native.year, native.month, native.day, 
    199                     native.hour, native.minute, native.second) 
    200         if native.microsecond: 
    201             value += u'.' + unicode(native.microsecond/1000000.0).split(u'.')[1] 
    202         if native.utcoffset(): 
    203             value += unicode(native.utcoffset()) 
     180                % (data.year, data.month, data.day, 
     181                    data.hour, data.minute, data.second) 
     182        if data.microsecond: 
     183            value += u'.' + unicode(data.microsecond/1000000.0).split(u'.')[1] 
     184        if data.utcoffset(): 
     185            value += unicode(data.utcoffset()) 
    204186        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value) 
    205187 
    206     def represent_undefined(self, native): 
    207         raise RepresenterError("cannot represent an object: %s" % native) 
     188    def represent_yaml_object(self, tag, data, cls, flow_style=None): 
     189        if hasattr(data, '__getstate__'): 
     190            state = data.__getstate__() 
     191        else: 
     192            state = data.__dict__.copy() 
     193        mapping = state 
     194        if hasattr(state, 'keys'): 
     195            mapping = [] 
     196            keys = state.keys() 
     197            keys.sort() 
     198            for key in keys: 
     199                mapping.append((key.replace('_', '-'), state[key])) 
     200        return self.represent_mapping(tag, mapping, flow_style=flow_style) 
     201 
     202    def represent_undefined(self, data): 
     203        raise RepresenterError("cannot represent an object: %s" % data) 
    208204 
    209205SafeRepresenter.add_representer(type(None), 
  • pyyaml/trunk/lib/yaml/scanner.py

    r132 r136  
    4646class Scanner: 
    4747 
    48  
    49     def __init__(self, reader): 
     48    def __init__(self): 
    5049        """Initialize the scanner.""" 
    51         # The input stream. The Reader class do the dirty work of checking for 
    52         # BOM and converting the input data to Unicode. It also adds NUL to 
    53         # the end. 
     50        # It is assumed that Scanner and Reader will have a common descendant. 
     51        # Reader do the dirty work of checking for BOM and converting the 
     52        # input data to Unicode. It also adds NUL to the end. 
    5453        # 
    5554        # Reader supports the following methods 
    56         #   self.reader.peek(i=0)       # peek the next i-th character 
    57         #   self.reader.prefix(l=1)     # peek the next l characters 
    58         #   self.reader.forward(l=1)    # read the next l characters 
    59                                         # and move the pointer 
    60         self.reader = reader 
     55        #   self.peek(i=0)       # peek the next i-th character 
     56        #   self.prefix(l=1)     # peek the next l characters 
     57        #   self.forward(l=1)    # read the next l characters and move the pointer. 
    6158 
    6259        # Had we reached the end of the stream? 
     
    114111    # Public methods. 
    115112 
    116     def check(self, *choices): 
     113    def check_token(self, *choices): 
    117114        # Check if the next token is one of the given types. 
    118115        while self.need_more_tokens(): 
    119116            self.fetch_more_tokens() 
    120117        if self.tokens: 
     118            if not choices: 
     119                return True 
    121120            for choice in choices: 
    122121                if isinstance(self.tokens[0], choice): 
     
    124123        return False 
    125124 
    126     def peek(self): 
     125    def peek_token(self): 
    127126        # Return the next token, but do not delete if from the queue. 
    128127        while self.need_more_tokens(): 
     
    131130            return self.tokens[0] 
    132131 
    133     def get(self): 
     132    def get_token(self): 
    134133        # Return the next token. 
    135134        while self.need_more_tokens(): 
     
    172171        # Compare the current indentation and column. It may add some tokens 
    173172        # and decrease the current indentation level. 
    174         self.unwind_indent(self.reader.column) 
     173        self.unwind_indent(self.column) 
    175174 
    176175        # Peek the next character. 
    177         ch = self.reader.peek() 
     176        ch = self.peek() 
    178177 
    179178        # Is it the end of stream? 
     
    266265        raise ScannerError("while scanning for the next token", None, 
    267266                "found character %r that cannot start any token" 
    268                 % ch.encode('utf-8'), self.reader.get_mark()) 
     267                % ch.encode('utf-8'), self.get_mark()) 
    269268 
    270269    # Simple keys treatment. 
     
    294293        for level in self.possible_simple_keys.keys(): 
    295294            key = self.possible_simple_keys[level] 
    296             if key.line != self.reader.line  \ 
    297                     or self.reader.index-key.index > 1024: 
     295            if key.line != self.line  \ 
     296                    or self.index-key.index > 1024: 
    298297                if key.required: 
    299298                    raise ScannerError("while scanning a simple key", key.mark, 
    300                             "could not found expected ':'", self.reader.get_mark()) 
     299                            "could not found expected ':'", self.get_mark()) 
    301300                del self.possible_simple_keys[level] 
    302301 
     
    307306 
    308307        # Check if a simple key is required at the current position. 
    309         required = not self.flow_level and self.indent == self.reader.column 
     308        required = not self.flow_level and self.indent == self.column 
    310309 
    311310        # A simple key is required only if it is the first token in the current 
     
    318317            self.remove_possible_simple_key() 
    319318            token_number = self.tokens_taken+len(self.tokens) 
    320             index = self.reader.index 
    321             line = self.reader.line 
    322             column = self.reader.column 
    323             mark = self.reader.get_mark() 
    324319            key = SimpleKey(token_number, required, 
    325                     index, line, column, mark) 
     320                    self.index, self.line, self.column, self.get_mark()) 
    326321            self.possible_simple_keys[self.flow_level] = key 
    327322 
     
    335330            #if key.required: 
    336331            #    raise ScannerError("while scanning a simple key", key.mark, 
    337             #            "could not found expected ':'", self.reader.get_mark()) 
     332            #            "could not found expected ':'", self.get_mark()) 
    338333 
    339334    # Indentation functions. 
     
    350345        #    raise ScannerError(None, None, 
    351346        #            "invalid intendation or unclosed '[' or '{'",