source: branches/pyyaml3000/lib/yaml/constructor.py @ 55

Revision 55, 8.0 KB checked in by xi, 8 years ago (diff)

Working on Constructor.

RevLine 
[55]1
2from error import *
3from nodes import *
4
5try:
6    import datetime
7    datetime_available = True
8except ImportError:
9    datetime_available = False
10
11try:
12    set
13except NameError:
14    from sets import Set as set
15
16import binascii
17
18class ConstructorError(MarkedYAMLError):
19    pass
20
21class BaseConstructor:
22
23    def __init__(self, resolver):
24        self.resolver = resolver
25        self.constructed_objects = {}
26
27    def check(self):
28        # If there are more documents available?
29        return self.resolver.check()
30
31    def get(self):
32        # Construct and return the next document.
33        if self.resolver.check():
34            return self.construct_document(self.resolver.get())
35
36    def __iter__(self):
37        # Iterator protocol.
38        while self.resolver.check():
39            yield self.construct_document(self.resolver.get())
40
41    def construct_document(self, node):
42        native = self.construct_object(node)
43        self.constructed_objects = {}
44        return native
45
46    def construct_object(self, node):
47        if node in self.constructed_objects:
48            return self.constructed_objects[node]
49        if node.tag in self.yaml_constructors:
50            native = self.yaml_constructors[node.tag](self, node)
51        elif None in self.yaml_constructors:
52            native = self.yaml_constructors[None](self, node)
53        elif isinstance(node, ScalarNode):
54            native = self.construct_scalar(node)
55        elif isinstance(node, SequenceNode):
56            native = self.construct_sequence(node)
57        elif isinstance(node, MappingNode):
58            native = self.construct_mapping(node)
59        self.constructed_objects[node] = native
60        return native
61
62    def construct_scalar(self, node):
63        if not isinstance(node, ScalarNode):
64            if isinstance(node, MappingNode):
65                for key_node in node.value:
66                    if key_node.tag == u'tag:yaml.org,2002:value':
67                        return self.construct_scalar(node.value[key_node])
68            raise ConstructorError(None, None,
69                    "expected a scalar node, but found %s" % node.id,
70                    node.start_marker)
71        return node.value
72
73    def construct_sequence(self, node):
74        if not isinstance(node, SequenceNode):
75            raise ConstructorError(None, None,
76                    "expected a sequence node, but found %s" % node.id,
77                    node.start_marker)
78        return [self.construct_object(child) for child in node.value]
79
80    def construct_mapping(self, node):
81        if not isinstance(node, MappingNode):
82            raise ConstructorError(None, None,
83                    "expected a mapping node, but found %s" % node.id,
84                    node.start_marker)
85        mapping = {}
86        for key_node in node.value:
87            key = self.construct_object(key_node)
88            try:
89                duplicate_key = key in mapping
90            except TypeError, exc:
91                raise ConstructorError("while constructing a mapping", node.start_marker,
92                        "found unacceptable key (%s)" % exc, key_node.start_marker)
93            if duplicate_key:
94                raise ConstructorError("while constructing a mapping", node.start_marker,
95                        "found duplicate key", key_node.start_marker)
96            value = self.construct_object(node.value[key_node])
97            mapping[key] = value
98        return mapping
99
100    def construct_pairs(self, node):
101        if not isinstance(node, MappingNode):
102            raise ConstructorError(None, None,
103                    "expected a mapping node, but found %s" % node.id,
104                    node.start_marker)
105        pairs = []
106        for key_node in node.value:
107            key = self.construct_object(key_node)
108            value = self.construct_object(node.value[key_node])
109            pairs.append((key, value))
110        return pairs
111
112    def add_constructor(cls, tag, constructor):
113        if not 'yaml_constructors' in cls.__dict__:
114            cls.yaml_constructors = cls.yaml_constructors.copy()
115        cls.yaml_constructors[tag] = constructor
116    add_constructor = classmethod(add_constructor)
117
118    yaml_constructors = {}
119
120class Constructor(BaseConstructor):
121
122    def construct_yaml_null(self, node):
123        self.construct_scalar(node)
124        return None
125
126    bool_values = {
127        u'y':       True,
128        u'yes':     True,
129        u'n':       False,
130        u'no':      False,
131        u'true':    True,
132        u'false':   False,
133        u'on':      True,
134        u'off':     False,
135    }
136
137    def construct_yaml_bool(self, node):
138        value = self.construct_scalar(node)
139        return self.bool_values[value.lower()]
140
141    def construct_yaml_int(self, node):
142        value = str(self.construct_scalar(node))
143        value = value.replace('_', '')
144        sign = +1
145        if value[0] == '-':
146            sign = -1
147        if value[0] in '+-':
148            value = value[1:]
149        if value == '0':
150            return 0
151        elif value.startswith('0b'):
152            return sign*int(value[2:], 2)
153        elif value.startswith('0x'):
154            return sign*int(value[2:], 16)
155        elif value[0] == '0':
156            return sign*int(value, 8)
157        elif ':' in value:
158            digits = [int(part) for part in value.split(':')]
159            digits.reverse()
160            base = 1
161            value = 0
162            for digit in digits:
163                value += digit*base
164                base *= 60
165            return sign*value
166        else:
167            return sign*int(value)
168
169    inf_value = 1e300000
170    nan_value = inf_value/inf_value
171
172    def construct_yaml_float(self, node):
173        value = str(self.construct_scalar(node))
174        value = value.replace('_', '')
175        sign = +1
176        if value[0] == '-':
177            value = -1
178        if value[0] in '+-':
179            value = value[1:]
180        if value.lower() == '.inf':
181            return sign*self.inf_value
182        elif value.lower() == '.nan':
183            return self.nan_value
184        elif ':' in value:
185            digits = [float(part) for part in value.split(':')]
186            digits.reverse()
187            base = 1
188            value = 0.0
189            for digit in digits:
190                value += digit*base
191                base *= 60
192            return sign*value
193        else:
194            return float(value)
195
196    def construct_yaml_binary(self, node):
197        value = self.construct_scalar(node)
198        try:
199            return str(value).decode('base64')
200        except (binascii.Error, UnicodeEncodeError), exc:
201            raise ConstructorError(None, None,
202                    "failed to decode base64 data: %s" % exc, node.start_mark) 
203
204    def construct_yaml_str(self, node):
205        value = self.construct_scalar(node)
206        try:
207            return str(value)
208        except UnicodeEncodeError:
209            return value
210
211Constructor.add_constructor(
212        u'tag:yaml.org,2002:null',
213        Constructor.construct_yaml_null)
214
215Constructor.add_constructor(
216        u'tag:yaml.org,2002:bool',
217        Constructor.construct_yaml_bool)
218
219Constructor.add_constructor(
220        u'tag:yaml.org,2002:int',
221        Constructor.construct_yaml_int)
222
223Constructor.add_constructor(
224        u'tag:yaml.org,2002:float',
225        Constructor.construct_yaml_float)
226
227Constructor.add_constructor(
228        u'tag:yaml.org,2002:str',
229        Constructor.construct_yaml_str)
230
231class YAMLObjectMetaclass(type):
232
233    def __init__(cls, name, bases, kwds):
234        super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
235        if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
236            cls.yaml_constructor_class.add_constructor(cls.yaml_tag, cls.from_yaml)
237
238class YAMLObject(object):
239
240    __metaclass__ = YAMLObjectMetaclass
241
242    yaml_constructor_class = Constructor
243
244    yaml_tag = None
245
246    def from_yaml(cls, constructor, node):
247        raise ConstructorError(None, None,
248                "found undefined constructor for the tag %r"
249                % node.tag.encode('utf-8'), node.start_marker)
250    from_yaml = classmethod(from_yaml)
251
252    def to_yaml(self):
253        assert False    # needs dumper
254
Note: See TracBrowser for help on using the repository browser.