Ticket #5: constructor.3.py

File constructor.3.py, 28.5 kB (added by Peter Murphy (pkmurphy at postmaster.co.uk), 2 years ago)

Allowing recursive tuples

Line 
1
2 __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
3     'ConstructorError']
4
5 from error import *
6 from nodes import *
7 from composer import *
8
9 try:
10     import datetime
11     datetime_available = True
12 except ImportError:
13     datetime_available = False
14
15 try:
16     set
17 except NameError:
18     from sets import Set as set
19
20 import binascii, re, sys
21
22 class ConstructorError(MarkedYAMLError):
23     pass
24
25 class BaseConstructor(Composer):
26
27     yaml_constructors = {}
28     yaml_multi_constructors = {}
29    
30 # While we are in the middle of constructing a recursive tuple, we may encounter other things
31 # that contain this tuple. For quicker store, we take a note of them. What we do is make a key
32 # (actually by node id again), and the values are a list containing of structures containing this
33 # tuple directly.
34
35     def __init__(self):
36         self.constructed_objects = {}
37         self.recursive_objects = {}
38
39 # PKM - We now add an extra map that contains a map of nodes to temporary sequences. These
40 # temporary sequences can be used in place of tuples until all tuples have been constructed. Then
41 # these sequences are "replaced" by the actual tuples.
42
43         self.yaml_tuple_replacement = {};
44
45
46     def check_data(self):
47         # If there are more documents available?
48         return self.check_node()
49
50     def get_data(self):
51         # Construct and return the next document.
52         if self.check_node():
53             return self.construct_document(self.get_node())
54
55     def __iter__(self):
56         # Iterator protocol.
57         while self.check_node():
58             yield self.construct_document(self.get_node())
59
60     def construct_document(self, node):
61         data = self.construct_object(node)
62         self.constructed_objects = {}
63         self.recursive_objects = {}
64         self.yaml_tuple_replacement = {}; # PKM2006.
65         return data
66
67     def construct_object(self, node):
68         if node in self.constructed_objects:
69             return self.constructed_objects[node]
70 #        if node in self.recursive_objects:
71 #            raise ConstructorError(None, None,
72 #                    "found recursive node", node.start_mark)
73 #        self.recursive_objects[node] = None
74         constructor = None
75         if node.tag in self.yaml_constructors:
76             constructor = lambda node: self.yaml_constructors[node.tag](self, node) #Modify BBB2
77         else:
78             for tag_prefix in self.yaml_multi_constructors:
79                 if node.tag.startswith(tag_prefix):
80                     tag_suffix = node.tag[len(tag_prefix):]
81                     constructor = lambda node:  \
82                             self.yaml_multi_constructors[tag_prefix](self, tag_suffix, node)
83                     break
84             else:
85                 if None in self.yaml_multi_constructors:
86                     constructor = lambda node:  \
87                             self.yaml_multi_constructors[None](self, node.tag, node)
88                 elif None in self.yaml_constructors:
89                     constructor = lambda node:  \
90                             self.yaml_constructors[None](self, node)
91                 elif isinstance(node, ScalarNode):
92                     constructor = self.construct_scalar
93                 elif isinstance(node, SequenceNode):
94                     constructor = self.construct_sequence
95                 elif isinstance(node, MappingNode):
96                     constructor = self.construct_mapping
97                 else:
98                     print node.tag
99         data = constructor(node) #Modify BBB1
100         self.constructed_objects[node] = data
101 #        del self.recursive_objects[node]
102         return data
103
104     def construct_scalar(self, node):
105         if not isinstance(node, ScalarNode):
106             if isinstance(node, MappingNode):
107                 for key_node in node.value:
108                     if key_node.tag == u'tag:yaml.org,2002:value':
109                         return self.construct_scalar(node.value[key_node])
110             raise ConstructorError(None, None,
111                     "expected a scalar node, but found %s" % node.id,
112                     node.start_mark)
113         return node.value
114
115     def construct_sequence(self, node):
116         if not isinstance(node, SequenceNode):
117             raise ConstructorError(None, None,
118                     "expected a sequence node, but found %s" % node.id,
119                     node.start_mark)
120
121 #PKM2006.
122                    
123         data = [];
124         self.constructed_objects[node] = data; # PKM2006
125         for child in node.value:
126             data.append(self.construct_object(child));
127         return data;                   
128                    
129 #        return [self.construct_object(child) for child in node.value] #MODIFY BBB4
130
131     def construct_mapping(self, node):
132         if not isinstance(node, MappingNode):
133             raise ConstructorError(None, None,
134                     "expected a mapping node, but found %s" % node.id,
135                     node.start_mark)
136         mapping = {}
137         self.constructed_objects[node] = mapping; # PKM2006
138         merge = None
139         for key_node in node.value:
140             if key_node.tag == u'tag:yaml.org,2002:merge':
141                 if merge is not None:
142                     raise ConstructorError("while constructing a mapping", node.start_mark,
143                             "found duplicate merge key", key_node.start_mark)
144                 value_node = node.value[key_node]
145                 if isinstance(value_node, MappingNode):
146                     merge = [self.construct_mapping(value_node)]
147                 elif isinstance(value_node, SequenceNode):
148                     merge = []
149                     for subnode in value_node.value:
150                         if not isinstance(subnode, MappingNode):
151                             raise ConstructorError("while constructing a mapping",
152                                     node.start_mark,
153                                     "expected a mapping for merging, but found %s"
154                                     % subnode.id, subnode.start_mark)
155                         merge.append(self.construct_mapping(subnode))
156                     merge.reverse()
157                 else:
158                     raise ConstructorError("while constructing a mapping", node.start_mark,
159                             "expected a mapping or list of mappings for merging, but found %s"
160                             % value_node.id, value_node.start_mark)
161             elif key_node.tag == u'tag:yaml.org,2002:value':
162                 if '=' in mapping:
163                     raise ConstructorError("while construction a mapping", node.start_mark,
164                             "found duplicate value key", key_node.start_mark)
165                 value = self.construct_object(node.value[key_node])
166                 mapping['='] = value
167             else:
168                 key = self.construct_object(key_node)
169                 try:
170                     duplicate_key = key in mapping
171                 except TypeError, exc:
172                     raise ConstructorError("while constructing a mapping", node.start_mark,
173                             "found unacceptable key (%s)" % exc, key_node.start_mark)
174                 if duplicate_key:
175                     raise ConstructorError("while constructing a mapping", node.start_mark,
176                             "found duplicate key", key_node.start_mark)
177                 value = self.construct_object(node.value[key_node])
178                 mapping[key] = value
179         if merge is not None:
180             merge.append(mapping)
181             mapping.clear(); # PKM2006 = {}
182             for submapping in merge:
183                 mapping.update(submapping)
184         return mapping
185
186     def construct_pairs(self, node):
187         if not isinstance(node, MappingNode):
188             raise ConstructorError(None, None,
189                     "expected a mapping node, but found %s" % node.id,
190                     node.start_mark)
191         pairs = []
192         self.constructed_objects[node] = pairs; # PKM2006
193         for key_node in node.value:
194             key = self.construct_object(key_node)
195             value = self.construct_object(node.value[key_node])
196             pairs.append((key, value))
197         return pairs
198
199     def add_constructor(cls, tag, constructor):
200         if not 'yaml_constructors' in cls.__dict__:
201             cls.yaml_constructors = cls.yaml_constructors.copy()
202         cls.yaml_constructors[tag] = constructor
203     add_constructor = classmethod(add_constructor)
204
205     def add_multi_constructor(cls, tag_prefix, multi_constructor):
206         if not 'yaml_multi_constructors' in cls.__dict__:
207             cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
208         cls.yaml_multi_constructors[tag_prefix] = multi_constructor
209     add_multi_constructor = classmethod(add_multi_constructor)
210
211 class SafeConstructor(BaseConstructor):
212
213     def construct_yaml_null(self, node):
214         self.construct_scalar(node)
215         return None
216
217     bool_values = {
218         u'yes':     True,
219         u'no':      False,
220         u'true':    True,
221         u'false':   False,
222         u'on':      True,
223         u'off':     False,
224     }
225
226     def construct_yaml_bool(self, node):
227         value = self.construct_scalar(node)
228         return self.bool_values[value.lower()]
229
230     def construct_yaml_int(self, node):
231         value = str(self.construct_scalar(node))
232         value = value.replace('_', '')
233         sign = +1
234         if value[0] == '-':
235             sign = -1
236         if value[0] in '+-':
237             value = value[1:]
238         if value == '0':
239             return 0
240         elif value.startswith('0b'):
241             return sign*int(value[2:], 2)
242         elif value.startswith('0x'):
243             return sign*int(value[2:], 16)
244         elif value[0] == '0':
245             return sign*int(value, 8)
246         elif ':' in value:
247             digits = [int(part) for part in value.split(':')]
248             digits.reverse()
249             base = 1
250             value = 0
251             for digit in digits:
252                 value += digit*base
253                 base *= 60
254             return sign*value
255         else:
256             return sign*int(value)
257
258     inf_value = 1e300
259     while inf_value != inf_value*inf_value:
260         inf_value *= inf_value
261     nan_value = -inf_value/inf_value   # Trying to make a quiet NaN (like C99).
262
263     def construct_yaml_float(self, node):
264         value = str(self.construct_scalar(node))
265         value = value.replace('_', '').lower()
266         sign = +1
267         if value[0] == '-':
268             sign = -1
269         if value[0] in '+-':
270             value = value[1:]
271         if value == '.inf':
272             return sign*self.inf_value
273         elif value == '.nan':
274             return self.nan_value
275         elif ':' in value:
276             digits = [float(part) for part in value.split(':')]
277             digits.reverse()
278             base = 1
279             value = 0.0
280             for digit in digits:
281                 value += digit*base
282                 base *= 60
283             return sign*value
284         else:
285             return sign*float(value)
286
287     def construct_yaml_binary(self, node):
288         value = self.construct_scalar(node)
289         try:
290             return str(value).decode('base64')
291         except (binascii.Error, UnicodeEncodeError), exc:
292             raise ConstructorError(None, None,
293                     "failed to decode base64 data: %s" % exc, node.start_mark)
294
295     timestamp_regexp = re.compile(
296             ur'''^(?P<year>[0-9][0-9][0-9][0-9])
297                 -(?P<month>[0-9][0-9]?)
298                 -(?P<day>[0-9][0-9]?)
299                 (?:(?:[Tt]|[ \t]+)
300                 (?P<hour>[0-9][0-9]?)
301                 :(?P<minute>[0-9][0-9])
302                 :(?P<second>[0-9][0-9])
303                 (?:\.(?P<fraction>[0-9]*))?
304                 (?:[ \t]*(?:Z|(?P<tz_hour>[-+][0-9][0-9]?)
305                 (?::(?P<tz_minute>[0-9][0-9])?)?))?)?$''', re.X)
306
307     def construct_yaml_timestamp(self, node):
308         value = self.construct_scalar(node)
309         match = self.timestamp_regexp.match(node.value)
310         values = match.groupdict()
311         for key in values:
312             if values[key]:
313                 values[key] = int(values[key])
314             else:
315                 values[key] = 0
316         fraction = values['fraction']
317         if fraction:
318             while 10*fraction < 1000000:
319                 fraction *= 10
320             values['fraction'] = fraction
321         stamp = datetime.datetime(values['year'], values['month'], values['day'],
322                 values['hour'], values['minute'], values['second'], values['fraction'])
323         diff = datetime.timedelta(hours=values['tz_hour'], minutes=values['tz_minute'])
324         return stamp-diff
325
326     def construct_yaml_omap(self, node):
327         # Note: we do not check for duplicate keys, because it's too
328         # CPU-expensive.
329         if not isinstance(node, SequenceNode):
330             raise ConstructorError("while constructing an ordered map", node.start_mark,
331                     "expected a sequence, but found %s" % node.id, node.start_mark)
332         omap = []
333         self.constructed_objects[node] = omap; # PKM2006
334         for subnode in node.value:
335             if not isinstance(subnode, MappingNode):
336                 raise ConstructorError("while constructing an ordered map", node.start_mark,
337                         "expected a mapping of length 1, but found %s" % subnode.id,
338                         subnode.start_mark)
339             if len(subnode.value) != 1:
340                 raise ConstructorError("while constructing an ordered map", node.start_mark,
341                         "expected a single mapping item, but found %d items" % len(subnode.value),
342                         subnode.start_mark)
343             key_node = subnode.value.keys()[0]
344             key = self.construct_object(key_node)
345             value = self.construct_object(subnode.value[key_node])
346             omap.append((key, value))
347         return omap
348
349     def construct_yaml_pairs(self, node):
350         # Note: the same code as `construct_yaml_omap`.
351         if not isinstance(node, SequenceNode):
352             raise ConstructorError("while constructing pairs", node.start_mark,
353                     "expected a sequence, but found %s" % node.id, node.start_mark)
354         pairs = []
355         self.constructed_objects[node] = pairs; # PKM2006
356         for subnode in node.value:
357             if not isinstance(subnode, MappingNode):
358                 raise ConstructorError("while constructing pairs", node.start_mark,
359                         "expected a mapping of length 1, but found %s" % subnode.id,
360                         subnode.start_mark)
361             if len(subnode.value) != 1:
362                 raise ConstructorError("while constructing pairs", node.start_mark,
363                         "expected a single mapping item, but found %d items" % len(subnode.value),
364                         subnode.start_mark)
365             key_node = subnode.value.keys()[0]
366             key = self.construct_object(key_node)
367             value = self.construct_object(subnode.value[key_node])
368             pairs.append((key, value))
369         return pairs
370
371     def construct_yaml_set(self, node):
372         value = self.construct_mapping(node)
373         return set(value)
374
375     def construct_yaml_str(self, node):
376         value = self.construct_scalar(node)
377         try:
378             return str(value)
379         except UnicodeEncodeError:
380             return value
381
382     def construct_yaml_seq(self, node):
383         return self.construct_sequence(node) #MODIFY BBB3
384
385     def construct_yaml_map(self, node):
386         return self.construct_mapping(node)
387
388     def construct_yaml_object(self, node, cls):
389         state = self.construct_mapping(node)
390         data = cls.__new__(cls)
391         if hasattr(data, '__setstate__'):
392             data.__setstate__(state)
393         else:
394             data.__dict__.update(state)
395         return data
396
397     def construct_undefined(self, node):
398         raise ConstructorError(None, None,
399                 "could not determine a constructor for the tag %r" % node.tag.encode('utf-8'),
400                 node.start_mark)
401
402 SafeConstructor.add_constructor(
403         u'tag:yaml.org,2002:null',
404         SafeConstructor.construct_yaml_null)
405
406 SafeConstructor.add_constructor(
407         u'tag:yaml.org,2002:bool',
408         SafeConstructor.construct_yaml_bool)
409
410 SafeConstructor.add_constructor(
411         u'tag:yaml.org,2002:int',
412         SafeConstructor.construct_yaml_int)
413
414 SafeConstructor.add_constructor(
415         u'tag:yaml.org,2002:float',
416         SafeConstructor.construct_yaml_float)
417
418 SafeConstructor.add_constructor(
419         u'tag:yaml.org,2002:binary',
420         SafeConstructor.construct_yaml_binary)
421
422 if datetime_available:
423     SafeConstructor.add_constructor(
424             u'tag:yaml.org,2002:timestamp',
425             SafeConstructor.construct_yaml_timestamp)
426
427 SafeConstructor.add_constructor(
428         u'tag:yaml.org,2002:omap',
429         SafeConstructor.construct_yaml_omap)
430
431 SafeConstructor.add_constructor(
432         u'tag:yaml.org,2002:pairs',
433         SafeConstructor.construct_yaml_pairs)
434
435 SafeConstructor.add_constructor(
436         u'tag:yaml.org,2002:set',
437         SafeConstructor.construct_yaml_set)
438
439 SafeConstructor.add_constructor(
440         u'tag:yaml.org,2002:str',
441         SafeConstructor.construct_yaml_str)
442
443 SafeConstructor.add_constructor(
444         u'tag:yaml.org,2002:seq',
445         SafeConstructor.construct_yaml_seq)
446
447 SafeConstructor.add_constructor(
448         u'tag:yaml.org,2002:map',
449         SafeConstructor.construct_yaml_map)
450
451 SafeConstructor.add_constructor(None,
452         SafeConstructor.construct_undefined)
453
454 class Constructor(SafeConstructor):
455
456     def construct_python_str(self, node):
457         return self.construct_scalar(node).encode('utf-8')
458
459     def construct_python_unicode(self, node):
460         return self.construct_scalar(node)
461
462     def construct_python_long(self, node):
463         return long(self.construct_yaml_int(node))
464
465     def construct_python_complex(self, node):
466        return complex(self.construct_scalar(node))
467
468 # PKM - This is not recursive enough... not at all.
469 #    def construct_python_tuple(self, node):
470 #        return tuple(self.construct_yaml_seq(node))
471 # So we roll our own.
472
473     def construct_python_tuple(self, node):
474
475 # Tuples are strange beasts. What we need for each tuple T is to construct a
476 # sequence S first, and then make a tuple T = tuple([S]). The requirements of
477 # the function are:
478 # 1 - S must be fully created with all elements before making a tuple out of
479 # it.
480 # 2 - Any object R that references T must reference T only after it has been
481 # created.
482 # 3 - We want the same strategy to construct the rest of the YAML tree - top
483 # down construction with a little bit of recursion.
484 # 4 - Make time minimal.
485 # 5 - Make least use of memory.
486 # 6 - Write the code that limits the effect on the rest of the system. (I am
487 # thinking of third-parties that add their own constructors. Do they have to
488 # make any special accommodation for tuples? I hope not.
489
490 # The function will have a very weird recursive structure. Check it out.
491
492 # As normal, we do this.       
493
494         if not isinstance(node, SequenceNode):
495             raise ConstructorError(None, None,
496                     "expected a sequence node, but found %s" % node.id,
497                     node.start_mark)
498
499 # Now we might have a situation with Tuple -> List or Map ... -> Tuple. The
500 # following code is probably unnecessary, but I'll put it in.
501
502         if node in self.constructed_objects:
503             return self.constructed_objects[node]
504
505 # Let's get this out of the way.
506
507         if (len(node.value) == 0):
508             data = tuple();
509             self.constructed_objects[node] = data;
510             return data;
511
512 # What is more likely is that in the Tuple -> List or Map ... -> Tuple, we
513 # have construct_python_tuple(tuplenode) called twice for the same tuplenode,
514 # and worse, the corresponding tuple will not have been fully constructed.
515 # What we need is to check if the process has already been done.
516
517         ournodeid = id(node);
518
519         if ournodeid in self.yaml_tuple_replacement:
520             thisdata = (self.yaml_tuple_replacement[ournodeid])[0];
521             thislength = (self.yaml_tuple_replacement[ournodeid])[1];
522             thisindex = (self.yaml_tuple_replacement[ournodeid])[2];
523         else:
524             thisdata = [];
525             thislength = len(node.value);
526             thisindex = 0;
527             self.yaml_tuple_replacement[ournodeid] = [thisdata, thislength, thisindex];
528
529 # Now we loop over each other
530
531         if (thislength == thisindex):
532             loopWhile = False;
533         else:
534             loopWhile = True;
535
536         while loopWhile:
537             child = node.value[thisindex];
538             self.yaml_tuple_replacement[ournodeid] = [thisdata, thislength, thisindex];
539             ourobject = self.construct_object(child);
540
541 # The tuple might have been constructed somewhere else. In that case, we can
542 # return.
543
544             if ournodeid not in self.yaml_tuple_replacement:
545                 return self.constructed_objects[node];
546                
547 # Now we append only if the object has not been added to the tuple.
548
549             ournewindex = (self.yaml_tuple_replacement[ournodeid])[2];
550             if (ournewindex == thisindex):
551                 thisdata.append(ourobject);
552
553 # We can end when we have run out of objects to construct.
554
555             thisindex = thisindex + 1;
556             if (thisindex == thislength):
557                 loopWhile = False;
558            
559 # Now that we have everything there, we can construct our tuple.
560
561         ourtuple = tuple(thisdata);
562         self.constructed_objects[node] = tuple;
563        
564 # Then we can go around swapping references from the old sequence.
565
566 # Now we can let the old sequence go.
567
568         del self.yaml_tuple_replacement[ournodeid];
569         del thisdata;
570         return ourtuple;                   
571
572
573
574     def find_python_module(self, name, mark):
575         if not name:
576             raise ConstructorError("while constructing a Python module", mark,
577                     "expected non-empty name appended to the tag", mark)
578         try:
579             __import__(name)
580         except ImportError, exc:
581             raise ConstructorError("while constructing a Python module", mark,
582                     "cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
583         return sys.modules[name]
584
585     def find_python_name(self, name, mark):
586         if not name:
587             raise ConstructorError("while constructing a Python object", mark,
588                     "expected non-empty name appended to the tag", mark)
589         if u'.' in name:
590             # Python 2.4 only
591             #module_name, object_name = name.rsplit('.', 1)
592             items = name.split('.')
593             object_name = items.pop()
594             module_name = '.'.join(items)
595         else:
596             module_name = '__builtin__'
597             object_name = name
598         try:
599             __import__(module_name)
600         except ImportError, exc:
601             raise ConstructorError("while constructing a Python object", mark,
602                     "cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
603         module = sys.modules[module_name]
604         if not hasattr(module, object_name):
605             raise ConstructorError("while constructing a Python object", mark,
606                     "cannot find %r in the module %r" % (object_name.encode('utf-8'),
607                         module.__name__), mark)
608         return getattr(module, object_name)
609
610     def construct_python_name(self, suffix, node):
611         value = self.construct_scalar(node)
612         if value:
613             raise ConstructorError("while constructing a Python name", node.start_mark,
614                     "expected the empty value, but found %r" % value.encode('utf-8'),
615                     node.start_mark)
616         return self.find_python_name(suffix, node.start_mark)
617
618     def construct_python_module(self, suffix, node):
619         value = self.construct_scalar(node)
620         if value:
621             raise ConstructorError("while constructing a Python module", node.start_mark,
622                     "expected the empty value, but found %r" % value.encode('utf-8'),
623                     node.start_mark)
624         return self.find_python_module(suffix, node.start_mark)
625
626     class classobj: pass
627
628     def make_python_instance(self, suffix, node,
629             args=None, kwds=None, newobj=False):
630         if not args:
631             args = []
632         if not kwds:
633             kwds = {}
634         cls = self.find_python_name(suffix, node.start_mark)
635         if newobj and isinstance(cls, type(self.classobj))  \
636                 and not args and not kwds:
637             instance = self.classobj()
638             instance.__class__ = cls
639             return instance
640         elif newobj and isinstance(cls, type):
641             return cls.__new__(cls, *args, **kwds)
642         else:
643             return cls(*args, **kwds)
644
645     def set_python_instance_state(self, instance, state):
646         if hasattr(instance, '__setstate__'):
647             instance.__setstate__(state)
648         else:
649             slotstate = {}
650             if isinstance(state, tuple) and len(state) == 2:
651                 state, slotstate = state
652             if hasattr(instance, '__dict__'):
653                 instance.__dict__.update(state)
654             elif state:
655                 slotstate.update(state)
656             for key, value in slotstate.items():
657                 setattr(object, key, value)
658
659     def construct_python_object(self, suffix, node):
660         # Format:
661         #   !!python/object:module.name { ... state ... }
662         instance = self.make_python_instance(suffix, node, newobj=True)
663         state = self.construct_mapping(node)
664         self.set_python_instance_state(instance, state)
665         return instance
666
667     def construct_python_object_apply(self, suffix, node, newobj=False):
668         # Format:
669         #   !!python/object/apply       # (or !!python/object/new)
670         #   args: [ ... arguments ... ]
671         #   kwds: { ... keywords ... }
672         #   state: ... state ...
673         #   listitems: [ ... listitems ... ]
674         #   dictitems: { ... dictitems ... }
675         # or short format:
676         #   !!python/object/apply [ ... arguments ... ]
677         # The difference between !!python/object/apply and !!python/object/new
678         # is how an object is created, check make_python_instance for details.
679         if isinstance(node, SequenceNode):
680             args = self.construct_sequence(node)
681             kwds = {}
682             state = {}
683             listitems = []
684             dictitems = {}
685         else:
686             value = self.construct_mapping(node)
687             args = value.get('args', [])
688             kwds = value.get('kwds', {})
689             state = value.get('state', {})
690             listitems = value.get('listitems', [])
691             dictitems = value.get('dictitems', {})
692         instance = self.make_python_instance(suffix, node, args, kwds, newobj)
693         if state:
694             self.set_python_instance_state(instance, state)
695         if listitems:
696             instance.extend(listitems)
697         if dictitems:
698             for key in dictitems:
699                 instance[key] = dictitems[key]
700         return instance
701
702     def construct_python_object_new(self, suffix, node):
703         return self.construct_python_object_apply(suffix, node, newobj=True)
704
705
706 Constructor.add_constructor(
707     u'tag:yaml.org,2002:python/none',
708     Constructor.construct_yaml_null)
709
710 Constructor.add_constructor(
711     u'tag:yaml.org,2002:python/bool',
712     Constructor.construct_yaml_bool)
713
714 Constructor.add_constructor(
715     u'tag:yaml.org,2002:python/str',
716     Constructor.construct_python_str)
717
718 Constructor.add_constructor(
719     u'tag:yaml.org,2002:python/unicode',
720     Constructor.construct_python_unicode)
721
722 Constructor.add_constructor(
723     u'tag:yaml.org,2002:python/int',
724     Constructor.construct_yaml_int)
725
726 Constructor.add_constructor(
727     u'tag:yaml.org,2002:python/long',
728     Constructor.construct_python_long)
729
730 Constructor.add_constructor(
731     u'tag:yaml.org,2002:python/float',
732     Constructor.construct_yaml_float)
733
734 Constructor.add_constructor(
735     u'tag:yaml.org,2002:python/complex',
736     Constructor.construct_python_complex)
737
738 Constructor.add_constructor(
739     u'tag:yaml.org,2002:python/list',
740     Constructor.construct_yaml_seq)
741
742 Constructor.add_constructor(
743     u'tag:yaml.org,2002:python/tuple',
744     Constructor.construct_python_tuple)
745
746 Constructor.add_constructor(
747     u'tag:yaml.org,2002:python/dict',
748     Constructor.construct_yaml_map)
749
750 Constructor.add_multi_constructor(
751     u'tag:yaml.org,2002:python/name:',
752     Constructor.construct_python_name)
753
754 Constructor.add_multi_constructor(
755     u'tag:yaml.org,2002:python/module:',
756     Constructor.construct_python_module)
757
758 Constructor.add_multi_constructor(
759     u'tag:yaml.org,2002:python/object:',
760     Constructor.construct_python_object)
761
762 Constructor.add_multi_constructor(
763     u'tag:yaml.org,2002:python/object/apply:',
764     Constructor.construct_python_object_apply)
765
766 Constructor.add_multi_constructor(
767     u'tag:yaml.org,2002:python/object/new:',
768     Constructor.construct_python_object_new)
769