CMS 3D CMS Logo

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