Ticket #5: constructor.4.py

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

The final version of constructor.py? (Solves sets.)

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