CMS 3D CMS Logo

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