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