Salome HOME
Copyright update 2022
[tools/yacsgen.git] / module_generator / compat.py
1 #!/usr/bin/env python
2 #coding: iso-8859-15
3 #
4 # Copyright (C) 2005-2022  EDF R&D
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 k not in d :
42                                 d[k] = []
43                         d[k].append(v)
44                 keys = list(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(metaclass=_TemplateMetaclass):
82         """A string class for supporting $-substitutions."""
83         
84         delimiter = '$'
85         idpattern = r'[_a-z][_a-z0-9]*'
86         
87         def __init__(self, template):
88                 self.template = template
89         
90         # Search for $$, $identifier, ${identifier}, and any bare $'s
91         
92         def _invalid(self, mo):
93                 i = mo.start('invalid')
94                 lines = self.template[:i].splitlines(True)
95                 if not lines:
96                         colno = 1
97                         lineno = 1
98                 else:
99                         colno = i - len(''.join(lines[:-1]))
100                         lineno = len(lines)
101                 raise ValueError('Invalid placeholder in string: line %d, col %d' %
102                                 (lineno, colno))
103         
104         def substitute(self, *args, **kws):
105                 if len(args) > 1:
106                         raise TypeError('Too many positional arguments')
107                 if not args:
108                         mapping = kws
109                 elif kws:
110                         mapping = _multimap(kws, args[0])
111                 else:
112                         mapping = args[0]
113                 # Helper function for .sub()
114                 def convert(mo):
115                         # Check the most common path first.
116                         named = mo.group('named') or mo.group('braced')
117                         if named is not None:
118                                 val = mapping[named]
119                                 # We use this idiom instead of str() because the latter will
120                                 # fail if val is a Unicode containing non-ASCII characters.
121                                 return '%s' % val
122                         if mo.group('escaped') is not None:
123                                 return self.delimiter
124                         if mo.group('invalid') is not None:
125                                 self._invalid(mo)
126                         raise ValueError('Unrecognized named group in pattern',
127                                         self.pattern)
128                 return self.pattern.sub(convert, self.template)
129         
130         def safe_substitute(self, *args, **kws):
131                 if len(args) > 1:
132                         raise TypeError('Too many positional arguments')
133                 if not args:
134                         mapping = kws
135                 elif kws:
136                         mapping = _multimap(kws, args[0])
137                 else:
138                         mapping = args[0]
139                 # Helper function for .sub()
140                 def convert(mo):
141                         named = mo.group('named')
142                         if named is not None:
143                                 try:
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]
147                                 except KeyError:
148                                         return self.delimiter + named
149                         braced = mo.group('braced')
150                         if braced is not None:
151                                 try:
152                                         return '%s' % mapping[braced]
153                                 except KeyError:
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',
160                                         self.pattern)
161                 return self.pattern.sub(convert, self.template)