Ticket #5: constructor.3.py

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

Allowing recursive tuples

Line 
1
2__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
3    'ConstructorError']
4
5from error import *
6from nodes import *
7from composer import *
8
9try:
10    import datetime
11    datetime_available = True
12except ImportError:
13    datetime_available = False
14
15try:
16    set
17except NameError:
18    from sets import Set as set
19
20import binascii, re, sys
21
22class ConstructorError(MarkedYAMLError):
23    pass
24
25class 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
211class 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
402SafeConstructor.add_constructor(
403        u'tag:yaml.org,2002:null',
404        SafeConstructor.construct_yaml_null)
405
406SafeConstructor.add_constructor(
407        u'tag:yaml.org,2002:bool',
408        SafeConstructor.construct_yaml_bool)
409
410SafeConstructor.add_constructor(
411        u'tag:yaml.org,2002:int',
412        SafeConstructor.construct_yaml_int)
413
414SafeConstructor.add_constructor(
415        u'tag:yaml.org,2002:float',
416        SafeConstructor.construct_yaml_float)
417
418SafeConstructor.add_constructor(
419        u'tag:yaml.org,2002:binary',
420        SafeConstructor.construct_yaml_binary)
421
422if datetime_available:
423    SafeConstructor.add_constructor(
424            u'tag:yaml.org,2002:timestamp',
425            SafeConstructor.construct_yaml_timestamp)
426
427SafeConstructor.add_constructor(
428        u'tag:yaml.org,2002:omap',
429        SafeConstructor.construct_yaml_omap)
430
431SafeConstructor.add_constructor(
432        u'tag:yaml.org,2002:pairs',
433        SafeConstructor.construct_yaml_pairs)
434
435SafeConstructor.add_constructor(
436        u'tag:yaml.org,2002:set',
437        SafeConstructor.construct_yaml_set)
438
439SafeConstructor.add_constructor(
440        u'tag:yaml.org,2002:str',
441        SafeConstructor.construct_yaml_str)
442
443SafeConstructor.add_constructor(
444        u'tag:yaml.org,2002:seq',
445        SafeConstructor.construct_yaml_seq)
446
447SafeConstructor.add_constructor(
448        u'tag:yaml.org,2002:map',
449        SafeConstructor.construct_yaml_map)
450
451SafeConstructor.add_constructor(None,
452        SafeConstructor.construct_undefined)
453
454class 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
706Constructor.add_constructor(
707    u'tag:yaml.org,2002:python/none',
708    Constructor.construct_yaml_null)
709
710Constructor.add_constructor(
711    u'tag:yaml.org,2002:python/bool',
712    Constructor.construct_yaml_bool)
713
714Constructor.add_constructor(
715    u'tag:yaml.org,2002:python/str',
716    Constructor.construct_python_str)
717
718Constructor.add_constructor(
719    u'tag:yaml.org,2002:python/unicode',
720    Constructor.construct_python_unicode)
721
722Constructor.add_constructor(
723    u'tag:yaml.org,2002:python/int',
724    Constructor.construct_yaml_int)
725
726Constructor.add_constructor(
727    u'tag:yaml.org,2002:python/long',
728    Constructor.construct_python_long)
729
730Constructor.add_constructor(
731    u'tag:yaml.org,2002:python/float',
732    Constructor.construct_yaml_float)
733
734Constructor.add_constructor(
735    u'tag:yaml.org,2002:python/complex',
736    Constructor.construct_python_complex)
737
738Constructor.add_constructor(
739    u'tag:yaml.org,2002:python/list',
740    Constructor.construct_yaml_seq)
741
742Constructor.add_constructor(
743    u'tag:yaml.org,2002:python/tuple',
744    Constructor.construct_python_tuple)
745
746Constructor.add_constructor(
747    u'tag:yaml.org,2002:python/dict',
748    Constructor.construct_yaml_map)
749
750Constructor.add_multi_constructor(
751    u'tag:yaml.org,2002:python/name:',
752    Constructor.construct_python_name)
753
754Constructor.add_multi_constructor(
755    u'tag:yaml.org,2002:python/module:',
756    Constructor.construct_python_module)
757
758Constructor.add_multi_constructor(
759    u'tag:yaml.org,2002:python/object:',
760    Constructor.construct_python_object)
761
762Constructor.add_multi_constructor(
763    u'tag:yaml.org,2002:python/object/apply:',
764    Constructor.construct_python_object_apply)
765
766Constructor.add_multi_constructor(
767    u'tag:yaml.org,2002:python/object/new:',
768    Constructor.construct_python_object_new)
769