Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/syck/loaders.py

    r25 r18  
    1 """ 
    2 syck.loaders is a high-level wrapper for the Syck YAML parser. 
    3 Do not use it directly, use the module 'syck' instead. 
    4 """ 
    51 
    62# Python 2.2 compatibility 
     
    2521import _syck 
    2622 
    27 import sys, re 
     23import re 
    2824 
    2925__all__ = ['GenericLoader', 'Loader', 
     
    3127 
    3228class GenericLoader(_syck.Parser): 
    33     """ 
    34     GenericLoader constructs primitive Python objects from YAML documents. 
    35     """ 
    3629 
    3730    def load(self): 
    38         """ 
    39         Loads a YAML document from the source and return a native Python 
    40         object. On EOF, returns None and set the eof attribute on. 
    41         """ 
    4231        node = self.parse() 
    4332        if self.eof: 
     
    6150                value_object = self._convert(node.value[key_node], 
    6251                        node_to_object) 
     52                if key_object in value: 
     53                    value = None 
     54                    break 
    6355                try: 
    64                     if key_object in value: 
    65                         value = None 
    66                         break 
    6756                    value[key_object] = value_object 
    6857                except TypeError: 
     
    7261                value = [] 
    7362                for key_node in node.value: 
    74                     key_object = self._convert(key_node, node_to_object) 
     63                    key_object = self_convert(key_node, node_to_object) 
    7564                    value_object = self._convert(node.value[key_node], 
    7665                            node_to_object) 
     
    8271 
    8372    def construct(self, node): 
    84         """Constructs a Python object by the given node.""" 
    8573        return node.value 
    8674 
    8775class Merge: 
    88     """Represents the merge key '<<'.""" 
    8976    pass 
    9077 
    9178class Default: 
    92     """Represents the default key '='.""" 
    9379    pass 
    9480 
    9581class Loader(GenericLoader): 
    96     """ 
    97     Loader constructs native Python objects from YAML documents. 
    98     """ 
    9982 
    10083    inf_value = 1e300000 
    10184    nan_value = inf_value/inf_value 
    10285 
     86    ymd_expr = re.compile(r'(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)') 
    10387    timestamp_expr = re.compile(r'(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)' 
    10488            r'(?:' 
     
    11195    default_key = Default() 
    11296 
    113     non_ascii = [] 
    114     for i in range(256): 
    115         ch = chr(i) 
    116         if ch.isalnum(): 
    117             non_ascii.append(ch) 
    118         else: 
    119             non_ascii.append('_') 
    120     non_ascii = ''.join(non_ascii) 
    121  
    122     python_bools = {'True': True, 'False': False} 
    123  
    124     class python_class: 
    125         pass 
    126  
    127     def find_constructor(self, node): 
    128         """ 
    129         Returns the contructor for generating a Python object for the given 
    130         node. 
    131  
    132         The node tags are mapped to constructors by the following rule: 
    133  
    134         Tag                             Constructor 
    135         ---                             ----------- 
    136         tag:yaml.org,2002:type          construct_type 
    137         tag:python.yaml.org,2002:type   construct_python_type 
    138         x-private:type                  construct_private_type 
    139         tag:domain.tld,2002:type        construct_domain_tld_2002_type 
    140  
    141         See the method code for more details. 
    142         """ 
    143         parts = [] 
    144         if node.tag: 
    145             parts = node.tag.split(':') 
    146         if parts: 
    147             if parts[0] == 'tag': 
    148                 parts.pop(0) 
    149                 if parts: 
    150                     if parts[0] == 'yaml.org,2002': 
    151                         parts.pop(0) 
    152                     elif parts[0] == 'python.yaml.org,2002': 
    153                         parts[0] = 'python' 
    154             elif parts[0] == 'x-private': 
    155                 parts[0] = 'private' 
    156         parts = [part.translate(self.non_ascii) for part in parts] 
    157         while parts: 
    158             method = 'construct_'+'_'.join(parts) 
    159             if hasattr(self, method): 
    160                 return getattr(self, method) 
    161             parts.pop() 
     97    def __init__(self, *args, **kwds): 
     98        super(Loader, self).__init__(*args, **kwds) 
     99        self.tags = {} 
     100        self.add_builtin_types() 
     101 
     102    def add_builtin_types(self): 
     103        self.add_builtin_type('null', lambda node: None) 
     104        self.add_builtin_type('bool#yes', lambda node: True) 
     105        self.add_builtin_type('bool#no', lambda node: False) 
     106        self.add_builtin_type('float#fix', lambda node: float(node.value)) 
     107        self.add_builtin_type('float#exp', lambda node: float(node.value)) 
     108        self.add_builtin_type('float#base60', 'construct_base60_float') 
     109        self.add_builtin_type('float#inf', lambda node: self.inf_value) 
     110        self.add_builtin_type('float#neginf', lambda node: -self.inf_value) 
     111        self.add_builtin_type('float#nan', lambda node: self.nan_value) 
     112        self.add_builtin_type('int', lambda node: int(node.value)) 
     113        self.add_builtin_type('int#hex', lambda node: int(node.value, 16)) 
     114        self.add_builtin_type('int#oct', lambda node: int(node.value, 8)) 
     115        self.add_builtin_type('int#base60', 'construct_base60_int') 
     116        self.add_builtin_type('binary', lambda node: node.value.decode('base64')) 
     117        self.add_builtin_type('timestamp#ymd', 'construct_timestamp') 
     118        self.add_builtin_type('timestamp#iso8601', 'construct_timestamp') 
     119        self.add_builtin_type('timestamp#spaced', 'construct_timestamp') 
     120        self.add_builtin_type('timestamp', 'construct_timestamp') 
     121        self.add_builtin_type('merge', 'construct_merge') 
     122        self.add_builtin_type('default', 'construct_default') 
     123        self.add_builtin_type('omap', 'construct_omap') 
     124        self.add_builtin_type('pairs', 'construct_pairs') 
     125        self.add_builtin_type('set', 'construct_set') 
     126 
     127    def add_type(self, type_tag, constuctor): 
     128        self.tags[type_tag] = constructor 
     129 
     130    def add_domain_type(self, domain, type_tag, constructor): 
     131        self.tags['tag:%s:%s' % (domain, type_tag)] = constructor 
     132 
     133    def add_builtin_type(self, type_tag, constructor): 
     134        self.tags['tag:yaml.org,2002:'+type_tag] = constructor 
     135 
     136    def add_python_type(self, type_tag, constructor): 
     137        self.tags['tag:python.yaml.org,2002:'+type_tag] = constructor 
     138 
     139    def add_private_type(self, type_tag, constructor): 
     140        self.tags['x-private:'+type_tag] = constructor 
    162141 
    163142    def construct(self, node): 
    164         """Constructs a Python object by the given node.""" 
    165143        if node.kind == 'map' and self.merge_key in node.value: 
    166144            self.merge_maps(node) 
    167         constructor = self.find_constructor(node) 
    168         if constructor: 
     145        if node.tag in self.tags: 
     146            constructor = self.tags[node.tag] 
     147            if isinstance(constructor, str): 
     148                constructor = getattr(self, constructor) 
    169149            return constructor(node) 
    170150        else: 
    171151            return node.value 
    172152 
    173     def construct_null(self, node): 
    174         return None 
    175  
    176     def construct_bool_yes(self, node): 
    177         return True 
    178  
    179     def construct_bool_no(self, node): 
    180         return False 
    181  
    182     def construct_numeric_base60(self, num_type, node): 
     153    def construct_base60_float(self, node): 
     154        return self.construct_base60(float, node) 
     155 
     156    def construct_base60_int(self, node): 
     157        return self.construct_base60(int, node) 
     158 
     159    def construct_base60(self, num_type, node): 
    183160        digits = [num_type(part) for part in node.value.split(':')] 
    184161        digits.reverse() 
     
    189166            base *= 60 
    190167        return value 
    191  
    192     def construct_int(self, node): 
    193         return int(node.value) 
    194  
    195     def construct_int_hex(self, node): 
    196         return int(node.value, 16) 
    197  
    198     def construct_int_oct(self, node): 
    199         return int(node.value, 8) 
    200  
    201     def construct_int_base60(self, node): 
    202         return self.construct_numeric_base60(int, node) 
    203  
    204     def construct_float(self, node): 
    205         return float(node.value) 
    206     construct_float_fix = construct_float 
    207     construct_float_exp = construct_float 
    208  
    209     def construct_float_base60(self, node): 
    210         return self.construct_numeric_base60(float, node) 
    211  
    212     def construct_float_inf(self, node): 
    213         return self.inf_value 
    214  
    215     def construct_float_neginf(self, node): 
    216         return -self.inf_value 
    217  
    218     def construct_float_nan(self, node): 
    219         return self.nan_value 
    220  
    221     def construct_binary(self, node): 
    222         return node.value.decode('base64') 
    223168 
    224169    def construct_timestamp(self, node): 
     
    238183        diff = datetime.timedelta(hours=values['zhour'], minutes=values['zminute']) 
    239184        return stamp-diff 
    240     construct_timestamp_ymd = construct_timestamp 
    241     construct_timestamp_iso8601 = construct_timestamp 
    242     construct_timestamp_spaced = construct_timestamp 
    243185 
    244186    def construct_merge(self, node): 
     
    275217        return sets.Set(node.value) 
    276218 
    277     def construct_python_none(self, node): 
    278         return None 
    279  
    280     def construct_python_bool(self, node): 
    281         return self.python_bools[node.value] 
    282  
    283     def construct_python_int(self, node): 
    284         return int(node.value) 
    285  
    286     def construct_python_long(self, node): 
    287         return long(node.value) 
    288  
    289     def construct_python_float(self, node): 
    290         return float(node.value) 
    291  
    292     def construct_python_str(self, node): 
    293         return str(node.value) 
    294  
    295     def construct_python_unicode(self, node): 
    296         return unicode(node.value, 'utf-8') 
    297  
    298     def construct_python_list(self, node): 
    299         return node.value 
    300  
    301     def construct_python_tuple(self, node): 
    302         return tuple(node.value) 
    303  
    304     def construct_python_dict(self, node): 
    305         return node.value 
    306  
    307     def find_python_object(self, node): 
    308         full_name = node.tag.split(':')[3] 
    309         parts = full_name.split('.') 
    310         object_name = parts.pop() 
    311         module_name = '.'.join(parts) 
    312         if not module_name: 
    313             module_name = '__builtin__' 
    314         else: 
    315             __import__(module_name) 
    316         return getattr(sys.modules[module_name], object_name) 
    317  
    318     def find_python_state(self, node): 
    319         if node.kind == 'seq': 
    320             args = node.value 
    321             kwds = {} 
    322             state = {} 
    323         else: 
    324             args = node.value.get('args', []) 
    325             kwds = node.value.get('kwds', {}) 
    326             state = node.value.get('state', {}) 
    327         return args, kwds, state 
    328  
    329     def set_python_state(self, object, state): 
    330         if hasattr(object, '__setstate__'): 
    331             object.__setstate__(state) 
    332         else: 
    333             slotstate = {} 
    334             if isinstance(state, tuple) and len(state) == 2: 
    335                 state, slotstate = state 
    336             if hasattr(object, '__dict__'): 
    337                 object.__dict__.update(state) 
    338             elif state: 
    339                 slotstate.update(state) 
    340             for key, value in slotstate.items(): 
    341                 setattr(object, key, value) 
    342  
    343     def construct_python_name(self, node): 
    344         return self.find_python_object(node) 
    345  
    346     def construct_python_object(self, node): 
    347         cls = self.find_python_object(node) 
    348         if type(cls) is type(self.python_class): 
    349             if hasattr(cls, '__getnewargs__'): 
    350                 object = cls() 
    351             else: 
    352                 object = self.python_class() 
    353                 object.__class__ = cls 
    354         else: 
    355             object = cls.__new__(cls) 
    356         self.set_python_state(object, node.value) 
    357         return object 
    358  
    359     def construct_python_new(self, node): 
    360         cls = self.find_python_object(node) 
    361         args, kwds, state = self.find_python_state(node) 
    362         if type(cls) is type(self.python_class): 
    363             object = cls(*args, **kwds) 
    364         else: 
    365             object = cls.__new__(cls, *args, **kwds) 
    366         self.set_python_state(object, state) 
    367         return object 
    368  
    369     def construct_python_apply(self, node): 
    370         constructor = self.find_python_object(node) 
    371         args, kwds, state = self.find_python_state(node) 
    372         object = constructor(*args, **kwds) 
    373         self.set_python_state(object, state) 
    374         return object 
    375  
    376 def parse(source, Loader=Loader, **parameters): 
     219def parse(source): 
    377220    """Parses 'source' and returns the root of the 'Node' graph.""" 
    378     loader = Loader(source, **parameters) 
     221    loader = Loader(source) 
    379222    return loader.parse() 
    380223 
    381 def load(source, Loader=Loader, **parameters): 
     224def load(source): 
    382225    """Parses 'source' and returns the root object.""" 
    383     loader = Loader(source, **parameters) 
     226    loader = Loader(source) 
    384227    return loader.load() 
    385228 
    386 def parse_documents(source, Loader=Loader, **parameters): 
    387     """Iterates over 'source' and yields the root 'Node' for each document.""" 
    388     loader = Loader(source, **parameters) 
     229def parse_documents(source): 
     230    """Iterates over 'source' and yields the root node of each document.""" 
     231    loader = Loader(source) 
    389232    while True: 
    390233        node = loader.parse() 
     
    393236        yield node 
    394237 
    395 def load_documents(source, Loader=Loader, **parameters): 
    396     """Iterates over 'source' and yields the root object for each document.""" 
    397     loader = Loader(source, **parameters) 
     238def load_documents(source): 
     239    """Iterates over 'source' and yields the root object of each document.""" 
     240    loader = Loader(source) 
    398241    while True: 
    399242        object = loader.load() 
Note: See TracChangeset for help on using the changeset viewer.