Variable.py
Go to the documentation of this file.
1 '''
2 Created on Jun 27, 2011
3 
4 @author: mplajner
5 '''
6 import re
7 import os
8 import logging
9 from os.path import normpath
10 from zipfile import is_zipfile
11 
12 class VariableProcessor(object):
13  '''
14  Base class for the objects used to process the variables.
15  '''
16  def __init__(self, env):
17  '''
18  @param env: dictionary with the reference environment to use
19  '''
20  if env is None:
21  env = {}
22  self._env = env
23 
24  def isTarget(self, variable):
25  '''
26  Return True if this processor can operate on the given variable.
27  '''
28  return True
29 
30  def process(self, variable, value):
31  '''
32  Process the variable.
33 
34  @param value: the content of the variable to be processed
35  @return: the processed value
36  '''
37  # by default do nothing
38  return value
39 
40  def __call__(self, variable, value):
41  return self.process(variable, value)
42 
44  '''
45  Base class for processors operating only on lists.
46  '''
47  def isTarget(self, variable):
48  '''
49  Return True if this variable is a list.
50  '''
51  return isinstance(variable, List)
52 
54  '''
55  Base class for processors operating only on scalars.
56  '''
57  def isTarget(self, variable):
58  '''
59  Return True if this variable is a scalar.
60  '''
61  return isinstance(variable, Scalar)
62 
64  '''
65  Variable processor to expand the reference to environment variables.
66  '''
67  def __init__(self, env):
68  super(EnvExpander, self).__init__(env)
69  self._exp = re.compile(r"\$([A-Za-z_][A-Za-z0-9_]*)|\$\(([A-Za-z_][A-Za-z0-9_]*)\)|\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$\{(\.)\}")
70 
71  def isTarget(self, variable):
72  return (super(EnvExpander, self).isTarget(variable)
73  and variable.expandVars)
74 
75  def _repl(self, value):
76  m = self._exp.search(value)
77  if m:
78  try:
79  value = (value[:m.start()]
80  + str(self._env[filter(None, m.groups())[0]])
81  + value[m.end():])
82  except KeyError, k:
83  logging.debug('KeyError: %s unknown while expanding %s', k, value)
84  return value
85  return self._repl(value)
86  else:
87  return value
88 
89  def process(self, variable, value):
90  if isinstance(value, str):
91  value = self._repl(value)
92  else:
93  # expand only in the elements that are new
94  old_values = set(variable.val)
95  value = map(lambda v: v if v in old_values else self._repl(v), value)
96  return value
97 
99  '''
100  Call os.path.normpath for all the entries of the variable.
101  '''
102  def process(self, variable, value):
103  if not value: # do not process empty strings/lists
104  return value
105  if isinstance(value, str):
106  if '://' not in value: # this might be a URL
107  value = normpath(value)
108  else:
109  value = [normpath(v) for v in value if v]
110  return value
111 
113  '''
114  Remove duplicates entries from lists.
115  '''
116  def process(self, variable, value):
117  val = []
118  for s in value:
119  if s not in val:
120  val.append(s)
121  return val
122 
124  '''
125  Remove empty or not existing directories from lists.
126  '''
127  def process(self, variable, value):
128  from os.path import isdir
129  from os import listdir
130  return [s for s in value if s.endswith('.zip') or (isdir(s) and listdir(s))]
131 
133  '''
134  Use .zip files instead of regular directories in PYTHONPATH when possible.
135  '''
136  def isTarget(self, variable):
137  return (super(UsePythonZip, self).isTarget(variable)
138  and variable.varName == 'PYTHONPATH')
139 
140  def process(self, variable, value):
141  val = []
142  for s in value:
143  z = s + '.zip'
144  if is_zipfile(z):
145  val.append(z)
146  else:
147  val.append(s)
148  return val
149 
150 # Default (minimal) set of processors.
151 processors = [ EnvExpander, PathNormalizer, DuplicatesRemover,
152  # special processors
153  EmptyDirsRemover, UsePythonZip
154  ]
155 
156 # FIXME: these are back-ward compatibility hacks: we need a proper way to add/remove processors
157 if ('no-strip-path' in os.environ.get('CMTEXTRATAGS', '')
158  or 'GAUDI_NO_STRIP_PATH' in os.environ
159  or 'LB_NO_STRIP_PATH' in os.environ):
160  processors.remove(EmptyDirsRemover)
161 
162 if 'no-pyzip' in os.environ.get('CMTEXTRATAGS', ''):
163  processors.remove(UsePythonZip)
164 
165 class VariableBase(object):
166  '''
167  Base class for the classes used to manipulate the environment.
168  '''
169 
170  def __init__(self, name, local=False):
171  self.varName = name
172  self.local = local
173  self.expandVars = True
174  self.log = logging.getLogger('Variable')
175 
176  def process(self, value, env):
177  '''
178  Call all the processors defined in the processors list on 'value'.
179 
180  @return: the processed value
181  '''
182  for p in [c(env) for c in processors]:
183  if p.isTarget(self):
184  value = p(self, value)
185  return value
186 
188  '''
189  Class for manipulating with environment lists.
190 
191  It holds its name and values represented by a list.
192  Some operations are done with separator, which is usually colon. For windows use semicolon.
193  '''
194 
195  def __init__(self, name, local=False):
196  super(List, self).__init__(name, local)
197  self.val = []
198 
199  def name(self):
200  '''Returns the name of the List.'''
201  return self.varName
202 
203  def set(self, value, separator=':', environment=None):
204  '''Sets the value of the List. Any previous value is overwritten.'''
205  if isinstance(value, str):
206  value = value.split(separator)
207  self.val = self.process(value, environment)
208 
209  def unset(self, value, separator=':', environment=None):# pylint: disable=W0613
210  '''Sets the value of the List to empty. Any previous value is overwritten.'''
211  self.val = []
212 
213  def value(self, asString=False, separator=':'):
214  '''Returns values of the List. Either as a list or string with desired separator.'''
215  if asString:
216  return separator.join(self.val)
217  else:
218  # clone the list
219  return list(self.val)
220 
221  def remove_regexp(self, value, separator = ':'):
222  self.remove(value, separator, True)
223 
224  def remove(self, value, separator=':', regexp=False):
225  '''Removes value(s) from List. If value is not found, removal is canceled.'''
226  if regexp:
227  value = self.search(value, True)
228 
229  elif isinstance(value,str):
230  value = value.split(separator)
231 
232  for i in range(len(value)):
233  val = value[i]
234  if val not in value:
235  self.log.info('Value "%s" not found in List: "%s". Removal canceled.', val, self.varName)
236  while val in self.val:
237  self.val.remove(val)
238 
239 
240  def append(self, value, separator=':', environment=None):
241  '''Adds value(s) at the end of the list.'''
242  if isinstance(value, str):
243  value = value.split(separator)
244  self.val = self.process(self.val + value, environment)
245 
246  def prepend(self, value, separator=':', environment=None):
247  '''Adds value(s) at the beginning of the list.
248  resolve references and duplications'''
249  if isinstance(value, str):
250  value = value.split(separator)
251  self.val = self.process(value + self.val, environment)
252 
253  def search(self, expr, regExp):
254  '''Searches in List's values for a match
255 
256  Use string value or set regExp to True.
257  In the first case search is done only for an exact match for one of List`s value ('^' and '$' added).
258  '''
259  if not regExp:
260  expr = '^' + expr + '$'
261  v = re.compile(expr)
262  res = []
263  for val in self.val:
264  if v.search(val):
265  res.append(val)
266 
267  return res
268 
269  def __getitem__(self, key):
270  return self.val[key]
271 
272  def __setitem__(self, key, value):
273  if value in self.val:
274  self.log.info('Var: "%s" value: "%s". Addition canceled because of duplicate entry.', self.varName, value)
275  else:
276  self.val.insert(key, value)
277 
278  def __delitem__(self, key):
279  self.remove(self.val[key])
280 
281  def __iter__(self):
282  for i in self.val:
283  yield i
284 
285  def __contains__(self, item):
286  return item in self.val
287 
288  def __len__(self):
289  return len(self.val)
290 
291  def __str__(self):
292  return ':'.join(self.val)
293 
294 
296  '''Class for manipulating with environment scalars.'''
297 
298  def __init__(self, name, local=False):
299  super(Scalar, self).__init__(name, local)
300  self.val = ''
301 
302  def name(self):
303  '''Returns the name of the scalar.'''
304  return self.varName
305 
306  def set(self, value, separator=':', environment=None):# pylint: disable=W0613
307  '''Sets the value of the scalar. Any previous value is overwritten.'''
308  self.val = self.process(value, environment)
309 
310  def unset(self, value, separator=':', environment=None):# pylint: disable=W0613
311  '''Sets the value of the variable to empty. Any previous value is overwritten.'''
312  self.val = ''
313 
314  def value(self, asString=False, separator=':'):# pylint: disable=W0613
315  '''Returns values of the scalar.'''
316  return self.val
317 
318  def remove_regexp(self, value, separator=':'):
319  self.remove(value, separator, True)
320 
321  def remove(self, value, separator=':', regexp=True):# pylint: disable=W0613
322  '''Removes value(s) from the scalar. If value is not found, removal is canceled.'''
323  value = self.search(value)
324  for val in value:
325  self.val = self.val.replace(val, '')
326 
327  def append(self, value, separator=':', environment=None):# pylint: disable=W0613
328  '''Adds value(s) at the end of the scalar.'''
329  self.val += self.process(value, environment)
330 
331  def prepend(self, value, separator=':', environment=None):# pylint: disable=W0613
332  '''Adds value(s) at the beginning of the scalar.'''
333  self.val = self.process(value, environment) + self.val
334 
335  def search(self, expr):
336  '''Searches in scalar`s values for a match'''
337  return re.findall(expr, self.val)
338 
339  def __str__(self):
340  return self.val
341 
342 class EnvError(Exception):
343  '''Class which defines errors for locals operations.'''
344  def __init__(self, value, code):
345  super(EnvError, self).__init__()
346  self.val = value
347  self.code = code
348  def __str__(self):
349  if self.code == 'undefined':
350  return 'Reference to undefined environment element: "'+self.val +'".'
351  elif self.code == 'ref2var':
352  return 'Reference to list from the middle of string.'
353  elif self.code == 'redeclaration':
354  return 'Wrong redeclaration of environment element "'+self.val+'".'
tuple c
Definition: gaudirun.py:391
def __init__(self, value, code)
Definition: Variable.py:344
def isTarget(self, variable)
Definition: Variable.py:47
def search(self, expr)
Definition: Variable.py:335
def __contains__(self, item)
Definition: Variable.py:285
def __delitem__(self, key)
Definition: Variable.py:278
def isTarget(self, variable)
Definition: Variable.py:24
def isTarget(self, variable)
Definition: Variable.py:57
def isTarget(self, variable)
Definition: Variable.py:136
def __setitem__(self, key, value)
Definition: Variable.py:272
struct GAUDI_API map
Parametrisation class for map-like implementation.
NamedRange_< CONTAINER > range(const CONTAINER &cnt, std::string name)
simple function to create the named range form arbitrary container
Definition: NamedRange.h:130
def __getitem__(self, key)
Definition: Variable.py:269
def process(self, variable, value)
Definition: Variable.py:102
def process(self, variable, value)
Definition: Variable.py:140
def search(self, expr, regExp)
Definition: Variable.py:253
def process(self, value, env)
Definition: Variable.py:176
def process(self, variable, value)
Definition: Variable.py:30
def _repl(self, value)
Definition: Variable.py:75
def __call__(self, variable, value)
Definition: Variable.py:40
def isTarget(self, variable)
Definition: Variable.py:71
def process(self, variable, value)
Definition: Variable.py:116
def process(self, variable, value)
Definition: Variable.py:127
def process(self, variable, value)
Definition: Variable.py:89