CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
comments.py
Go to the documentation of this file.
1 #!/bin/env python
2 
3 # tool to add comments to python configuration files
4 #
5 # this tool makes the following assumptions
6 # - for each file Subproject/Package/data/config.[cff,cfg,cfi]
7 # there is a file Subproject/Package/python/config_[cff,cfg,cfi].py
8 # - comments are either in the line just above a command or just behind in the same line
9 
10 
11 # should hold the comment ID
12 # which is Comment.value and Comment.type = "trailing" or "inline"
13 #
14 
15 from FWCore.ParameterSet import cfgName2py
16 
17 class Comment:
18  pass
19 
20 
21 def prepareReplaceDict(line, comment, replaceDict):
22  """take a line and a corresponding comment and prepare the replaceDict such that it can be found again in the python version """
23  allKeywords = ['module','int32','vint32','uint32', 'vuint32','double','vdouble','InputTag', 'VInputTag', 'PSet', 'VPSet', 'string', 'vstring', 'bool', 'vbool', 'path', 'sequence', 'schedule', 'endpath', 'es_source', 'es_module', 'block', 'FileInPath']
24  unnamedKeywords = ['es_source', 'es_module']
25 
26 
27  words = line.lstrip().split()
28  # at least <keyword> <label> = "
29  if len(words) > 1:
30  firstWord = words[0]
31  if firstWord in allKeywords and len(words) > 2 and words[2] == '=':
32  tokenInPython = words[1] + " = "
33  replaceDict[tokenInPython] = comment
34  elif firstWord == 'untracked' and len(words) > 3 and words[1] in allKeywords and words[3] == '=':
35  tokenInPython = words[2] + " = cms.untracked"
36  replaceDict[tokenInPython] = comment
37  elif firstWord.startswith('include'): # handling of include statements
38  pythonModule = cfgName2py.cfgName2py(line.split('"')[1])
39  pythonModule = pythonModule.replace("/",".").replace("python.","").replace(".py","")
40  tokenInPython = "from "+pythonModule
41  tokenInPython = tokenInPython.replace("/",".").replace("python.","").replace(".py","")
42  replaceDict[tokenInPython] = comment
43  # if a cfg
44  tokenInPython = "process.load(\""+pythonModule
45  replaceDict[tokenInPython] = comment
46  elif firstWord == 'source' and len(words) > 1 and words[1] == '=':
47  replaceDict['source = '] = comment
48  elif firstWord in unnamedKeywords and len(words) > 2 and words[1] == '=':
49  tokenInPython = words[2] + ' = cms.ES'
50  replaceDict[tokenInPython] = comment
51  elif firstWord == 'replace' and len(words) > 2 and words[2] == '=':
52  tokenInPython= words[1] + " = "
53  replaceDict[tokenInPython] = comment
54  elif firstWord == 'replace' and len(words) > 2 and words[2] == '=':
55  tokenInPython= words[1] + " = "
56  replaceDict[tokenInPython] = comment
57  # if it's a cfg
58  tokenInPython = 'process.'+tokenInPython
59  replaceDict[tokenInPython] = comment
60  elif firstWord == 'using' and len(words) == 2:
61  tokenInPython= words[1]
62  replaceDict[tokenInPython] = comment
63  # if it's a significant line, we're not in a comment any more
64  else:
65  replaceDict["@beginning"] +="\n"+comment.value
66 
67 
68 
69 def identifyComments(configString):
70 
71  replaceDict = {}
72 
73  replaceDict["@beginning"] = "# The following comments couldn't be translated into the new config version:\n"
74  allKeywords = ['module','int32','vint32','uint32', 'vuint32','double','vdouble','InputTag', 'VInputTag', 'PSet', 'VPSet', 'string', 'bool', 'vbool', 'path', 'sequence', 'schedule', 'endpath', 'es_source', 'es_module', 'block', 'FileInPath']
75  unnamedKeywords = ['es_source', 'es_module']
76  # the ugly parsing part
77  inComment = False # are we currently in a comment?
78  inSlashStarComment = False
79 
80  # TODO - include inline comments
81  # for now only modules work
82  for line in configString.splitlines():
83  if line.lstrip().startswith("/*"):
84  comment = Comment()
85  comment.type = "slashstar"
86  splitStarSlash = line.lstrip().lstrip("/*").split("*/")
87  comment.value = "# "+splitStarSlash[0]+"\n"
88  # has it ended yet? Might ignore legitimate commands after the end.
89  inSlashStarComment = (line.find('*/') == -1)
90  inComment = True
91  elif inSlashStarComment:
92  splitStarSlash = line.lstrip().lstrip("/*").split("*/")
93  comment.value += "# "+splitStarSlash[0]+"\n"
94  inSlashStarComment = (line.find('*/') == -1)
95  elif line.lstrip().startswith("#") or line.lstrip().startswith("//"):
96  if inComment:
97  comment.value += "#"+line.lstrip().lstrip("//").lstrip("#") + "\n"
98  else:
99  comment = Comment()
100  comment.type = "trailing"
101  comment.value = "#"+line.lstrip().lstrip("//").lstrip("#") + "\n"
102  inComment = True
103  elif inComment: # we are now in a line just below a comment
104  words = line.lstrip().split()
105  # at least <keyword> <label> = "
106  if len(words) > 1:
107  prepareReplaceDict(line,comment,replaceDict)
108  if len(words) > 0:
109  inComment = False
110  else:
111  # now to comments in the same line
112  if len(line.split("#")) > 1 or len(line.split("//")) > 1:
113  comment = Comment()
114  if len(line.split("#")) > 1:
115  comment.value = '#'+line.split("#")[1]
116  else:
117  comment.value = '#'+line.split("//")[1]
118  comment.type = "inline"
119  # prepare the replaceDict
120  prepareReplaceDict(line, comment, replaceDict)
121 
122 
123  return replaceDict
124 
125 
126 
127 
128 def modifyPythonVersion(configString, replaceDict):
129 
130  # first put all comments at the beginning of the file which could not be assigned to any other token
131  if replaceDict["@beginning"] != "# The following comments couldn't be translated into the new config version:\n":
132  configString = replaceDict["@beginning"]+"\n"+configString
133 
134  replaceDict.pop("@beginning")
135 
136  # identify the lines to replace and prepare the replacing line
137  actualReplacements = {}
138  for keyword, comment in replaceDict.iteritems():
139  for line in configString.splitlines():
140  if line.lstrip().startswith(keyword):
141  indentation = line[0:line.find(keyword)]
142  if len([1 for l in configString.splitlines() if l.lstrip().startswith(keyword)]) !=1:
143  print "WARNING. Following keyword not unique:", keyword
144  continue
145  if comment.type == "inline":
146  newLine = line + " #"+comment.value+"\n"
147  else:
148  newLine = line.replace(line,comment.value+line) # lacking the trailing whitespace support
149  newLine = newLine.replace('#', indentation+'#')
150  actualReplacements[line] = newLine
151 
152 
153  # now do the actual replacement
154  for original, new in actualReplacements.iteritems():
155  configString = configString.replace(original, new)
156 
157  return configString
158 
159 
160 def loopfile(cfgFileName):
161  cfgFile = file(cfgFileName)
162  cfgString = cfgFile.read()
163 
164  pyFileName = cfgName2py.cfgName2py(cfgFileName)
165 
166  try:
167  pyFile = file(pyFileName)
168  pyString = pyFile.read()
169  except IOError:
170  print pyFileName, "does not exist"
171  return
172  comments = identifyComments(cfgString)
173  print "Opening", pyFileName
174  newPyString = modifyPythonVersion(pyString, comments)
175  pyFile.close()
176 
177  pyOutFile = file(pyFileName,"w")
178  pyOutFile.write(newPyString)
179  print "Wrote", pyFileName
180  pyOutFile.close()
181 
182 #out = file("foo_cfi.py","w")
183 #out.write(configString)
184 #print configString
185 
186 
187 
188 #
189 import os
190 from sys import argv
191 
192 if len(argv) != 2:
193  print "Please give either a filename, or 'local'"
194 elif argv[1] == 'local':
195  for subsystem in os.listdir("."):
196  try:
197  #print subsystem
198  for package in os.listdir("./"+subsystem):
199  #print " ",subsystem+"/"+package
200  try:
201  for name in os.listdir(subsystem+"/"+package+"/data"):
202  if len(name.split("."))==2 and name.split(".")[1] in ["cfg","cfi","cff"]:
203  print subsystem+"/"+package+"/data/"+name
204  loopfile(subsystem+"/"+package+"/data/"+name)
205  except OSError:
206  pass
207  except OSError:
208  pass
209 
210 
211 else:
212  loopfile(argv[1])
213 
214 
def modifyPythonVersion
Definition: comments.py:128
def replace
Definition: linker.py:10
def cfgName2py
Definition: cfgName2py.py:4
def loopfile
Definition: comments.py:160
def prepareReplaceDict
Definition: comments.py:21
double split
Definition: MVATrainer.cc:139
def identifyComments
Definition: comments.py:69