Salome HOME
Merge branch 'V8_0_0_BR'
[tools/yacsgen.git] / module_generator / compat.py
1 #!/usr/bin/env python
2 #coding: iso-8859-15
3 #
4 # Copyright (C) 2005  GaĆ«tan Lehmann <gaetan.lehmann@jouy.inra.fr>
5 #
6 # this file is part of uptodate
7 #
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.
12 #
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.
17 #
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.
21 #
22
23 # this module sets python 2.3 compatibility
24
25
26 # python 2.4 now have set in __builtin__ module
27
28 import sets
29 set = sets.Set
30 del sets
31
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
34
35 def sorted(iterable, cmp=None, key=None, reverse=False) :
36         i = list(iterable)
37         if key :
38                 d = {}
39                 for v in iterable :
40                         k = key(v)
41                         if not d.has_key(k) :
42                                 d[k] = []
43                         d[k].append(v)
44                 keys = d.keys()
45                 keys.sort(cmp)
46                 i = []
47                 for k in keys :
48                         i += d[k]
49         else :
50                 i.sort(cmp)
51         if reverse :
52                 i.reverse()
53         return i
54         
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
58 import re
59 class _TemplateMetaclass(type):
60         pattern = r"""
61         %(delim)s(?:
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
66         )
67         """
68         
69         def __init__(cls, name, bases, dct):
70                 super(_TemplateMetaclass, cls).__init__(name, bases, dct)
71                 if 'pattern' in dct:
72                         pattern = cls.pattern
73                 else:
74                         pattern = _TemplateMetaclass.pattern % {
75                                 'delim' : re.escape(cls.delimiter),
76                                 'id'    : cls.idpattern,
77                                 }
78                 cls.pattern = re.compile(pattern, re.IGNORECASE | re.VERBOSE)
79
80
81 class Template:
82         """A string class for supporting $-substitutions."""
83         __metaclass__ = _TemplateMetaclass
84         
85         delimiter = '$'
86         idpattern = r'[_a-z][_a-z0-9]*'
87         
88         def __init__(self, template):
89                 self.template = template
90         
91         # Search for $$, $identifier, ${identifier}, and any bare $'s
92         
93         def _invalid(self, mo):
94                 i = mo.start('invalid')
95                 lines = self.template[:i].splitlines(True)
96                 if not lines:
97                         colno = 1
98                         lineno = 1
99                 else:
100                         colno = i - len(''.join(lines[:-1]))
101                         lineno = len(lines)
102                 raise ValueError('Invalid placeholder in string: line %d, col %d' %
103                                 (lineno, colno))
104         
105         def substitute(self, *args, **kws):
106                 if len(args) > 1:
107                         raise TypeError('Too many positional arguments')
108                 if not args:
109                         mapping = kws
110                 elif kws:
111                         mapping = _multimap(kws, args[0])
112                 else:
113                         mapping = args[0]
114                 # Helper function for .sub()
115                 def convert(mo):
116                         # Check the most common path first.
117                         named = mo.group('named') or mo.group('braced')
118                         if named is not None:
119                                 val = mapping[named]
120                                 # We use this idiom instead of str() because the latter will
121                                 # fail if val is a Unicode containing non-ASCII characters.
122                                 return '%s' % val
123                         if mo.group('escaped') is not None:
124                                 return self.delimiter
125                         if mo.group('invalid') is not None:
126                                 self._invalid(mo)
127                         raise ValueError('Unrecognized named group in pattern',
128                                         self.pattern)
129                 return self.pattern.sub(convert, self.template)
130         
131         def safe_substitute(self, *args, **kws):
132                 if len(args) > 1:
133                         raise TypeError('Too many positional arguments')
134                 if not args:
135                         mapping = kws
136                 elif kws:
137                         mapping = _multimap(kws, args[0])
138                 else:
139                         mapping = args[0]
140                 # Helper function for .sub()
141                 def convert(mo):
142                         named = mo.group('named')
143                         if named is not None:
144                                 try:
145                                         # We use this idiom instead of str() because the latter
146                                         # will fail if val is a Unicode containing non-ASCII
147                                         return '%s' % mapping[named]
148                                 except KeyError:
149                                         return self.delimiter + named
150                         braced = mo.group('braced')
151                         if braced is not None:
152                                 try:
153                                         return '%s' % mapping[braced]
154                                 except KeyError:
155                                         return self.delimiter + '{' + braced + '}'
156                         if mo.group('escaped') is not None:
157                                 return self.delimiter
158                         if mo.group('invalid') is not None:
159                                 return self.delimiter
160                         raise ValueError('Unrecognized named group in pattern',
161                                         self.pattern)
162                 return self.pattern.sub(convert, self.template)