2 __all__
= ['BaseConstructor', 'SafeConstructor', 'Constructor',
11 datetime_available
= True
13 datetime_available
= False
18 from sets
import Set
as set
20 import binascii
, re
, sys
22 class ConstructorError(MarkedYAMLError
):
25 class BaseConstructor(Composer
):
27 yaml_constructors
= {}
28 yaml_multi_constructors
= {}
31 self
.constructed_objects
= {}
34 # If there are more documents available?
35 return self
.check_node()
38 # Construct and return the next document.
40 return self
.construct_document(self
.get_node())
44 while self
.check_node():
45 yield self
.construct_document(self
.get_node())
47 def construct_document(self
, node
):
48 data
= self
.construct_object(node
)
49 self
.constructed_objects
= {}
52 def construct_object(self
, node
):
53 if node
in self
.constructed_objects
:
54 return self
.constructed_objects
[node
]
56 if node
.tag
in self
.yaml_constructors
:
57 constructor
= lambda node
: self
.yaml_constructors
[node
.tag
](self
, node
)
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
)
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
80 data
= constructor(node
)
81 self
.constructed_objects
[node
] = data
84 def construct_scalar(self
, node
):
85 if not isinstance(node
, ScalarNode
):
86 if isinstance(node
, MappingNode
):
87 for key_node
in node
.value
:
88 if key_node
.tag
== u
'tag:yaml.org,2002:value':
89 return self
.construct_scalar(node
.value
[key_node
])
90 raise ConstructorError(None, None,
91 "expected a scalar node, but found %s" % node
.id,
95 def construct_sequence(self
, node
):
96 if not isinstance(node
, SequenceNode
):
97 raise ConstructorError(None, None,
98 "expected a sequence node, but found %s" % node
.id,
100 return [self
.construct_object(child
) for child
in node
.value
]
102 def construct_mapping(self
, node
):
103 if not isinstance(node
, MappingNode
):
104 raise ConstructorError(None, None,
105 "expected a mapping node, but found %s" % node
.id,
109 for key_node
in node
.value
:
110 if key_node
.tag
== u
'tag:yaml.org,2002:merge':
111 if merge
is not None:
112 raise ConstructorError("while constructing a mapping", node
.start_mark
,
113 "found duplicate merge key", key_node
.start_mark
)
114 value_node
= node
.value
[key_node
]
115 if isinstance(value_node
, MappingNode
):
116 merge
= [self
.construct_mapping(value_node
)]
117 elif isinstance(value_node
, SequenceNode
):
119 for subnode
in value_node
.value
:
120 if not isinstance(subnode
, MappingNode
):
121 raise ConstructorError("while constructing a mapping",
123 "expected a mapping for merging, but found %s"
124 % subnode
.id, subnode
.start_mark
)
125 merge
.append(self
.construct_mapping(subnode
))
128 raise ConstructorError("while constructing a mapping", node
.start_mark
,
129 "expected a mapping or list of mappings for merging, but found %s"
130 % value_node
.id, value_node
.start_mark
)
131 elif key_node
.tag
== u
'tag:yaml.org,2002:value':
133 raise ConstructorError("while construction a mapping", node
.start_mark
,
134 "found duplicate value key", key_node
.start_mark
)
135 value
= self
.construct_object(node
.value
[key_node
])
138 key
= self
.construct_object(key_node
)
140 duplicate_key
= key
in mapping
141 except TypeError, exc
:
142 raise ConstructorError("while constructing a mapping", node
.start_mark
,
143 "found unacceptable key (%s)" % exc
, key_node
.start_mark
)
145 raise ConstructorError("while constructing a mapping", node
.start_mark
,
146 "found duplicate key", key_node
.start_mark
)
147 value
= self
.construct_object(node
.value
[key_node
])
149 if merge
is not None:
150 merge
.append(mapping
)
152 for submapping
in merge
:
153 mapping
.update(submapping
)
156 def construct_pairs(self
, node
):
157 if not isinstance(node
, MappingNode
):
158 raise ConstructorError(None, None,
159 "expected a mapping node, but found %s" % node
.id,
162 for key_node
in node
.value
:
163 key
= self
.construct_object(key_node
)
164 value
= self
.construct_object(node
.value
[key_node
])
165 pairs
.append((key
, value
))
168 def add_constructor(cls
, tag
, constructor
):
169 if not 'yaml_constructors' in cls
.__dict
__:
170 cls
.yaml_constructors
= cls
.yaml_constructors
.copy()
171 cls
.yaml_constructors
[tag
] = constructor
172 add_constructor
= classmethod(add_constructor
)
174 def add_multi_constructor(cls
, tag_prefix
, multi_constructor
):
175 if not 'yaml_multi_constructors' in cls
.__dict
__:
176 cls
.yaml_multi_constructors
= cls
.yaml_multi_constructors
.copy()
177 cls
.yaml_multi_constructors
[tag_prefix
] = multi_constructor
178 add_multi_constructor
= classmethod(add_multi_constructor
)
180 class SafeConstructor(BaseConstructor
):
182 def construct_yaml_null(self
, node
):
183 self
.construct_scalar(node
)
195 def construct_yaml_bool(self
, node
):
196 value
= self
.construct_scalar(node
)
197 return self
.bool_values
[value
.lower()]
199 def construct_yaml_int(self
, node
):
200 value
= str(self
.construct_scalar(node
))
201 value
= value
.replace('_', '')
209 elif value
.startswith('0b'):
210 return sign
*int(value
[2:], 2)
211 elif value
.startswith('0x'):
212 return sign
*int(value
[2:], 16)
213 elif value
[0] == '0':
214 return sign
*int(value
, 8)
216 digits
= [int(part
) for part
in value
.split(':')]
225 return sign
*int(value
)
228 nan_value
= inf_value
/inf_value
230 def construct_yaml_float(self
, node
):
231 value
= str(self
.construct_scalar(node
))
232 value
= value
.replace('_', '')
238 if value
.lower() == '.inf':
239 return sign
*self
.inf_value
240 elif value
.lower() == '.nan':
241 return self
.nan_value
243 digits
= [float(part
) for part
in value
.split(':')]
254 def construct_yaml_binary(self
, node
):
255 value
= self
.construct_scalar(node
)
257 return str(value
).decode('base64')
258 except (binascii
.Error
, UnicodeEncodeError), exc
:
259 raise ConstructorError(None, None,
260 "failed to decode base64 data: %s" % exc
, node
.start_mark
)
262 timestamp_regexp
= re
.compile(
263 ur
'''^(?P<year>[0-9][0-9][0-9][0-9])
264 -(?P<month>[0-9][0-9]?)
265 -(?P<day>[0-9][0-9]?)
267 (?P<hour>[0-9][0-9]?)
268 :(?P<minute>[0-9][0-9])
269 :(?P<second>[0-9][0-9])
270 (?:\.(?P<fraction>[0-9]*))?
271 (?:[ \t]*(?:Z|(?P<tz_hour>[-+][0-9][0-9]?)
272 (?::(?P<tz_minute>[0-9][0-9])?)?))?)?$''', re
.X
)
274 def construct_yaml_timestamp(self
, node
):
275 value
= self
.construct_scalar(node
)
276 match
= self
.timestamp_regexp
.match(node
.value
)
277 values
= match
.groupdict()
280 values
[key
] = int(values
[key
])
283 fraction
= values
['fraction']
285 while 10*fraction
< 1000000:
287 values
['fraction'] = fraction
288 stamp
= datetime
.datetime(values
['year'], values
['month'], values
['day'],
289 values
['hour'], values
['minute'], values
['second'], values
['fraction'])
290 diff
= datetime
.timedelta(hours
=values
['tz_hour'], minutes
=values
['tz_minute'])
293 def construct_yaml_omap(self
, node
):
294 # Note: we do not check for duplicate keys, because it's too
296 if not isinstance(node
, SequenceNode
):
297 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
298 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
300 for subnode
in node
.value
:
301 if not isinstance(subnode
, MappingNode
):
302 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
303 "expected a mapping of length 1, but found %s" % subnode
.id,
305 if len(subnode
.value
) != 1:
306 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
307 "expected a single mapping item, but found %d items" % len(subnode
.value
),
309 key_node
= subnode
.value
.keys()[0]
310 key
= self
.construct_object(key_node
)
311 value
= self
.construct_object(subnode
.value
[key_node
])
312 omap
.append((key
, value
))
315 def construct_yaml_pairs(self
, node
):
316 # Note: the same code as `construct_yaml_omap`.
317 if not isinstance(node
, SequenceNode
):
318 raise ConstructorError("while constructing pairs", node
.start_mark
,
319 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
321 for subnode
in node
.value
:
322 if not isinstance(subnode
, MappingNode
):
323 raise ConstructorError("while constructing pairs", node
.start_mark
,
324 "expected a mapping of length 1, but found %s" % subnode
.id,
326 if len(subnode
.value
) != 1:
327 raise ConstructorError("while constructing pairs", node
.start_mark
,
328 "expected a single mapping item, but found %d items" % len(subnode
.value
),
330 key_node
= subnode
.value
.keys()[0]
331 key
= self
.construct_object(key_node
)
332 value
= self
.construct_object(subnode
.value
[key_node
])
333 pairs
.append((key
, value
))
336 def construct_yaml_set(self
, node
):
337 value
= self
.construct_mapping(node
)
340 def construct_yaml_str(self
, node
):
341 value
= self
.construct_scalar(node
)
344 except UnicodeEncodeError:
347 def construct_yaml_seq(self
, node
):
348 return self
.construct_sequence(node
)
350 def construct_yaml_map(self
, node
):
351 return self
.construct_mapping(node
)
353 def construct_yaml_object(self
, node
, cls
):
354 state
= self
.construct_mapping(node
)
355 data
= cls
.__new
__(cls
)
356 if hasattr(data
, '__setstate__'):
357 data
.__setstate
__(state
)
359 data
.__dict
__.update(state
)
362 def construct_undefined(self
, node
):
363 raise ConstructorError(None, None,
364 "could not determine a constructor for the tag %r" % node
.tag
.encode('utf-8'),
367 SafeConstructor
.add_constructor(
368 u
'tag:yaml.org,2002:null',
369 SafeConstructor
.construct_yaml_null
)
371 SafeConstructor
.add_constructor(
372 u
'tag:yaml.org,2002:bool',
373 SafeConstructor
.construct_yaml_bool
)
375 SafeConstructor
.add_constructor(
376 u
'tag:yaml.org,2002:int',
377 SafeConstructor
.construct_yaml_int
)
379 SafeConstructor
.add_constructor(
380 u
'tag:yaml.org,2002:float',
381 SafeConstructor
.construct_yaml_float
)
383 SafeConstructor
.add_constructor(
384 u
'tag:yaml.org,2002:binary',
385 SafeConstructor
.construct_yaml_binary
)
387 if datetime_available
:
388 SafeConstructor
.add_constructor(
389 u
'tag:yaml.org,2002:timestamp',
390 SafeConstructor
.construct_yaml_timestamp
)
392 SafeConstructor
.add_constructor(
393 u
'tag:yaml.org,2002:omap',
394 SafeConstructor
.construct_yaml_omap
)
396 SafeConstructor
.add_constructor(
397 u
'tag:yaml.org,2002:pairs',
398 SafeConstructor
.construct_yaml_pairs
)
400 SafeConstructor
.add_constructor(
401 u
'tag:yaml.org,2002:set',
402 SafeConstructor
.construct_yaml_set
)
404 SafeConstructor
.add_constructor(
405 u
'tag:yaml.org,2002:str',
406 SafeConstructor
.construct_yaml_str
)
408 SafeConstructor
.add_constructor(
409 u
'tag:yaml.org,2002:seq',
410 SafeConstructor
.construct_yaml_seq
)
412 SafeConstructor
.add_constructor(
413 u
'tag:yaml.org,2002:map',
414 SafeConstructor
.construct_yaml_map
)
416 SafeConstructor
.add_constructor(None,
417 SafeConstructor
.construct_undefined
)
419 class Constructor(SafeConstructor
):
421 def construct_python_str(self
, node
):
422 return self
.construct_scalar(node
).encode('utf-8')
424 def construct_python_unicode(self
, node
):
425 return self
.construct_scalar(node
)
427 def construct_python_long(self
, node
):
428 return long(self
.construct_yaml_int(node
))
430 def construct_python_complex(self
, node
):
431 return complex(self
.construct_scalar(node
))
433 def construct_python_tuple(self
, node
):
434 return tuple(self
.construct_yaml_seq(node
))
436 def find_python_module(self
, name
, mark
):
438 raise ConstructorError("while constructing a Python module", mark
,
439 "expected non-empty name appended to the tag", mark
)
442 except ImportError, exc
:
443 raise ConstructorError("while constructing a Python module", mark
,
444 "cannot find module %r (%s)" % (name
.encode('utf-8'), exc
), mark
)
445 return sys
.modules
[name
]
447 def find_python_name(self
, name
, mark
):
449 raise ConstructorError("while constructing a Python object", mark
,
450 "expected non-empty name appended to the tag", mark
)
452 module_name
, object_name
= name
.rsplit('.', 1)
454 module_name
= '__builtin__'
457 __import__(module_name
)
458 except ImportError, exc
:
459 raise ConstructorError("while constructing a Python object", mark
,
460 "cannot find module %r (%s)" % (module_name
.encode('utf-8'), exc
), mark
)
461 module
= sys
.modules
[module_name
]
462 if not hasattr(module
, object_name
):
463 raise ConstructorError("while constructing a Python object", mark
,
464 "cannot find %r in the module %r" % (object_name
.encode('utf-8'),
465 module
.__name
__), mark
)
466 return getattr(module
, object_name
)
468 def construct_python_name(self
, suffix
, node
):
469 value
= self
.construct_scalar(node
)
471 raise ConstructorError("while constructing a Python name", node
.start_mark
,
472 "expected the empty value, but found %r" % value
.encode('utf-8'),
474 return self
.find_python_name(suffix
, node
.start_mark
)
476 def construct_python_module(self
, suffix
, node
):
477 value
= self
.construct_scalar(node
)
479 raise ConstructorError("while constructing a Python module", node
.start_mark
,
480 "expected the empty value, but found %r" % value
.encode('utf-8'),
482 return self
.find_python_module(suffix
, node
.start_mark
)
484 Constructor
.add_constructor(
485 u
'tag:yaml.org,2002:python/none',
486 Constructor
.construct_yaml_null
)
488 Constructor
.add_constructor(
489 u
'tag:yaml.org,2002:python/bool',
490 Constructor
.construct_yaml_bool
)
492 Constructor
.add_constructor(
493 u
'tag:yaml.org,2002:python/str',
494 Constructor
.construct_python_str
)
496 Constructor
.add_constructor(
497 u
'tag:yaml.org,2002:python/unicode',
498 Constructor
.construct_python_unicode
)
500 Constructor
.add_constructor(
501 u
'tag:yaml.org,2002:python/int',
502 Constructor
.construct_yaml_int
)
504 Constructor
.add_constructor(
505 u
'tag:yaml.org,2002:python/long',
506 Constructor
.construct_python_long
)
508 Constructor
.add_constructor(
509 u
'tag:yaml.org,2002:python/float',
510 Constructor
.construct_yaml_float
)
512 Constructor
.add_constructor(
513 u
'tag:yaml.org,2002:python/complex',
514 Constructor
.construct_python_complex
)
516 Constructor
.add_constructor(
517 u
'tag:yaml.org,2002:python/list',
518 Constructor
.construct_yaml_seq
)
520 Constructor
.add_constructor(
521 u
'tag:yaml.org,2002:python/tuple',
522 Constructor
.construct_python_tuple
)
524 Constructor
.add_constructor(
525 u
'tag:yaml.org,2002:python/dict',
526 Constructor
.construct_yaml_map
)
528 Constructor
.add_multi_constructor(
529 u
'tag:yaml.org,2002:python/name:',
530 Constructor
.construct_python_name
)
532 Constructor
.add_multi_constructor(
533 u
'tag:yaml.org,2002:python/module:',
534 Constructor
.construct_python_module
)