2 __all__
= ['BaseConstructor', 'SafeConstructor', 'Constructor',
10 datetime_available
= True
12 datetime_available
= False
17 from sets
import Set
as set
19 import binascii
, re
, sys
21 class ConstructorError(MarkedYAMLError
):
24 class BaseConstructor(object):
26 yaml_constructors
= {}
27 yaml_multi_constructors
= {}
30 self
.constructed_objects
= {}
31 self
.recursive_objects
= {}
32 self
.state_generators
= []
33 self
.deep_construct
= False
36 # If there are more documents available?
37 return self
.check_node()
40 # Construct and return the next document.
42 return self
.construct_document(self
.get_node())
45 generator_type
= type(g())
48 def construct_document(self
, node
):
49 data
= self
.construct_object(node
)
50 while self
.state_generators
:
51 state_generators
= self
.state_generators
52 self
.state_generators
= []
53 for generator
in state_generators
:
54 for dummy
in generator
:
56 self
.constructed_objects
= {}
57 self
.recursive_objects
= {}
58 self
.deep_construct
= False
61 def construct_object(self
, node
, deep
=False):
63 old_deep
= self
.deep_construct
64 self
.deep_construct
= True
65 if node
in self
.constructed_objects
:
66 return self
.constructed_objects
[node
]
67 if node
in self
.recursive_objects
:
68 raise ConstructorError(None, None,
69 "found unconstructable recursive node", node
.start_mark
)
70 self
.recursive_objects
[node
] = None
72 state_constructor
= None
74 if node
.tag
in self
.yaml_constructors
:
75 constructor
= self
.yaml_constructors
[node
.tag
]
77 for tag_prefix
in self
.yaml_multi_constructors
:
78 if node
.tag
.startswith(tag_prefix
):
79 tag_suffix
= node
.tag
[len(tag_prefix
):]
80 constructor
= self
.yaml_multi_constructors
[tag_prefix
]
83 if None in self
.yaml_multi_constructors
:
85 constructor
= self
.yaml_multi_constructors
[None]
86 elif None in self
.yaml_constructors
:
87 constructor
= self
.yaml_constructors
[None]
88 elif isinstance(node
, ScalarNode
):
89 constructor
= self
.__class
__.construct_scalar
90 elif isinstance(node
, SequenceNode
):
91 constructor
= self
.__class
__.construct_sequence
92 elif isinstance(node
, MappingNode
):
93 constructor
= self
.__class
__.construct_mapping
94 if tag_suffix
is None:
95 data
= constructor(self
, node
)
97 data
= constructor(self
, tag_suffix
, node
)
98 if isinstance(data
, self
.generator_type
):
100 data
= generator
.next()
101 if self
.deep_construct
:
102 for dummy
in generator
:
105 self
.state_generators
.append(generator
)
106 self
.constructed_objects
[node
] = data
107 del self
.recursive_objects
[node
]
109 self
.deep_construct
= old_deep
112 def construct_scalar(self
, node
):
113 if not isinstance(node
, ScalarNode
):
114 raise ConstructorError(None, None,
115 "expected a scalar node, but found %s" % node
.id,
119 def construct_sequence(self
, node
, deep
=False):
120 if not isinstance(node
, SequenceNode
):
121 raise ConstructorError(None, None,
122 "expected a sequence node, but found %s" % node
.id,
124 return [self
.construct_object(child
, deep
=deep
)
125 for child
in node
.value
]
127 def construct_mapping(self
, node
, deep
=False):
128 if not isinstance(node
, MappingNode
):
129 raise ConstructorError(None, None,
130 "expected a mapping node, but found %s" % node
.id,
133 for key_node
, value_node
in node
.value
:
134 key
= self
.construct_object(key_node
, deep
=deep
)
137 except TypeError, exc
:
138 raise ConstructorError("while constructing a mapping", node
.start_mark
,
139 "found unacceptable key (%s)" % exc
, key_node
.start_mark
)
140 value
= self
.construct_object(value_node
, deep
=deep
)
144 def construct_pairs(self
, node
, deep
=False):
145 if not isinstance(node
, MappingNode
):
146 raise ConstructorError(None, None,
147 "expected a mapping node, but found %s" % node
.id,
150 for key_node
, value_node
in node
.value
:
151 key
= self
.construct_object(key_node
, deep
=deep
)
152 value
= self
.construct_object(value_node
, deep
=deep
)
153 pairs
.append((key
, value
))
156 def add_constructor(cls
, tag
, constructor
):
157 if not 'yaml_constructors' in cls
.__dict
__:
158 cls
.yaml_constructors
= cls
.yaml_constructors
.copy()
159 cls
.yaml_constructors
[tag
] = constructor
160 add_constructor
= classmethod(add_constructor
)
162 def add_multi_constructor(cls
, tag_prefix
, multi_constructor
):
163 if not 'yaml_multi_constructors' in cls
.__dict
__:
164 cls
.yaml_multi_constructors
= cls
.yaml_multi_constructors
.copy()
165 cls
.yaml_multi_constructors
[tag_prefix
] = multi_constructor
166 add_multi_constructor
= classmethod(add_multi_constructor
)
168 class SafeConstructor(BaseConstructor
):
170 def construct_scalar(self
, node
):
171 if isinstance(node
, MappingNode
):
172 for key_node
, value_node
in node
.value
:
173 if key_node
.tag
== u
'tag:yaml.org,2002:value':
174 return self
.construct_scalar(value_node
)
175 return BaseConstructor
.construct_scalar(self
, node
)
177 def flatten_mapping(self
, node
):
180 while index
< len(node
.value
):
181 key_node
, value_node
= node
.value
[index
]
182 if key_node
.tag
== u
'tag:yaml.org,2002:merge':
183 del node
.value
[index
]
184 if isinstance(value_node
, MappingNode
):
185 self
.flatten_mapping(value_node
)
186 merge
.extend(value_node
.value
)
187 elif isinstance(value_node
, SequenceNode
):
189 for subnode
in value_node
.value
:
190 if not isinstance(subnode
, MappingNode
):
191 raise ConstructorError("while constructing a mapping",
193 "expected a mapping for merging, but found %s"
194 % subnode
.id, subnode
.start_mark
)
195 self
.flatten_mapping(subnode
)
196 submerge
.append(subnode
.value
)
198 for value
in submerge
:
201 raise ConstructorError("while constructing a mapping", node
.start_mark
,
202 "expected a mapping or list of mappings for merging, but found %s"
203 % value_node
.id, value_node
.start_mark
)
204 elif key_node
.tag
== u
'tag:yaml.org,2002:value':
205 key_node
.tag
= u
'tag:yaml.org,2002:str'
210 node
.value
= merge
+ node
.value
212 def construct_mapping(self
, node
, deep
=False):
213 if isinstance(node
, MappingNode
):
214 self
.flatten_mapping(node
)
215 return BaseConstructor
.construct_mapping(self
, node
, deep
=deep
)
217 def construct_yaml_null(self
, node
):
218 self
.construct_scalar(node
)
230 def construct_yaml_bool(self
, node
):
231 value
= self
.construct_scalar(node
)
232 return self
.bool_values
[value
.lower()]
234 def construct_yaml_int(self
, node
):
235 value
= str(self
.construct_scalar(node
))
236 value
= value
.replace('_', '')
244 elif value
.startswith('0b'):
245 return sign
*int(value
[2:], 2)
246 elif value
.startswith('0x'):
247 return sign
*int(value
[2:], 16)
248 elif value
[0] == '0':
249 return sign
*int(value
, 8)
251 digits
= [int(part
) for part
in value
.split(':')]
260 return sign
*int(value
)
263 while inf_value
!= inf_value
*inf_value
:
264 inf_value
*= inf_value
265 nan_value
= -inf_value
/inf_value
# Trying to make a quiet NaN (like C99).
267 def construct_yaml_float(self
, node
):
268 value
= str(self
.construct_scalar(node
))
269 value
= value
.replace('_', '').lower()
276 return sign
*self
.inf_value
277 elif value
== '.nan':
278 return self
.nan_value
280 digits
= [float(part
) for part
in value
.split(':')]
289 return sign
*float(value
)
291 def construct_yaml_binary(self
, node
):
292 value
= self
.construct_scalar(node
)
294 return str(value
).decode('base64')
295 except (binascii
.Error
, UnicodeEncodeError), exc
:
296 raise ConstructorError(None, None,
297 "failed to decode base64 data: %s" % exc
, node
.start_mark
)
299 timestamp_regexp
= re
.compile(
300 ur
'''^(?P<year>[0-9][0-9][0-9][0-9])
301 -(?P<month>[0-9][0-9]?)
302 -(?P<day>[0-9][0-9]?)
304 (?P<hour>[0-9][0-9]?)
305 :(?P<minute>[0-9][0-9])
306 :(?P<second>[0-9][0-9])
307 (?:\.(?P<fraction>[0-9]*))?
308 (?:[ \t]*(?:Z|(?P<tz_hour>[-+][0-9][0-9]?)
309 (?::(?P<tz_minute>[0-9][0-9])?)?))?)?$''', re
.X
)
311 def construct_yaml_timestamp(self
, node
):
312 value
= self
.construct_scalar(node
)
313 match
= self
.timestamp_regexp
.match(node
.value
)
314 values
= match
.groupdict()
317 values
[key
] = int(values
[key
])
320 fraction
= values
['fraction']
322 while 10*fraction
< 1000000:
324 values
['fraction'] = fraction
325 stamp
= datetime
.datetime(values
['year'], values
['month'], values
['day'],
326 values
['hour'], values
['minute'], values
['second'], values
['fraction'])
327 diff
= datetime
.timedelta(hours
=values
['tz_hour'], minutes
=values
['tz_minute'])
330 def construct_yaml_omap(self
, node
):
331 # Note: we do not check for duplicate keys, because it's too
335 if not isinstance(node
, SequenceNode
):
336 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
337 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
338 for subnode
in node
.value
:
339 if not isinstance(subnode
, MappingNode
):
340 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
341 "expected a mapping of length 1, but found %s" % subnode
.id,
343 if len(subnode
.value
) != 1:
344 raise ConstructorError("while constructing an ordered map", node
.start_mark
,
345 "expected a single mapping item, but found %d items" % len(subnode
.value
),
347 key_node
, value_node
= subnode
.value
[0]
348 key
= self
.construct_object(key_node
)
349 value
= self
.construct_object(value_node
)
350 omap
.append((key
, value
))
352 def construct_yaml_pairs(self
, node
):
353 # Note: the same code as `construct_yaml_omap`.
356 if not isinstance(node
, SequenceNode
):
357 raise ConstructorError("while constructing pairs", node
.start_mark
,
358 "expected a sequence, but found %s" % node
.id, node
.start_mark
)
359 for subnode
in node
.value
:
360 if not isinstance(subnode
, MappingNode
):
361 raise ConstructorError("while constructing pairs", node
.start_mark
,
362 "expected a mapping of length 1, but found %s" % subnode
.id,
364 if len(subnode
.value
) != 1:
365 raise ConstructorError("while constructing pairs", node
.start_mark
,
366 "expected a single mapping item, but found %d items" % len(subnode
.value
),
368 key_node
, value_node
= subnode
.value
[0]
369 key
= self
.construct_object(key_node
)
370 value
= self
.construct_object(value_node
)
371 pairs
.append((key
, value
))
373 def construct_yaml_set(self
, node
):
376 value
= self
.construct_mapping(node
)
379 def construct_yaml_str(self
, node
):
380 value
= self
.construct_scalar(node
)
383 except UnicodeEncodeError:
386 def construct_yaml_seq(self
, node
):
389 data
.extend(self
.construct_sequence(node
))
391 def construct_yaml_map(self
, node
):
394 value
= self
.construct_mapping(node
)
397 def construct_yaml_object(self
, node
, cls
):
398 data
= cls
.__new
__(cls
)
400 if hasattr(data
, '__setstate__'):
401 state
= self
.construct_mapping(node
, deep
=True)
402 data
.__setstate
__(state
)
404 state
= self
.construct_mapping(node
)
405 data
.__dict
__.update(state
)
407 def construct_undefined(self
, node
):
408 raise ConstructorError(None, None,
409 "could not determine a constructor for the tag %r" % node
.tag
.encode('utf-8'),
412 SafeConstructor
.add_constructor(
413 u
'tag:yaml.org,2002:null',
414 SafeConstructor
.construct_yaml_null
)
416 SafeConstructor
.add_constructor(
417 u
'tag:yaml.org,2002:bool',
418 SafeConstructor
.construct_yaml_bool
)
420 SafeConstructor
.add_constructor(
421 u
'tag:yaml.org,2002:int',
422 SafeConstructor
.construct_yaml_int
)
424 SafeConstructor
.add_constructor(
425 u
'tag:yaml.org,2002:float',
426 SafeConstructor
.construct_yaml_float
)
428 SafeConstructor
.add_constructor(
429 u
'tag:yaml.org,2002:binary',
430 SafeConstructor
.construct_yaml_binary
)
432 if datetime_available
:
433 SafeConstructor
.add_constructor(
434 u
'tag:yaml.org,2002:timestamp',
435 SafeConstructor
.construct_yaml_timestamp
)
437 SafeConstructor
.add_constructor(
438 u
'tag:yaml.org,2002:omap',
439 SafeConstructor
.construct_yaml_omap
)
441 SafeConstructor
.add_constructor(
442 u
'tag:yaml.org,2002:pairs',
443 SafeConstructor
.construct_yaml_pairs
)
445 SafeConstructor
.add_constructor(
446 u
'tag:yaml.org,2002:set',
447 SafeConstructor
.construct_yaml_set
)
449 SafeConstructor
.add_constructor(
450 u
'tag:yaml.org,2002:str',
451 SafeConstructor
.construct_yaml_str
)
453 SafeConstructor
.add_constructor(
454 u
'tag:yaml.org,2002:seq',
455 SafeConstructor
.construct_yaml_seq
)
457 SafeConstructor
.add_constructor(
458 u
'tag:yaml.org,2002:map',
459 SafeConstructor
.construct_yaml_map
)
461 SafeConstructor
.add_constructor(None,
462 SafeConstructor
.construct_undefined
)
464 class Constructor(SafeConstructor
):
466 def construct_python_str(self
, node
):
467 return self
.construct_scalar(node
).encode('utf-8')
469 def construct_python_unicode(self
, node
):
470 return self
.construct_scalar(node
)
472 def construct_python_long(self
, node
):
473 return long(self
.construct_yaml_int(node
))
475 def construct_python_complex(self
, node
):
476 return complex(self
.construct_scalar(node
))
478 def construct_python_tuple(self
, node
):
479 return tuple(self
.construct_sequence(node
))
481 def find_python_module(self
, name
, mark
):
483 raise ConstructorError("while constructing a Python module", mark
,
484 "expected non-empty name appended to the tag", mark
)
487 except ImportError, exc
:
488 raise ConstructorError("while constructing a Python module", mark
,
489 "cannot find module %r (%s)" % (name
.encode('utf-8'), exc
), mark
)
490 return sys
.modules
[name
]
492 def find_python_name(self
, name
, mark
):
494 raise ConstructorError("while constructing a Python object", mark
,
495 "expected non-empty name appended to the tag", mark
)
498 #module_name, object_name = name.rsplit('.', 1)
499 items
= name
.split('.')
500 object_name
= items
.pop()
501 module_name
= '.'.join(items
)
503 module_name
= '__builtin__'
506 __import__(module_name
)
507 except ImportError, exc
:
508 raise ConstructorError("while constructing a Python object", mark
,
509 "cannot find module %r (%s)" % (module_name
.encode('utf-8'), exc
), mark
)
510 module
= sys
.modules
[module_name
]
511 if not hasattr(module
, object_name
):
512 raise ConstructorError("while constructing a Python object", mark
,
513 "cannot find %r in the module %r" % (object_name
.encode('utf-8'),
514 module
.__name
__), mark
)
515 return getattr(module
, object_name
)
517 def construct_python_name(self
, suffix
, node
):
518 value
= self
.construct_scalar(node
)
520 raise ConstructorError("while constructing a Python name", node
.start_mark
,
521 "expected the empty value, but found %r" % value
.encode('utf-8'),
523 return self
.find_python_name(suffix
, node
.start_mark
)
525 def construct_python_module(self
, suffix
, node
):
526 value
= self
.construct_scalar(node
)
528 raise ConstructorError("while constructing a Python module", node
.start_mark
,
529 "expected the empty value, but found %r" % value
.encode('utf-8'),
531 return self
.find_python_module(suffix
, node
.start_mark
)
535 def make_python_instance(self
, suffix
, node
,
536 args
=None, kwds
=None, newobj
=False):
541 cls
= self
.find_python_name(suffix
, node
.start_mark
)
542 if newobj
and isinstance(cls
, type(self
.classobj
)) \
543 and not args
and not kwds
:
544 instance
= self
.classobj()
545 instance
.__class
__ = cls
547 elif newobj
and isinstance(cls
, type):
548 return cls
.__new
__(cls
, *args
, **kwds
)
550 return cls(*args
, **kwds
)
552 def set_python_instance_state(self
, instance
, state
):
553 if hasattr(instance
, '__setstate__'):
554 instance
.__setstate
__(state
)
557 if isinstance(state
, tuple) and len(state
) == 2:
558 state
, slotstate
= state
559 if hasattr(instance
, '__dict__'):
560 instance
.__dict
__.update(state
)
562 slotstate
.update(state
)
563 for key
, value
in slotstate
.items():
564 setattr(object, key
, value
)
566 def construct_python_object(self
, suffix
, node
):
568 # !!python/object:module.name { ... state ... }
569 instance
= self
.make_python_instance(suffix
, node
, newobj
=True)
571 deep
= hasattr(instance
, '__setstate__')
572 state
= self
.construct_mapping(node
, deep
=deep
)
573 self
.set_python_instance_state(instance
, state
)
575 def construct_python_object_apply(self
, suffix
, node
, newobj
=False):
577 # !!python/object/apply # (or !!python/object/new)
578 # args: [ ... arguments ... ]
579 # kwds: { ... keywords ... }
580 # state: ... state ...
581 # listitems: [ ... listitems ... ]
582 # dictitems: { ... dictitems ... }
584 # !!python/object/apply [ ... arguments ... ]
585 # The difference between !!python/object/apply and !!python/object/new
586 # is how an object is created, check make_python_instance for details.
587 if isinstance(node
, SequenceNode
):
588 args
= self
.construct_sequence(node
, deep
=True)
594 value
= self
.construct_mapping(node
, deep
=True)
595 args
= value
.get('args', [])
596 kwds
= value
.get('kwds', {})
597 state
= value
.get('state', {})
598 listitems
= value
.get('listitems', [])
599 dictitems
= value
.get('dictitems', {})
600 instance
= self
.make_python_instance(suffix
, node
, args
, kwds
, newobj
)
602 self
.set_python_instance_state(instance
, state
)
604 instance
.extend(listitems
)
606 for key
in dictitems
:
607 instance
[key
] = dictitems
[key
]
610 def construct_python_object_new(self
, suffix
, node
):
611 return self
.construct_python_object_apply(suffix
, node
, newobj
=True)
613 Constructor
.add_constructor(
614 u
'tag:yaml.org,2002:python/none',
615 Constructor
.construct_yaml_null
)
617 Constructor
.add_constructor(
618 u
'tag:yaml.org,2002:python/bool',
619 Constructor
.construct_yaml_bool
)
621 Constructor
.add_constructor(
622 u
'tag:yaml.org,2002:python/str',
623 Constructor
.construct_python_str
)
625 Constructor
.add_constructor(
626 u
'tag:yaml.org,2002:python/unicode',
627 Constructor
.construct_python_unicode
)
629 Constructor
.add_constructor(
630 u
'tag:yaml.org,2002:python/int',
631 Constructor
.construct_yaml_int
)
633 Constructor
.add_constructor(
634 u
'tag:yaml.org,2002:python/long',
635 Constructor
.construct_python_long
)
637 Constructor
.add_constructor(
638 u
'tag:yaml.org,2002:python/float',
639 Constructor
.construct_yaml_float
)
641 Constructor
.add_constructor(
642 u
'tag:yaml.org,2002:python/complex',
643 Constructor
.construct_python_complex
)
645 Constructor
.add_constructor(
646 u
'tag:yaml.org,2002:python/list',
647 Constructor
.construct_yaml_seq
)
649 Constructor
.add_constructor(
650 u
'tag:yaml.org,2002:python/tuple',
651 Constructor
.construct_python_tuple
)
653 Constructor
.add_constructor(
654 u
'tag:yaml.org,2002:python/dict',
655 Constructor
.construct_yaml_map
)
657 Constructor
.add_multi_constructor(
658 u
'tag:yaml.org,2002:python/name:',
659 Constructor
.construct_python_name
)
661 Constructor
.add_multi_constructor(
662 u
'tag:yaml.org,2002:python/module:',
663 Constructor
.construct_python_module
)
665 Constructor
.add_multi_constructor(
666 u
'tag:yaml.org,2002:python/object:',
667 Constructor
.construct_python_object
)
669 Constructor
.add_multi_constructor(
670 u
'tag:yaml.org,2002:python/object/apply:',
671 Constructor
.construct_python_object_apply
)
673 Constructor
.add_multi_constructor(
674 u
'tag:yaml.org,2002:python/object/new:',
675 Constructor
.construct_python_object_new
)