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

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

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