source: pyyaml/trunk/lib/yaml/constructor.py @ 234

Revision 234, 24.5 KB checked in by xi, 8 years ago (diff)

Fix loss of microsecond precision in datetime.datetime constructor (fix #30).
Thanks to edemaine@… for the bug report and the patch.

RevLine 
[55]1
[133]2__all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
3    'ConstructorError']
[57]4
[55]5from error import *
6from nodes import *
7
[225]8import datetime
[55]9
10try:
11    set
12except NameError:
13    from sets import Set as set
14
[139]15import binascii, re, sys
[55]16
17class ConstructorError(MarkedYAMLError):
18    pass
19
[222]20class BaseConstructor(object):
[55]21
[136]22    yaml_constructors = {}
23    yaml_multi_constructors = {}
24
25    def __init__(self):
[55]26        self.constructed_objects = {}
[142]27        self.recursive_objects = {}
[222]28        self.state_generators = []
29        self.deep_construct = False
[55]30
[136]31    def check_data(self):
[55]32        # If there are more documents available?
[136]33        return self.check_node()
[55]34
[136]35    def get_data(self):
[55]36        # Construct and return the next document.
[136]37        if self.check_node():
38            return self.construct_document(self.get_node())
[55]39
[222]40    def g(): yield None
41    generator_type = type(g())
42    del g
43
[55]44    def construct_document(self, node):
[136]45        data = self.construct_object(node)
[222]46        while self.state_generators:
47            state_generators = self.state_generators
48            self.state_generators = []
49            for generator in state_generators:
50                for dummy in generator:
51                    pass
[55]52        self.constructed_objects = {}
[142]53        self.recursive_objects = {}
[222]54        self.deep_construct = False
[136]55        return data
[55]56
[222]57    def construct_object(self, node, deep=False):
58        if deep:
59            old_deep = self.deep_construct
60            self.deep_construct = True
[55]61        if node in self.constructed_objects:
62            return self.constructed_objects[node]
[142]63        if node in self.recursive_objects:
64            raise ConstructorError(None, None,
[222]65                    "found unconstructable recursive node", node.start_mark)
[142]66        self.recursive_objects[node] = None
[136]67        constructor = None
[222]68        state_constructor = None
69        tag_suffix = None
[55]70        if node.tag in self.yaml_constructors:
[222]71            constructor = self.yaml_constructors[node.tag]
[136]72        else:
73            for tag_prefix in self.yaml_multi_constructors:
74                if node.tag.startswith(tag_prefix):
75                    tag_suffix = node.tag[len(tag_prefix):]
[222]76                    constructor = self.yaml_multi_constructors[tag_prefix]
[139]77                    break
[136]78            else:
79                if None in self.yaml_multi_constructors:
[222]80                    tag_suffix = node.tag
81                    constructor = self.yaml_multi_constructors[None]
[136]82                elif None in self.yaml_constructors:
[222]83                    constructor = self.yaml_constructors[None]
[136]84                elif isinstance(node, ScalarNode):
[222]85                    constructor = self.__class__.construct_scalar
[136]86                elif isinstance(node, SequenceNode):
[222]87                    constructor = self.__class__.construct_sequence
[136]88                elif isinstance(node, MappingNode):
[222]89                    constructor = self.__class__.construct_mapping
90        if tag_suffix is None:
91            data = constructor(self, node)
92        else:
93            data = constructor(self, tag_suffix, node)
94        if isinstance(data, self.generator_type):
95            generator = data
96            data = generator.next()
97            if self.deep_construct:
98                for dummy in generator:
99                    pass
100            else:
101                self.state_generators.append(generator)
[136]102        self.constructed_objects[node] = data
[142]103        del self.recursive_objects[node]
[222]104        if deep:
105            self.deep_construct = old_deep
[136]106        return data
[55]107
108    def construct_scalar(self, node):
109        if not isinstance(node, ScalarNode):
110            raise ConstructorError(None, None,
111                    "expected a scalar node, but found %s" % node.id,
[116]112                    node.start_mark)
[55]113        return node.value
114
[222]115    def construct_sequence(self, node, deep=False):
[55]116        if not isinstance(node, SequenceNode):
117            raise ConstructorError(None, None,
118                    "expected a sequence node, but found %s" % node.id,
[116]119                    node.start_mark)
[222]120        return [self.construct_object(child, deep=deep)
121                for child in node.value]
[55]122
[222]123    def construct_mapping(self, node, deep=False):
[55]124        if not isinstance(node, MappingNode):
125            raise ConstructorError(None, None,
126                    "expected a mapping node, but found %s" % node.id,
[116]127                    node.start_mark)
[55]128        mapping = {}
[222]129        for key_node, value_node in node.value:
130            key = self.construct_object(key_node, deep=deep)
131            try:
132                hash(key)
133            except TypeError, exc:
134                raise ConstructorError("while constructing a mapping", node.start_mark,
135                        "found unacceptable key (%s)" % exc, key_node.start_mark)
136            value = self.construct_object(value_node, deep=deep)
137            mapping[key] = value
[55]138        return mapping
139
[222]140    def construct_pairs(self, node, deep=False):
[55]141        if not isinstance(node, MappingNode):
142            raise ConstructorError(None, None,
143                    "expected a mapping node, but found %s" % node.id,
[116]144                    node.start_mark)
[55]145        pairs = []
[222]146        for key_node, value_node in node.value:
147            key = self.construct_object(key_node, deep=deep)
148            value = self.construct_object(value_node, deep=deep)
[55]149            pairs.append((key, value))
150        return pairs
151
152    def add_constructor(cls, tag, constructor):
153        if not 'yaml_constructors' in cls.__dict__:
154            cls.yaml_constructors = cls.yaml_constructors.copy()
155        cls.yaml_constructors[tag] = constructor
156    add_constructor = classmethod(add_constructor)
157
[136]158    def add_multi_constructor(cls, tag_prefix, multi_constructor):
159        if not 'yaml_multi_constructors' in cls.__dict__:
160            cls.yaml_multi_constructors = cls.yaml_multi_constructors.copy()
161        cls.yaml_multi_constructors[tag_prefix] = multi_constructor
162    add_multi_constructor = classmethod(add_multi_constructor)
[55]163
[133]164class SafeConstructor(BaseConstructor):
[55]165
[222]166    def construct_scalar(self, node):
167        if isinstance(node, MappingNode):
168            for key_node, value_node in node.value:
169                if key_node.tag == u'tag:yaml.org,2002:value':
170                    return self.construct_scalar(value_node)
171        return BaseConstructor.construct_scalar(self, node)
172
173    def flatten_mapping(self, node):
174        merge = []
175        index = 0
176        while index < len(node.value):
177            key_node, value_node = node.value[index]
178            if key_node.tag == u'tag:yaml.org,2002:merge':
179                del node.value[index]
180                if isinstance(value_node, MappingNode):
181                    self.flatten_mapping(value_node)
182                    merge.extend(value_node.value)
183                elif isinstance(value_node, SequenceNode):
184                    submerge = []
185                    for subnode in value_node.value:
186                        if not isinstance(subnode, MappingNode):
187                            raise ConstructorError("while constructing a mapping",
188                                    node.start_mark,
189                                    "expected a mapping for merging, but found %s"
190                                    % subnode.id, subnode.start_mark)
191                        self.flatten_mapping(subnode)
192                        submerge.append(subnode.value)
193                    submerge.reverse()
194                    for value in submerge:
195                        merge.extend(value)
196                else:
197                    raise ConstructorError("while constructing a mapping", node.start_mark,
198                            "expected a mapping or list of mappings for merging, but found %s"
199                            % value_node.id, value_node.start_mark)
200            elif key_node.tag == u'tag:yaml.org,2002:value':
201                key_node.tag = u'tag:yaml.org,2002:str'
202                index += 1
203            else:
204                index += 1
205        if merge:
206            node.value = merge + node.value
207
208    def construct_mapping(self, node, deep=False):
209        if isinstance(node, MappingNode):
210            self.flatten_mapping(node)
211        return BaseConstructor.construct_mapping(self, node, deep=deep)
212
[55]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
[168]258    inf_value = 1e300
[173]259    while inf_value != inf_value*inf_value:
[168]260        inf_value *= inf_value
[173]261    nan_value = -inf_value/inf_value   # Trying to make a quiet NaN (like C99).
[55]262
263    def construct_yaml_float(self, node):
264        value = str(self.construct_scalar(node))
[175]265        value = value.replace('_', '').lower()
[55]266        sign = +1
267        if value[0] == '-':
[58]268            sign = -1
[55]269        if value[0] in '+-':
270            value = value[1:]
[175]271        if value == '.inf':
[55]272            return sign*self.inf_value
[175]273        elif value == '.nan':
[55]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:
[170]285            return sign*float(value)
[55]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,
[116]293                    "failed to decode base64 data: %s" % exc, node.start_mark) 
[55]294
[56]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]?)
[58]299                (?:(?:[Tt]|[ \t]+)
[56]300                (?P<hour>[0-9][0-9]?)
301                :(?P<minute>[0-9][0-9])
302                :(?P<second>[0-9][0-9])
[234]303                (?:\.(?P<fraction>[0-9]*))?
[225]304                (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
305                (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
[56]306
307    def construct_yaml_timestamp(self, node):
308        value = self.construct_scalar(node)
[58]309        match = self.timestamp_regexp.match(node.value)
[56]310        values = match.groupdict()
[225]311        year = int(values['year'])
312        month = int(values['month'])
313        day = int(values['day'])
314        if not values['hour']:
315            return datetime.date(year, month, day)
316        hour = int(values['hour'])
317        minute = int(values['minute'])
318        second = int(values['second'])
319        fraction = 0
320        if values['fraction']:
[234]321            fraction = int(values['fraction'][:6].ljust(6, '0'))
[225]322        delta = None
323        if values['tz_sign']:
324            tz_hour = int(values['tz_hour'])
325            tz_minute = int(values['tz_minute'] or 0)
326            delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
327            if values['tz_sign'] == '-':
328                delta = -delta
329        data = datetime.datetime(year, month, day, hour, minute, second, fraction)
330        if delta:
331            data -= delta
332        return data
[56]333
334    def construct_yaml_omap(self, node):
335        # Note: we do not check for duplicate keys, because it's too
336        # CPU-expensive.
[222]337        omap = []
338        yield omap
[56]339        if not isinstance(node, SequenceNode):
[116]340            raise ConstructorError("while constructing an ordered map", node.start_mark,
341                    "expected a sequence, but found %s" % node.id, node.start_mark)
[56]342        for subnode in node.value:
343            if not isinstance(subnode, MappingNode):
[116]344                raise ConstructorError("while constructing an ordered map", node.start_mark,
[56]345                        "expected a mapping of length 1, but found %s" % subnode.id,
[116]346                        subnode.start_mark)
[58]347            if len(subnode.value) != 1:
[116]348                raise ConstructorError("while constructing an ordered map", node.start_mark,
[58]349                        "expected a single mapping item, but found %d items" % len(subnode.value),
[116]350                        subnode.start_mark)
[222]351            key_node, value_node = subnode.value[0]
[58]352            key = self.construct_object(key_node)
[222]353            value = self.construct_object(value_node)
[58]354            omap.append((key, value))
[56]355
356    def construct_yaml_pairs(self, node):
357        # Note: the same code as `construct_yaml_omap`.
[222]358        pairs = []
359        yield pairs
[56]360        if not isinstance(node, SequenceNode):
[116]361            raise ConstructorError("while constructing pairs", node.start_mark,
362                    "expected a sequence, but found %s" % node.id, node.start_mark)
[56]363        for subnode in node.value:
364            if not isinstance(subnode, MappingNode):
[116]365                raise ConstructorError("while constructing pairs", node.start_mark,
[56]366                        "expected a mapping of length 1, but found %s" % subnode.id,
[116]367                        subnode.start_mark)
[58]368            if len(subnode.value) != 1:
[116]369                raise ConstructorError("while constructing pairs", node.start_mark,
[58]370                        "expected a single mapping item, but found %d items" % len(subnode.value),
[116]371                        subnode.start_mark)
[222]372            key_node, value_node = subnode.value[0]
[58]373            key = self.construct_object(key_node)
[222]374            value = self.construct_object(value_node)
[58]375            pairs.append((key, value))
[56]376
377    def construct_yaml_set(self, node):
[222]378        data = set()
379        yield data
[56]380        value = self.construct_mapping(node)
[222]381        data.update(value)
[56]382
[55]383    def construct_yaml_str(self, node):
384        value = self.construct_scalar(node)
385        try:
386            return str(value)
387        except UnicodeEncodeError:
388            return value
389
[56]390    def construct_yaml_seq(self, node):
[222]391        data = []
392        yield data
393        data.extend(self.construct_sequence(node))
[56]394
395    def construct_yaml_map(self, node):
[222]396        data = {}
397        yield data
398        value = self.construct_mapping(node)
399        data.update(value)
[56]400
[136]401    def construct_yaml_object(self, node, cls):
402        data = cls.__new__(cls)
[222]403        yield data
[136]404        if hasattr(data, '__setstate__'):
[222]405            state = self.construct_mapping(node, deep=True)
[139]406            data.__setstate__(state)
[136]407        else:
[222]408            state = self.construct_mapping(node)
[139]409            data.__dict__.update(state)
[136]410
[57]411    def construct_undefined(self, node):
412        raise ConstructorError(None, None,
413                "could not determine a constructor for the tag %r" % node.tag.encode('utf-8'),
[116]414                node.start_mark)
[57]415
[133]416SafeConstructor.add_constructor(
[55]417        u'tag:yaml.org,2002:null',
[133]418        SafeConstructor.construct_yaml_null)
[55]419
[133]420SafeConstructor.add_constructor(
[55]421        u'tag:yaml.org,2002:bool',
[133]422        SafeConstructor.construct_yaml_bool)
[55]423
[133]424SafeConstructor.add_constructor(
[55]425        u'tag:yaml.org,2002:int',
[133]426        SafeConstructor.construct_yaml_int)
[55]427
[133]428SafeConstructor.add_constructor(
[55]429        u'tag:yaml.org,2002:float',
[133]430        SafeConstructor.construct_yaml_float)
[55]431
[133]432SafeConstructor.add_constructor(
[58]433        u'tag:yaml.org,2002:binary',
[133]434        SafeConstructor.construct_yaml_binary)
[56]435
[225]436SafeConstructor.add_constructor(
437        u'tag:yaml.org,2002:timestamp',
438        SafeConstructor.construct_yaml_timestamp)
[58]439
[133]440SafeConstructor.add_constructor(
[56]441        u'tag:yaml.org,2002:omap',
[133]442        SafeConstructor.construct_yaml_omap)
[56]443
[133]444SafeConstructor.add_constructor(
[56]445        u'tag:yaml.org,2002:pairs',
[133]446        SafeConstructor.construct_yaml_pairs)
[56]447
[133]448SafeConstructor.add_constructor(
[56]449        u'tag:yaml.org,2002:set',
[133]450        SafeConstructor.construct_yaml_set)
[56]451
[133]452SafeConstructor.add_constructor(
[55]453        u'tag:yaml.org,2002:str',
[133]454        SafeConstructor.construct_yaml_str)
[55]455
[133]456SafeConstructor.add_constructor(
[56]457        u'tag:yaml.org,2002:seq',
[133]458        SafeConstructor.construct_yaml_seq)
[56]459
[133]460SafeConstructor.add_constructor(
[56]461        u'tag:yaml.org,2002:map',
[133]462        SafeConstructor.construct_yaml_map)
[56]463
[133]464SafeConstructor.add_constructor(None,
465        SafeConstructor.construct_undefined)
[57]466
[133]467class Constructor(SafeConstructor):
[55]468
[139]469    def construct_python_str(self, node):
470        return self.construct_scalar(node).encode('utf-8')
471
472    def construct_python_unicode(self, node):
473        return self.construct_scalar(node)
474
475    def construct_python_long(self, node):
476        return long(self.construct_yaml_int(node))
477
478    def construct_python_complex(self, node):
479       return complex(self.construct_scalar(node))
480
481    def construct_python_tuple(self, node):
[222]482        return tuple(self.construct_sequence(node))
[139]483
484    def find_python_module(self, name, mark):
485        if not name:
486            raise ConstructorError("while constructing a Python module", mark,
487                    "expected non-empty name appended to the tag", mark)
488        try:
489            __import__(name)
490        except ImportError, exc:
491            raise ConstructorError("while constructing a Python module", mark,
492                    "cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
493        return sys.modules[name]
494
495    def find_python_name(self, name, mark):
496        if not name:
497            raise ConstructorError("while constructing a Python object", mark,
498                    "expected non-empty name appended to the tag", mark)
499        if u'.' in name:
[146]500            # Python 2.4 only
501            #module_name, object_name = name.rsplit('.', 1)
502            items = name.split('.')
503            object_name = items.pop()
504            module_name = '.'.join(items)
[139]505        else:
506            module_name = '__builtin__'
507            object_name = name
508        try:
509            __import__(module_name)
510        except ImportError, exc:
511            raise ConstructorError("while constructing a Python object", mark,
512                    "cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
513        module = sys.modules[module_name]
514        if not hasattr(module, object_name):
515            raise ConstructorError("while constructing a Python object", mark,
516                    "cannot find %r in the module %r" % (object_name.encode('utf-8'),
517                        module.__name__), mark)
518        return getattr(module, object_name)
519
520    def construct_python_name(self, suffix, node):
521        value = self.construct_scalar(node)
522        if value:
523            raise ConstructorError("while constructing a Python name", node.start_mark,
524                    "expected the empty value, but found %r" % value.encode('utf-8'),
525                    node.start_mark)
526        return self.find_python_name(suffix, node.start_mark)
527
528    def construct_python_module(self, suffix, node):
529        value = self.construct_scalar(node)
530        if value:
531            raise ConstructorError("while constructing a Python module", node.start_mark,
532                    "expected the empty value, but found %r" % value.encode('utf-8'),
533                    node.start_mark)
534        return self.find_python_module(suffix, node.start_mark)
535
[147]536    class classobj: pass
537
538    def make_python_instance(self, suffix, node,
539            args=None, kwds=None, newobj=False):
540        if not args:
541            args = []
542        if not kwds:
543            kwds = {}
544        cls = self.find_python_name(suffix, node.start_mark)
545        if newobj and isinstance(cls, type(self.classobj))  \
546                and not args and not kwds:
547            instance = self.classobj()
548            instance.__class__ = cls
549            return instance
550        elif newobj and isinstance(cls, type):
551            return cls.__new__(cls, *args, **kwds)
552        else:
553            return cls(*args, **kwds)
554
555    def set_python_instance_state(self, instance, state):
556        if hasattr(instance, '__setstate__'):
557            instance.__setstate__(state)
558        else:
559            slotstate = {}
560            if isinstance(state, tuple) and len(state) == 2:
561                state, slotstate = state
562            if hasattr(instance, '__dict__'):
563                instance.__dict__.update(state)
564            elif state:
565                slotstate.update(state)
566            for key, value in slotstate.items():
567                setattr(object, key, value)
568
569    def construct_python_object(self, suffix, node):
570        # Format:
571        #   !!python/object:module.name { ... state ... }
572        instance = self.make_python_instance(suffix, node, newobj=True)
[222]573        yield instance
574        deep = hasattr(instance, '__setstate__')
575        state = self.construct_mapping(node, deep=deep)
[147]576        self.set_python_instance_state(instance, state)
577
578    def construct_python_object_apply(self, suffix, node, newobj=False):
579        # Format:
580        #   !!python/object/apply       # (or !!python/object/new)
581        #   args: [ ... arguments ... ]
582        #   kwds: { ... keywords ... }
583        #   state: ... state ...
584        #   listitems: [ ... listitems ... ]
585        #   dictitems: { ... dictitems ... }
586        # or short format:
587        #   !!python/object/apply [ ... arguments ... ]
588        # The difference between !!python/object/apply and !!python/object/new
589        # is how an object is created, check make_python_instance for details.
590        if isinstance(node, SequenceNode):
[222]591            args = self.construct_sequence(node, deep=True)
[147]592            kwds = {}
593            state = {}
594            listitems = []
595            dictitems = {}
596        else:
[222]597            value = self.construct_mapping(node, deep=True)
[147]598            args = value.get('args', [])
599            kwds = value.get('kwds', {})
600            state = value.get('state', {})
601            listitems = value.get('listitems', [])
602            dictitems = value.get('dictitems', {})
603        instance = self.make_python_instance(suffix, node, args, kwds, newobj)
604        if state:
605            self.set_python_instance_state(instance, state)
606        if listitems:
607            instance.extend(listitems)
608        if dictitems:
609            for key in dictitems:
610                instance[key] = dictitems[key]
611        return instance
612
613    def construct_python_object_new(self, suffix, node):
614        return self.construct_python_object_apply(suffix, node, newobj=True)
615
[139]616Constructor.add_constructor(
617    u'tag:yaml.org,2002:python/none',
618    Constructor.construct_yaml_null)
619
620Constructor.add_constructor(
621    u'tag:yaml.org,2002:python/bool',
622    Constructor.construct_yaml_bool)
623
624Constructor.add_constructor(
625    u'tag:yaml.org,2002:python/str',
626    Constructor.construct_python_str)
627
628Constructor.add_constructor(
629    u'tag:yaml.org,2002:python/unicode',
630    Constructor.construct_python_unicode)
631
632Constructor.add_constructor(
633    u'tag:yaml.org,2002:python/int',
634    Constructor.construct_yaml_int)
635
636Constructor.add_constructor(
637    u'tag:yaml.org,2002:python/long',
638    Constructor.construct_python_long)
639
640Constructor.add_constructor(
641    u'tag:yaml.org,2002:python/float',
642    Constructor.construct_yaml_float)
643
644Constructor.add_constructor(
645    u'tag:yaml.org,2002:python/complex',
646    Constructor.construct_python_complex)
647
648Constructor.add_constructor(
649    u'tag:yaml.org,2002:python/list',
650    Constructor.construct_yaml_seq)
651
652Constructor.add_constructor(
653    u'tag:yaml.org,2002:python/tuple',
654    Constructor.construct_python_tuple)
655
656Constructor.add_constructor(
657    u'tag:yaml.org,2002:python/dict',
658    Constructor.construct_yaml_map)
659
660Constructor.add_multi_constructor(
661    u'tag:yaml.org,2002:python/name:',
662    Constructor.construct_python_name)
663
664Constructor.add_multi_constructor(
665    u'tag:yaml.org,2002:python/module:',
666    Constructor.construct_python_module)
667
[147]668Constructor.add_multi_constructor(
669    u'tag:yaml.org,2002:python/object:',
670    Constructor.construct_python_object)
671
672Constructor.add_multi_constructor(
673    u'tag:yaml.org,2002:python/object/apply:',
674    Constructor.construct_python_object_apply)
675
676Constructor.add_multi_constructor(
677    u'tag:yaml.org,2002:python/object/new:',
678    Constructor.construct_python_object_new)
679
Note: See TracBrowser for help on using the repository browser.