CMS 3D CMS Logo

betterConfigParser.py
Go to the documentation of this file.
1 import ConfigParser
2 import os
3 import re
4 import copy
5 import collections
6 from TkAlExceptions import AllInOneError
7 
8 
9 class AdaptedDict(collections.OrderedDict):
10  """
11  Dictionary which handles updates of values for already existing keys
12  in a modified way.
13  adapteddict[key] returns a list of all values associated with key
14  This dictionary is used in the class `BetterConfigParser` instead of the
15  default `dict_type` of the `ConfigParser` class.
16  """
17 
18  def __init__(self, *args, **kwargs):
19  self.validationslist = []
20  collections.OrderedDict.__init__(self, *args, **kwargs)
21 
22  def __setitem__(self, key, value, dict_setitem=collections.OrderedDict.__setitem__):
23  """
24  od.__setitem__(i, y) <==> od[i]=y
25  Updating an existing key appends the new value to the old value
26  instead of replacing it.
27 
28  Arguments:
29  - `key`: key part of the key-value pair
30  - `value`: value part of the key-value pair
31  - `dict_item`: method which is used for finally setting the item
32  """
33 
34  if key != "__name__" and "__name__" in self and self["__name__"]=="validation":
35  if isinstance(value, (str, unicode)):
36  for index, item in enumerate(self.validationslist[:]):
37  if item == (key, value.split("\n")):
38  self.validationslist[index] = (key, value)
39  return
40  self.validationslist.append((key, value))
41  else:
42  dict_setitem(self, key, value)
43 
44  def __getitem__(self, key):
45  if key != "__name__" and "__name__" in self and self["__name__"]=="validation":
46  return [validation[1] for validation in self.validationslist if validation[0] == key]
47  else:
48  return collections.OrderedDict.__getitem__(self, key)
49 
50  def items(self):
51  if "__name__" in self and self["__name__"]=="validation":
52  return self.validationslist
53  else:
54  return collections.OrderedDict.items(self)
55 
56 class BetterConfigParser(ConfigParser.ConfigParser):
57  def __init__(self):
58  ConfigParser.ConfigParser.__init__(self,dict_type=AdaptedDict)
60 
61  def optionxform(self, optionstr):
62  return optionstr
63 
64  def exists( self, section, option):
65  try:
66  items = self.items(section)
67  except ConfigParser.NoSectionError:
68  return False
69  for item in items:
70  if item[0] == option:
71  return True
72  return False
73 
74  def __updateDict( self, dictionary, section ):
75  result = dictionary
76  try:
77  for option in self.options( section ):
78  result[option] = self.get( section, option )
79  if "local"+section.title() in self.sections():
80  for option in self.options( "local"+section.title() ):
81  result[option] = self.get( "local"+section.title(),
82  option )
83  except ConfigParser.NoSectionError as section:
84  msg = ("%s in configuration files. This section is mandatory."
85  %(str(section).replace(":", "", 1)))
86  raise AllInOneError(msg)
87  return result
88 
89  def getResultingSection( self, section, defaultDict = {}, demandPars = [] ):
90  result = copy.deepcopy(defaultDict)
91  for option in demandPars:
92  try:
93  result[option] = self.get( section, option )
94  except ConfigParser.NoOptionError as globalSectionError:
95  globalSection = str( globalSectionError ).split( "'" )[-2]
96  splittedSectionName = section.split( ":" )
97  if len( splittedSectionName ) > 1:
98  localSection = ("local"+section.split( ":" )[0].title()+":"
99  +section.split(":")[1])
100  else:
101  localSection = ("local"+section.split( ":" )[0].title())
102  if self.has_section( localSection ):
103  try:
104  result[option] = self.get( localSection, option )
105  except ConfigParser.NoOptionError as option:
106  msg = ("%s. This option is mandatory."
107  %(str(option).replace(":", "", 1).replace(
108  "section",
109  "section '"+globalSection+"' or", 1)))
110  raise AllInOneError(msg)
111  else:
112  msg = ("%s. This option is mandatory."
113  %(str(globalSectionError).replace(":", "", 1)))
114  raise AllInOneError(msg)
115  try:
116  result = self.__updateDict( result, section )
117  except AllInOneError: #section doesn't exist
118  if demandPars: #then there's at least one mandatory parameter, which means the section needs to be there
119  raise #otherwise all the parameters are optional, so it's ok
120  return result
121 
122  def getAlignments( self ):
123  alignments = []
124  for section in self.sections():
125  if "alignment:" in section:
126  alignments.append( Alignment( section.split( "alignment:" )[1],
127  self ) )
128  names_after_cleaning = [alignment.name for alignment in alignments]
129  duplicates = [name
130  for name, count
131  in collections.Counter(names_after_cleaning).items()
132  if count > 1]
133  if len(duplicates) > 0:
134  msg = "Duplicate alignment names after removing invalid characters: "
135  msg += ", ".join(duplicates) +"\n"
136  msg += "Please rename the alignments to avoid name clashes."
137  raise AllInOneError(msg)
138  return alignments
139 
140  def getCompares( self ):
141  compares = {}
142  for section in self.sections():
143  if "compare:" in section:
144  self.checkInput(section,
145  knownSimpleOptions = ["levels", "dbOutput","moduleList","modulesToPlot","useDefaultRange","plotOnlyGlobal","plotPng","makeProfilePlots",
146  "dx_min","dx_max","dy_min","dy_max","dz_min","dz_max","dr_min","dr_max","rdphi_min","rdphi_max",
147  "dalpha_min","dalpha_max","dbeta_min","dbeta_max","dgamma_min","dgamma_max",
148  "jobmode", "3DSubdetector1", "3Dubdetector2", "3DTranslationalScaleFactor", "jobid"])
149  levels = self.get( section, "levels" )
150  dbOutput = self.get( section, "dbOutput" )
151  compares[section.split(":")[1]] = ( levels, dbOutput )
152  return compares
153 
154  def getGeneral( self ):
155  defaults = {
156  "jobmode":"interactive",
157  "datadir":os.getcwd(),
158  "logdir":os.getcwd(),
159  "eosdir": "",
160  }
161  self.checkInput("general", knownSimpleOptions = defaults.keys())
162  general = self.getResultingSection( "general", defaultDict = defaults )
163  internal_section = "internals"
164  if not self.has_section(internal_section):
165  self.add_section(internal_section)
166  if not self.has_option(internal_section, "workdir"):
167  self.set(internal_section, "workdir", "/tmp/$USER")
168  if not self.has_option(internal_section, "scriptsdir"):
169  self.set(internal_section, "scriptsdir", None)
170  #replaceByMap will fail if this is not replaced (which it is in validateAlignments.py)
171 
172  general["workdir"] = self.get(internal_section, "workdir")
173  general["scriptsdir"] = self.get(internal_section, "scriptsdir")
174  for folder in "workdir", "datadir", "logdir", "eosdir":
175  general[folder] = os.path.expandvars(general[folder])
176 
177  return general
178 
179  def checkInput(self, section, knownSimpleOptions=[], knownKeywords=[],
180  ignoreOptions=[]):
181  """
182  Method which checks, if the given options in `section` are in the
183  list of `knownSimpleOptions` or match an item of `knownKeywords`.
184  This is basically a check for typos and wrong parameters.
185 
186  Arguments:
187  - `section`: Section of a configuration file
188  - `knownSimpleOptions`: List of allowed simple options in `section`.
189  - `knownKeywords`: List of allowed keywords in `section`.
190  """
191 
192  try:
193  for option in self.options( section ):
194  if option in knownSimpleOptions:
195  continue
196  elif option.split()[0] in knownKeywords:
197  continue
198  elif option in ignoreOptions:
199  print ("Ignoring option '%s' in section '[%s]'."
200  %(option, section))
201  else:
202  msg = ("Invalid or unknown parameter '%s' in section '%s'!"
203  %(option, section))
204  raise AllInOneError(msg)
205  except ConfigParser.NoSectionError:
206  pass
207 
208  def set(self, section, option, value=None):
209  try:
210  ConfigParser.ConfigParser.set(self, section, option, value)
211  except ConfigParser.NoSectionError:
212  self.add_section(section)
213  ConfigParser.ConfigParser.set(self, section, option, value)
214 
215  def items(self, section, raw=False, vars=None):
216  if section == "validation":
217  if raw or vars:
218  raise NotImplementedError("'raw' and 'vars' do not work for betterConfigParser.items()!")
219  items = self._sections["validation"].items()
220  return items
221  else:
222  return ConfigParser.ConfigParser.items(self, section, raw, vars)
223 
224  def write(self, fp):
225  """Write an .ini-format representation of the configuration state."""
226  for section in self._sections:
227  fp.write("[%s]\n" % section)
228  for (key, value) in self._sections[section].items():
229  if key == "__name__" or not isinstance(value, (str, unicode)):
230  continue
231  if value is not None:
232  key = " = ".join((key, str(value).replace('\n', '\n\t')))
233  fp.write("%s\n" % (key))
234  fp.write("\n")
235 
236 
237  #Preexisting validations in the validation section have syntax:
238  # preexistingoffline myoffline
239  #with no = or :. This regex takes care of that.
240  OPTCRE_VALIDATION = re.compile(
241  r'(?P<option>'
242  r'(?P<preexisting>preexisting)?'
243  r'[^:=\s][^:=]*)' # very permissive!
244  r'\s*(?(preexisting)|' # IF preexisting does not exist:
245  r'(?P<vi>[:=])\s*' # any number of space/tab,
246  # followed by separator
247  # (either : or =), followed
248  # by any # space/tab
249  r'(?P<value>.*))$' # everything up to eol
250  )
def getResultingSection(self, section, defaultDict={}, demandPars=[])
def replace(string, replacements)
def __updateDict(self, dictionary, section)
def checkInput(self, section, knownSimpleOptions=[], knownKeywords=[], ignoreOptions=[])
def __init__(self, args, kwargs)
def items(self, section, raw=False, vars=None)
def __setitem__(self, key, value, dict_setitem=collections.OrderedDict.__setitem__)
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def set(self, section, option, value=None)
double split
Definition: MVATrainer.cc:139