00001 '''
00002 Created on Jun 27, 2011
00003
00004 @author: mplajner
00005 '''
00006 import re
00007 import os
00008 import platform
00009
00010 class List():
00011 '''
00012 Class for manipulating with environment lists.
00013
00014 It holds its name and values represented by a list.
00015 Some operations are done with separator, which is usually colon. For windows use semicolon.
00016 '''
00017
00018 def __init__(self, name, local=False, report=None):
00019 self.report = report
00020 self.varName = name
00021 self.local = local
00022 self.val = []
00023
00024 def name(self):
00025 '''Returns the name of the List.'''
00026 return self.varName
00027
00028
00029 def set(self, value, separator = ':', environment={}, resolve=True):
00030 '''Sets the value of the List. Any previous value is overwritten.'''
00031 if resolve:
00032 value = self.resolveReferences(value, environment, separator)
00033 else:
00034 value = value.split(separator)
00035 self.val = filter(None, value)
00036
00037 def unset(self, value, separator = ':', environment={}):
00038 '''Sets the value of the List to empty. Any previous value is overwritten.'''
00039 self.val = ''
00040
00041
00042 def value(self, asString = False, separator = ':'):
00043 '''Returns values of the List. Either as a list or string with desired separator.'''
00044 if asString:
00045 stri = self._concatenate(separator)
00046 return stri.replace(']', ':')
00047 else:
00048 lis = self.val[:]
00049 if platform.system() != 'Linux':
00050 for item in lis:
00051 item.replace(']',':')
00052 return lis
00053
00054
00055 def remove_regexp(self,value,separator = ':'):
00056 self.remove(value, separator, True)
00057
00058 def remove(self, value, separator = ':', regexp=False):
00059 '''Removes value(s) from List. If value is not found, removal is canceled.'''
00060 if regexp:
00061 value = self.search(value, True)
00062
00063 elif isinstance(value,str):
00064 value = value.split(separator)
00065
00066 for i in range(len(value)):
00067 val = value[i]
00068 if val not in value:
00069 self.report.addWarn('Value "'+val+'" not found in List: "'+self.varName+'". Removal canceled.')
00070 while val in self.val:
00071 self.val.remove(val)
00072
00073
00074 def append(self, value, separator = ':', environment={}, warningOn=True):
00075 '''Adds value(s) at the end of the list.'''
00076
00077 value = self.resolveReferences(value, environment, separator)
00078
00079 if type(value) is str:
00080 value = value.split(separator)
00081
00082 if warningOn:
00083 notPresent = lambda v: v not in self.val
00084 else:
00085 def notPresent(v):
00086 '''helper function to report duplicated entries'''
00087 if v not in self.val:
00088 return True
00089 else:
00090 self.report.addWarn('Var: "'+self.varName+'" value: "' + v + '". Addition canceled because of duplicate entry.')
00091 return False
00092
00093 self.val += filter(notPresent, value)
00094
00095 def prepend(self, value, separator = ':', environment={}):
00096 '''Adds value(s) at the beginning of the list.'''
00097 '''resolve references and duplications'''
00098 value = self.resolveReferences(value, environment, separator)
00099
00100 if type(value) is str:
00101 value = value.split(separator)
00102
00103 new_value = []
00104 for v in value + self.val:
00105 if v not in new_value:
00106 new_value.append(v)
00107 else:
00108 self.report.addWarn('Var: "' + self.varName + '" value: "' + v + '". Addition canceled because of duplicate entry.')
00109 self.val = new_value
00110
00111 def search(self, expr, regExp):
00112 '''Searches in List`s values for a match
00113
00114 Use string value or set regExp to True.
00115 In the first case search is done only for an exact match for one of List`s value ('^' and '$' added).
00116 '''
00117 if not regExp:
00118 expr = '^' + expr + '$'
00119 v = re.compile(expr)
00120 res = []
00121 for val in self.val:
00122 if v.search(val):
00123 res.append(val)
00124
00125 return res
00126
00127
00128 def repl(self, s, d):
00129 v = re.compile(r"\$([A-Za-z_][A-Za-z0-9_]*)|\$\(([A-Za-z_][A-Za-z0-9_]*)\)|\$\{([A-Za-z_][A-Za-z0-9_]*)\}")
00130 m = v.search(s)
00131 if m:
00132 s = s[:m.start()] + str(d[filter(None,m.groups())[0]]) + s[m.end():]
00133 return self.repl(s,d)
00134 else:
00135 return s
00136
00137
00138 def resolveReferences(self, value, environment, separator = ':'):
00139 '''Resolves references to Lists'''
00140 if isinstance(value, list):
00141 str = ''
00142 for val in value:
00143 str = val + '' + separator
00144 value = str[:len(str)-1]
00145
00146 value = self.repl(value, environment)
00147 value = value.split(separator)
00148
00149 value = self._remDuplicates(value)
00150 value = self._changeSlashes(value)
00151 return value
00152
00153
00154 def _changeSlashes(self, value):
00155 '''Changes slashes depending on operating system.'''
00156 i = 0
00157 while i < len(value):
00158 if len(value[i]) == 0:
00159 del value[i]
00160 continue
00161 if value[i][0] == '[':
00162 if platform.system() != 'Linux':
00163 value[i] = value[i][1:]
00164 else:
00165 value[i] = value[i][3:]
00166 value[i] = os.path.normpath(value[i])
00167 i+=1
00168 return value
00169
00170
00171 def _concatenate(self, separator):
00172 '''Returns a List string with separator "separator" from the values list'''
00173
00174 stri = ""
00175 for it in self.val:
00176 stri += it + separator
00177 stri = stri[0:len(stri)-1]
00178 return stri
00179
00180
00181 def _remDuplicates(self, seq, idfun=None):
00182 '''removes duplicated values from list'''
00183 if idfun is None:
00184 def idfun(x): return x
00185 seen = {}
00186 result = []
00187 for item in seq:
00188 marker = idfun(item)
00189
00190 if marker in seen:
00191 self.report.addWarn('Var: "'+self.varName+'" value: "' + marker + '". Addition canceled because of duplicate entry.')
00192 continue
00193 seen[marker] = 1
00194 result.append(item)
00195 return result
00196
00197
00198
00199 def __getitem__(self, key):
00200 return self.val[key]
00201
00202 def __setitem__(self, key, value):
00203 if value in self.val:
00204 self.report.addWarn('Var: "' + self.varName + '" value: "' + value + '". Addition canceled because of duplicate entry.')
00205 else:
00206 self.val.insert(key, value)
00207
00208 def __delitem__(self, key):
00209 self.removeVal(self.val[key])
00210
00211 def __iter__(self):
00212 for i in self.val:
00213 yield i
00214
00215 def __contains__(self, item):
00216 return item in self.val
00217
00218 def __len__(self):
00219 return len(self.val)
00220
00221 def __str__(self):
00222 return self._concatenate(':')
00223
00224
00225 class Scalar():
00226 '''Class for manipulating with environment scalars.'''
00227
00228 def __init__(self, name, local=False, report = None):
00229 self.report = report
00230 self.name = name
00231 self.val = ''
00232
00233 self.local = local
00234
00235 def name(self):
00236 '''Returns the name of the scalar.'''
00237 return self.name
00238
00239 def set(self, value, separator = ':', environment={}, resolve = True):
00240 '''Sets the value of the scalar. Any previous value is overwritten.'''
00241 if resolve:
00242 value = self.resolveReferences(value, environment)
00243 self.val = value
00244 self._changeSlashes()
00245 if self.val == '.':
00246 self.val = ""
00247
00248
00249 def value(self, asString = False, separator = ':'):
00250 '''Returns values of the scalar.'''
00251 return self.val
00252
00253 def remove_regexp(self,value,separator = ':'):
00254 self.remove(value, separator, True)
00255
00256 def remove(self, value, separator = ':', regexp=True):
00257 '''Removes value(s) from the scalar. If value is not found, removal is canceled.'''
00258 value = self.search(value)
00259 for val in value:
00260 self.val = self.val.replace(val,'')
00261
00262 def append(self,value, separator = ':', environment={}, warningOn=True):
00263 '''Adds value(s) at the end of the scalar.'''
00264 value = self.resolveReferences(value, environment)
00265 self.val = self.val + value
00266 self._changeSlashes()
00267
00268
00269 def prepend(self,value,action='cancel', separator = ':', environment={}):
00270 '''Adds value(s) at the beginning of the scalar.'''
00271 value = self.resolveReferences(value, environment)
00272 self.val = value + self.val
00273 self._changeSlashes()
00274
00275
00276 def repl(self, s, d):
00277 v = re.compile(r"\$([A-Za-z_][A-Za-z0-9_]*)|\$\(([A-Za-z_][A-Za-z0-9_]*)\)|\$\{([A-Za-z_][A-Za-z0-9_]*)\}")
00278 m = v.search(s)
00279 if m:
00280 s = s[:m.start()] + str(d[filter(None,m.groups())[0]]) + s[m.end():]
00281 return self.repl(s,d)
00282 else:
00283 return s
00284
00285
00286 def resolveReferences(self, value, environment):
00287 '''Resolve references inside the scalar.'''
00288
00289 value = self.repl(value, environment)
00290 return value
00291
00292 def search(self, expr):
00293 '''Searches in scalar`s values for a match'''
00294 return re.findall(expr,self.val)
00295
00296
00297 def _changeSlashes(self):
00298 '''Changes slashes depending on operating system.'''
00299 if self.val == '[':
00300 if platform.system() != 'Linux':
00301 self.val = self.val[1:]
00302 else:
00303 self.val = self.val[3:]
00304 self.val = os.path.normpath(self.val)
00305
00306
00307 def __str__(self):
00308 return self.val
00309
00310 class EnvironmentError(Exception):
00311 '''Class which defines errors for locals operations.'''
00312 def __init__(self, value, code):
00313 self.val = value
00314 self.code = code
00315 def __str__(self):
00316 if self.code == 'undefined':
00317 return 'Reference to undefined environment element: "'+self.val +'".'
00318 elif self.code == 'ref2var':
00319 return 'Reference to list from the middle of string.'
00320 elif self.code == 'redeclaration':
00321 return 'Wrong redeclaration of environment element "'+self.val+'".'