4 # Copyright (C) 2005 Gaƫtan Lehmann <gaetan.lehmann@jouy.inra.fr>
6 # this file is part of uptodate
8 # This program is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU General Public License
10 # as published by the Free Software Foundation; either version 2
11 # of the License, or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 # this module sets python 2.3 compatibility
26 # python 2.4 now have set in __builtin__ module
32 # python 2.4 enhance sort method in list object with key and reverse parameters, and introduced sorted function which do the same as sort but on a copied list
33 # as it's far more difficult to modify sort method, we implement a sorted fuction for python 2.3
35 def sorted(iterable, cmp=None, key=None, reverse=False) :
55 # string.Template allow us to create templated command without problem :
56 # configparser use standard substitution, so an error in template can make the config file invalid. With the new template, we avoid this problem
57 # thoses classes are stollen from python 2.4 string module
59 class _TemplateMetaclass(type):
62 (?P<escaped>%(delim)s) | # Escape sequence of two delimiters
63 (?P<named>%(id)s) | # delimiter and a Python identifier
64 {(?P<braced>%(id)s)} | # delimiter and a braced identifier
65 (?P<invalid>) # Other ill-formed delimiter exprs
69 def __init__(cls, name, bases, dct):
70 super(_TemplateMetaclass, cls).__init__(name, bases, dct)
74 pattern = _TemplateMetaclass.pattern % {
75 'delim' : re.escape(cls.delimiter),
78 cls.pattern = re.compile(pattern, re.IGNORECASE | re.VERBOSE)
81 class Template(metaclass=_TemplateMetaclass):
82 """A string class for supporting $-substitutions."""
85 idpattern = r'[_a-z][_a-z0-9]*'
87 def __init__(self, template):
88 self.template = template
90 # Search for $$, $identifier, ${identifier}, and any bare $'s
92 def _invalid(self, mo):
93 i = mo.start('invalid')
94 lines = self.template[:i].splitlines(True)
99 colno = i - len(''.join(lines[:-1]))
101 raise ValueError('Invalid placeholder in string: line %d, col %d' %
104 def substitute(self, *args, **kws):
106 raise TypeError('Too many positional arguments')
110 mapping = _multimap(kws, args[0])
113 # Helper function for .sub()
115 # Check the most common path first.
116 named = mo.group('named') or mo.group('braced')
117 if named is not None:
119 # We use this idiom instead of str() because the latter will
120 # fail if val is a Unicode containing non-ASCII characters.
122 if mo.group('escaped') is not None:
123 return self.delimiter
124 if mo.group('invalid') is not None:
126 raise ValueError('Unrecognized named group in pattern',
128 return self.pattern.sub(convert, self.template)
130 def safe_substitute(self, *args, **kws):
132 raise TypeError('Too many positional arguments')
136 mapping = _multimap(kws, args[0])
139 # Helper function for .sub()
141 named = mo.group('named')
142 if named is not None:
144 # We use this idiom instead of str() because the latter
145 # will fail if val is a Unicode containing non-ASCII
146 return '%s' % mapping[named]
148 return self.delimiter + named
149 braced = mo.group('braced')
150 if braced is not None:
152 return '%s' % mapping[braced]
154 return self.delimiter + '{' + braced + '}'
155 if mo.group('escaped') is not None:
156 return self.delimiter
157 if mo.group('invalid') is not None:
158 return self.delimiter
159 raise ValueError('Unrecognized named group in pattern',
161 return self.pattern.sub(convert, self.template)