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
= {}
32 self
.recursive_objects
= {}
35 # If there are more documents available?
36 return self
.check_node()
39 # Construct and return the next document.
41 return self
.construct_document(self
.get_node())
45 while self
.check_node():
46 yield self
.construct_document(self
.get_node())
48 def construct_document(self
, node
):
49 data
= self
.construct_object(node
)
50 self
.constructed_objects
= {}
51 self
.recursive_objects
= {}
54 def construct_object(self
, node
):
55 if node
in self
.constructed_objects
:
56 return self
.constructed_objects
[node
]
57 if node
in self
.recursive_objects
:
58 raise ConstructorError(None, None,
59 "found recursive node", node
.start_mark
)
60 self
.recursive_objects
[node
] = None
62 if node
.tag
in self
.yaml_constructors
:
63 constructor
= lambda node
: self
.yaml_constructors
[node
.tag
](self
, node
)
65 for tag_prefix
in self
.yaml_multi_constructors
:
66 if node
.tag
.startswith(tag_prefix
):
67 tag_suffix
= node
.tag
[len(tag_prefix
):]
68 constructor
= lambda node
: \
69 self
.yaml_multi_constructors
[tag_prefix
](self
, tag_suffix
, node
)
72 if None in self
.yaml_multi_constructors
:
73 constructor
= lambda node
: \
74 self
.yaml_multi_constructors
[None](self
, node
.tag
, node
)
75 elif None in self
.yaml_constructors
:
76 constructor
= lambda node
: \
77 self
.yaml_constructors
[None](self
, node
)
78 elif isinstance(node
, ScalarNode
):
79 constructor
= self
.construct_scalar
80 elif isinstance(node
, SequenceNode
):
81 constructor
= self
.construct_sequence
82 elif isinstance(node
, MappingNode
):
83 constructor
= self
.construct_mapping
86 data
= constructor(node
)
87 self
.constructed_objects
[node
] = data
88 del self
.recursive_objects
[node
]
91 def construct_scalar(self
, node
):
92 if not isinstance(node
, ScalarNode
):
93 if isinstance(node
, MappingNode
):
94 for key_node
in node
.value
:
95 if key_node
.tag
== u
'tag:yaml.org,2002:value':
96 return self
.construct_scalar(node
.value
[key_node
])
97 raise ConstructorError(None, None,
98 "expected a scalar node, but found %s" % node
.id,
102 def construct_sequence(self
, node
):
103 if not isinstance(node
, SequenceNode
):
104 raise ConstructorError(None, None,
105 "expected a sequence node, but found %s" % node
.id,
107 return [self
.construct_object(child
) for child
in node
.value
]
109 def construct_mapping(self
, node
):
110 if not isinstance(node
, MappingNode
):
111 raise ConstructorError(None, None,
112 "expected a mapping node, but found %s" % node
.id,
116 for key_node
in node
.value
:
117 if key_node
.tag
== u
'tag:yaml.org,2002:merge':
118 if merge
is not None:
119 raise ConstructorError("while constructing a mapping", node
.start_mark
,
120 "found duplicate merge key", key_node
.start_mark
)
121 value_node
= node
.value
[key_node
]
122 if isinstance(value_node
, MappingNode
):
123 merge
= [self
.construct_mapping(value_node
)]
124 elif isinstance(value_node
, SequenceNode
):
126 for subnode
in value_node
.value
:
127 if not isinstance(subnode
, MappingNode
):
128 raise ConstructorError("while constructing a mapping",
130 "expected a mapping for merging, but found %s"
131 % subnode
.id, subnode
.start_mark
)
132 merge
.append(self
.construct_mapping(subnode
))
135 raise ConstructorError("while constructing a mapping", node
.start_mark
,
136 "expected a mapping or list of mappings for merging, but found %s"
137 % value_node
.id, value_node
.start_mark
)
138 elif key_node
.tag
== u
'tag:yaml.org,2002:value':
140 raise ConstructorError("while construction a mapping", node
.start_mark
,
141 "found duplicate value key", key_node
.start_mark
)
142 value
= self
.construct_object(node
.value
[key_node
])
145 key
= self
.construct_object(key_node
)
147 duplicate_key
= key
in mapping
148 except TypeError, exc
:
149 raise ConstructorError("while constructing a mapping", node
.start_mark
,
150 "found unacceptable key (%s)" % exc
, key_node
.start_mark
)
152 raise ConstructorError("while constructing a mapping", node
.start_mark
,
153 "found duplicate key", key_node
.start_mark
)
154 value
= self
.construct_object(node
.value
[key_node
])
156 if merge
is not None:
157 merge
.append(mapping
)
159 for submapping
in merge
:
160 mapping
.update(submapping
)
163 def construct_pairs(self
, node
):
164 if not isinstance(node
, MappingNode
):
165 raise ConstructorError(None, None,
166 "expected a mapping node, but found %s" % node
.id,
169 for key_node
in node
.value
:
170 key
= self
.construct_object(key_node
)
171 value
= self
.construct_object(node
.value
[key_node
])
172 pairs
.append((key
, value
))
175 def add_constructor(cls
, tag
, constructor
):
176 if not 'yaml_constructors' in cls
.__dict
__:
177 cls
.yaml_constructors
= cls
.yaml_constructors
.copy()
178 cls
.yaml_constructors
[tag
] = constructor
179 add_constructor
= classmethod(add_constructor
)
181 def add_multi_constructor(cls
, tag_prefix
, multi_constructor
):
182 if not 'yaml_multi_constructors' in cls
.__dict
__:
183 cls
.yaml_multi_constructors
= cls
.yaml_multi_constructors
.copy()
184 cls
.yaml_multi_constructors
[tag_prefix
] = multi_constructor
185 add_multi_constructor
= classmethod(add_multi_constructor
)
187 class SafeConstructor(BaseConstructor
):
189 def construct_yaml_null(self
, node
):
190 self
.construct_scalar(node
)
202 def construct_yaml_bool(self
, node
):
203 value
= self
.construct_scalar(node
)
204 return self
.bool_values
[value
.lower()]
206 def construct_yaml_int(self
, node
):
207 value
= str(self
.construct_scalar(node
))
208 value
= value
.replace('_', '')
216 elif value
.startswith('0b'):
217 return sign
*int(value
[2:], 2)
218 elif value
.startswith('0x'):
219 return sign
*int(value
[2:], 16)
220 elif value
[0] == '0':
221 return sign
*int(value
, 8)
223 digits
= [int(part
) for part
in value
.split(':')]
232 return sign
*int(value
)
235 nan_value
= inf_value
/inf_value
237 def construct_yaml_float(self
, node
):
238 value
= str(self
.construct_scalar(node
))
239 value
= value
.replace('_', '')
245 if value
.lower() == '.inf':
246 return sign
*self
.inf_value
247 elif value
.lower() == '.nan':
248 return self
.nan_value
250 digits
= [float(part
) for part
in value
.split(':')]
261 def construct_yaml_binary(self
, node
):
262 value
= self
.construct_scalar(node
)
264 return str(value
).decode('base64')
265 except (binascii
.Error
, UnicodeEncodeError), exc
:
266 raise ConstructorError(None, None,
267 "failed to decode base64 data: %s" % exc
, node
.start_mark
)
269 timestamp_regexp
= re
.compile(
270 ur
'''^(?P<year>[0-9][0-9][0-9][0-9])
271 -(?P<month>[0-9][0-9]?)
272 -(?P<day>[0-9][0-9]?)
274 (?P<hour>[0-9][0-9]?)
275 :(?P<minute>[0-9][0-9])
276 :(?P<second>[0-9][0-9])
277 (?:\.(?P<fraction>[0-9]*))?
278 (?:[ \t]*(?:Z|(?P<tz_hour>[-+][0-9][0-9]?)
279 (?::(?P<tz_minute>[0-9][0-9])?)?))?)?$''', re
.X
)
281 def construct_yaml_timestamp(self
, node
):
282 value
= self
.construct_scalar(node
)
283 match
= self
.timestamp_regexp
.match(node
.value
)
284 values
= match
.groupdict()
287 values
[key
] = int(values
[key
])
290 fraction
= values
['fraction']
292 while 10*fraction
< 1000000:
294 values
['fraction'] = fraction
295 stamp
= datetime
.datetime(values
['year'], values
['month'], values
['day'],
296 values
['hour'], values
['minute'], values
['second'], values
['fraction'])
297 diff
= datetime
.timedelta(hours
=values
['tz_hour'], minutes
=values
['tz_minute'])
300 def construct_yaml_omap(self
, node
):
301 # Note: we do not check for duplicate keys, because it's too
303 if not isinstance(node
, SequenceNode
):
304 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
305 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
307 for subnode
in node
.value
:
308 if not isinstance(subnode
, MappingNode
):
309 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
310 "expected a mapping of length 1, but found %s" % subnode
.id,
312 if len(subnode
.value
) != 1:
313 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
314 "expected a single mapping item, but found %d items" % len(subnode
.value
),
316 key_node
= subnode
.value
.keys()[0]
317 key
= self
.construct_object(key_node
)
318 value
= self
.construct_object(subnode
.value
[key_node
])
319 omap
.append((key
, value
))
322 def construct_yaml_pairs(self
, node
):
323 # Note: the same code as `construct_yaml_omap`.
324 if not isinstance(node
, SequenceNode
):
325 raise ConstructorError("while constructing pairs", node
.start_mark
,
326 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
328 for subnode
in node
.value
:
329 if not isinstance(subnode
, MappingNode
):
330 raise ConstructorError("while constructing pairs", node
.start_mark
,
331 "expected a mapping of length 1, but found %s" % subnode
.id,
333 if len(subnode
.value
) != 1:
334 raise ConstructorError("while constructing pairs", node
.start_mark
,
335 "expected a single mapping item, but found %d items" % len(subnode
.value
),
337 key_node
= subnode
.value
.keys()[0]
338 key
= self
.construct_object(key_node
)
339 value
= self
.construct_object(subnode
.value
[key_node
])
340 pairs
.append((key
, value
))
343 def construct_yaml_set(self
, node
):
344 value
= self
.construct_mapping(node
)
347 def construct_yaml_str(self
, node
):
348 value
= self
.construct_scalar(node
)
351 except UnicodeEncodeError:
354 def construct_yaml_seq(self
, node
):
355 return self
.construct_sequence(node
)
357 def construct_yaml_map(self
, node
):
358 return self
.construct_mapping(node
)
360 def construct_yaml_object(self
, node
, cls
):
361 state
= self
.construct_mapping(node
)
362 data
= cls
.__new
__(cls
)
363 if hasattr(data
, '__setstate__'):
364 data
.__setstate
__(state
)
366 data
.__dict
__.update(state
)
369 def construct_undefined(self
, node
):
370 raise ConstructorError(None, None,
371 "could not determine a constructor for the tag %r" % node
.tag
.encode('utf-8'),
374 SafeConstructor
.add_constructor(
375 u
'tag:yaml.org,2002:null',
376 SafeConstructor
.construct_yaml_null
)
378 SafeConstructor
.add_constructor(
379 u
'tag:yaml.org,2002:bool',
380 SafeConstructor
.construct_yaml_bool
)
382 SafeConstructor
.add_constructor(
383 u
'tag:yaml.org,2002:int',
384 SafeConstructor
.construct_yaml_int
)
386 SafeConstructor
.add_constructor(
387 u
'tag:yaml.org,2002:float',
388 SafeConstructor
.construct_yaml_float
)
390 SafeConstructor
.add_constructor(
391 u
'tag:yaml.org,2002:binary',
392 SafeConstructor
.construct_yaml_binary
)
394 if datetime_available
:
395 SafeConstructor
.add_constructor(
396 u
'tag:yaml.org,2002:timestamp',
397 SafeConstructor
.construct_yaml_timestamp
)
399 SafeConstructor
.add_constructor(
400 u
'tag:yaml.org,2002:omap',
401 SafeConstructor
.construct_yaml_omap
)
403 SafeConstructor
.add_constructor(
404 u
'tag:yaml.org,2002:pairs',
405 SafeConstructor
.construct_yaml_pairs
)
407 SafeConstructor
.add_constructor(
408 u
'tag:yaml.org,2002:set',
409 SafeConstructor
.construct_yaml_set
)
411 SafeConstructor
.add_constructor(
412 u
'tag:yaml.org,2002:str',
413 SafeConstructor
.construct_yaml_str
)
415 SafeConstructor
.add_constructor(
416 u
'tag:yaml.org,2002:seq',
417 SafeConstructor
.construct_yaml_seq
)
419 SafeConstructor
.add_constructor(
420 u
'tag:yaml.org,2002:map',
421 SafeConstructor
.construct_yaml_map
)
423 SafeConstructor
.add_constructor(None,
424 SafeConstructor
.construct_undefined
)
426 class Constructor(SafeConstructor
):
428 def construct_python_str(self
, node
):
429 return self
.construct_scalar(node
).encode('utf-8')
431 def construct_python_unicode(self
, node
):
432 return self
.construct_scalar(node
)
434 def construct_python_long(self
, node
):
435 return long(self
.construct_yaml_int(node
))
437 def construct_python_complex(self
, node
):
438 return complex(self
.construct_scalar(node
))
440 def construct_python_tuple(self
, node
):
441 return tuple(self
.construct_yaml_seq(node
))
443 def find_python_module(self
, name
, mark
):
445 raise ConstructorError("while constructing a Python module", mark
,
446 "expected non-empty name appended to the tag", mark
)
449 except ImportError, exc
:
450 raise ConstructorError("while constructing a Python module", mark
,
451 "cannot find module %r (%s)" % (name
.encode('utf-8'), exc
), mark
)
452 return sys
.modules
[name
]
454 def find_python_name(self
, name
, mark
):
456 raise ConstructorError("while constructing a Python object", mark
,
457 "expected non-empty name appended to the tag", mark
)
459 module_name
, object_name
= name
.rsplit('.', 1)
461 module_name
= '__builtin__'
464 __import__(module_name
)
465 except ImportError, exc
:
466 raise ConstructorError("while constructing a Python object", mark
,
467 "cannot find module %r (%s)" % (module_name
.encode('utf-8'), exc
), mark
)
468 module
= sys
.modules
[module_name
]
469 if not hasattr(module
, object_name
):
470 raise ConstructorError("while constructing a Python object", mark
,
471 "cannot find %r in the module %r" % (object_name
.encode('utf-8'),
472 module
.__name
__), mark
)
473 return getattr(module
, object_name
)
475 def construct_python_name(self
, suffix
, node
):
476 value
= self
.construct_scalar(node
)
478 raise ConstructorError("while constructing a Python name", node
.start_mark
,
479 "expected the empty value, but found %r" % value
.encode('utf-8'),
481 return self
.find_python_name(suffix
, node
.start_mark
)
483 def construct_python_module(self
, suffix
, node
):
484 value
= self
.construct_scalar(node
)
486 raise ConstructorError("while constructing a Python module", node
.start_mark
,
487 "expected the empty value, but found %r" % value
.encode('utf-8'),
489 return self
.find_python_module(suffix
, node
.start_mark
)
491 Constructor
.add_constructor(
492 u
'tag:yaml.org,2002:python/none',
493 Constructor
.construct_yaml_null
)
495 Constructor
.add_constructor(
496 u
'tag:yaml.org,2002:python/bool',
497 Constructor
.construct_yaml_bool
)
499 Constructor
.add_constructor(
500 u
'tag:yaml.org,2002:python/str',
501 Constructor
.construct_python_str
)
503 Constructor
.add_constructor(
504 u
'tag:yaml.org,2002:python/unicode',
505 Constructor
.construct_python_unicode
)
507 Constructor
.add_constructor(
508 u
'tag:yaml.org,2002:python/int',
509 Constructor
.construct_yaml_int
)
511 Constructor
.add_constructor(
512 u
'tag:yaml.org,2002:python/long',
513 Constructor
.construct_python_long
)
515 Constructor
.add_constructor(
516 u
'tag:yaml.org,2002:python/float',
517 Constructor
.construct_yaml_float
)
519 Constructor
.add_constructor(
520 u
'tag:yaml.org,2002:python/complex',
521 Constructor
.construct_python_complex
)
523 Constructor
.add_constructor(
524 u
'tag:yaml.org,2002:python/list',
525 Constructor
.construct_yaml_seq
)
527 Constructor
.add_constructor(
528 u
'tag:yaml.org,2002:python/tuple',
529 Constructor
.construct_python_tuple
)
531 Constructor
.add_constructor(
532 u
'tag:yaml.org,2002:python/dict',
533 Constructor
.construct_yaml_map
)
535 Constructor
.add_multi_constructor(
536 u
'tag:yaml.org,2002:python/name:',
537 Constructor
.construct_python_name
)
539 Constructor
.add_multi_constructor(
540 u
'tag:yaml.org,2002:python/module:',
541 Constructor
.construct_python_module
)