source: pyyaml/trunk/lib/yaml/resolver.py @ 222

Revision 222, 7.6 KB checked in by xi, 8 years ago (diff)

Subclass all base classes from object.

Hold references to the objects being represented (should fix #22).

The value of a mapping node is represented as a list of pairs (key, value)
now.

Sort dictionary items (fix #23).

Recursive structures are now loaded and dumped correctly, including complex
structures like recursive tuples (fix #5). Thanks Peter Murphy for the patches.
To make it possible, representer functions are allowed to be generators.
In this case, the first generated value is an object. Other values produced
by the representer are ignored.

Make Representer not try to guess !!pairs when a list is represented.
You need to construct a !!pairs node explicitly now.

Do not check for duplicate mapping keys as it didn't work correctly anyway.

Line 
1
2__all__ = ['BaseResolver', 'Resolver']
3
4from error import *
5from nodes import *
6
7import re
8
9class ResolverError(YAMLError):
10    pass
11
12class BaseResolver(object):
13
14    DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
15    DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq'
16    DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
17
18    yaml_implicit_resolvers = {}
19    yaml_path_resolvers = {}
20
21    def __init__(self):
22        self.resolver_exact_paths = []
23        self.resolver_prefix_paths = []
24
25    def add_implicit_resolver(cls, tag, regexp, first):
26        if not 'yaml_implicit_resolvers' in cls.__dict__:
27            cls.yaml_implicit_resolvers = cls.yaml_implicit_resolvers.copy()
28        if first is None:
29            first = [None]
30        for ch in first:
31            cls.yaml_implicit_resolvers.setdefault(ch, []).append((tag, regexp))
32    add_implicit_resolver = classmethod(add_implicit_resolver)
33
34    def add_path_resolver(cls, tag, path, kind=None):
35        if not 'yaml_path_resolvers' in cls.__dict__:
36            cls.yaml_path_resolvers = cls.yaml_path_resolvers.copy()
37        new_path = []
38        for element in path:
39            if isinstance(element, (list, tuple)):
40                if len(element) == 2:
41                    node_check, index_check = element
42                elif len(element) == 1:
43                    node_check = element[0]
44                    index_check = True
45                else:
46                    raise ResolverError("Invalid path element: %s" % element)
47            else:
48                node_check = None
49                index_check = element
50            if node_check is str:
51                node_check = ScalarNode
52            elif node_check is list:
53                node_check = SequenceNode
54            elif node_check is dict:
55                node_check = MappingNode
56            elif node_check not in [ScalarNode, SequenceNode, MappingNode]  \
57                    and not isinstance(node_check, basestring)  \
58                    and node_check is not None:
59                raise ResolverError("Invalid node checker: %s" % node_check)
60            if not isinstance(index_check, (basestring, int))   \
61                    and index_check is not None:
62                raise ResolverError("Invalid index checker: %s" % index_check)
63            new_path.append((node_check, index_check))
64        if kind is str:
65            kind = ScalarNode
66        elif kind is list:
67            kind = SequenceNode
68        elif kind is dict:
69            kind = MappingNode
70        elif kind not in [ScalarNode, SequenceNode, MappingNode]    \
71                and kind is not None:
72            raise ResolverError("Invalid node kind: %s" % kind)
73        cls.yaml_path_resolvers[tuple(new_path), kind] = tag
74    add_path_resolver = classmethod(add_path_resolver)
75
76    def descend_resolver(self, current_node, current_index):
77        exact_paths = {}
78        prefix_paths = []
79        if current_node:
80            depth = len(self.resolver_prefix_paths)
81            for path, kind in self.resolver_prefix_paths[-1]:
82                if self.check_resolver_prefix(depth, path, kind,
83                        current_node, current_index):
84                    if len(path) > depth:
85                        prefix_paths.append((path, kind))
86                    else:
87                        exact_paths[kind] = self.yaml_path_resolvers[path, kind]
88        else:
89            for path, kind in self.yaml_path_resolvers:
90                if not path:
91                    exact_paths[kind] = self.yaml_path_resolvers[path, kind]
92                else:
93                    prefix_paths.append((path, kind))
94        self.resolver_exact_paths.append(exact_paths)
95        self.resolver_prefix_paths.append(prefix_paths)
96
97    def ascend_resolver(self):
98        self.resolver_exact_paths.pop()
99        self.resolver_prefix_paths.pop()
100
101    def check_resolver_prefix(self, depth, path, kind,
102            current_node, current_index):
103        node_check, index_check = path[depth-1]
104        if isinstance(node_check, basestring):
105            if current_node.tag != node_check:
106                return
107        elif node_check is not None:
108            if not isinstance(current_node, node_check):
109                return
110        if index_check is True and current_index is not None:
111            return
112        if index_check in [False, None] and current_index is None:
113            return
114        if isinstance(index_check, basestring):
115            if not (isinstance(current_index, ScalarNode)
116                    and index_check == current_index.value):
117                return
118        elif isinstance(index_check, int):
119            if index_check != current_index:
120                return
121        return True
122
123    def resolve(self, kind, value, implicit):
124        if kind is ScalarNode and implicit[0]:
125            if value == u'':
126                resolvers = self.yaml_implicit_resolvers.get(u'', [])
127            else:
128                resolvers = self.yaml_implicit_resolvers.get(value[0], [])
129            resolvers += self.yaml_implicit_resolvers.get(None, [])
130            for tag, regexp in resolvers:
131                if regexp.match(value):
132                    return tag
133            implicit = implicit[1]
134        exact_paths = self.resolver_exact_paths[-1]
135        if kind in exact_paths:
136            return exact_paths[kind]
137        if None in exact_paths:
138            return exact_paths[None]
139        if kind is ScalarNode:
140            return self.DEFAULT_SCALAR_TAG
141        elif kind is SequenceNode:
142            return self.DEFAULT_SEQUENCE_TAG
143        elif kind is MappingNode:
144            return self.DEFAULT_MAPPING_TAG
145
146class Resolver(BaseResolver):
147    pass
148
149Resolver.add_implicit_resolver(
150        u'tag:yaml.org,2002:bool',
151        re.compile(ur'''^(?:yes|Yes|YES|n|N|no|No|NO
152                    |true|True|TRUE|false|False|FALSE
153                    |on|On|ON|off|Off|OFF)$''', re.X),
154        list(u'yYnNtTfFoO'))
155
156Resolver.add_implicit_resolver(
157        u'tag:yaml.org,2002:float',
158        re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)?\.[0-9_]*(?:[eE][-+][0-9]+)?
159                    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
160                    |[-+]?\.(?:inf|Inf|INF)
161                    |\.(?:nan|NaN|NAN))$''', re.X),
162        list(u'-+0123456789.'))
163
164Resolver.add_implicit_resolver(
165        u'tag:yaml.org,2002:int',
166        re.compile(ur'''^(?:[-+]?0b[0-1_]+
167                    |[-+]?0[0-7_]+
168                    |[-+]?(?:0|[1-9][0-9_]*)
169                    |[-+]?0x[0-9a-fA-F_]+
170                    |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
171        list(u'-+0123456789'))
172
173Resolver.add_implicit_resolver(
174        u'tag:yaml.org,2002:merge',
175        re.compile(ur'^(?:<<)$'),
176        ['<'])
177
178Resolver.add_implicit_resolver(
179        u'tag:yaml.org,2002:null',
180        re.compile(ur'''^(?: ~
181                    |null|Null|NULL
182                    | )$''', re.X),
183        [u'~', u'n', u'N', u''])
184
185Resolver.add_implicit_resolver(
186        u'tag:yaml.org,2002:timestamp',
187        re.compile(ur'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
188                    |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
189                     (?:[Tt]|[ \t]+)[0-9][0-9]?
190                     :[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
191                     (?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
192        list(u'0123456789'))
193
194Resolver.add_implicit_resolver(
195        u'tag:yaml.org,2002:value',
196        re.compile(ur'^(?:=)$'),
197        ['='])
198
199# The following resolver is only for documentation purposes. It cannot work
200# because plain scalars cannot start with '!', '&', or '*'.
201Resolver.add_implicit_resolver(
202        u'tag:yaml.org,2002:yaml',
203        re.compile(ur'^(?:!|&|\*)$'),
204        list(u'!&*'))
205
Note: See TracBrowser for help on using the repository browser.