1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 from __future__ import with_statement
27
28 __authors__ = [ "Marie-Francoise Incardona", "Olof Svensson", "Jérôme Kieffer" ]
29 __contact__ = "svensson@esrf.fr"
30 __license__ = "LGPLv3+"
31 __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
32
33 """
34 This class handles the EDNA configuration XML/JSON files.
35 """
36
37 import os, json
38 from EDVerbose import EDVerbose
39 from EDLogging import EDLogging
40 from EDUtilsFile import EDUtilsFile
41 from EDUtilsPath import EDUtilsPath
42 from EDFactoryPluginStatic import EDFactoryPluginStatic
43 from EDDecorator import deprecated
44 from XSDataCommon import XSConfiguration, XSPluginItem, XSParamList, XSParamItem
47 """
48 convert a string to it's typed version
49 """
50 if a.lower() in ["true", "on"]:
51 return True
52 if a.lower() in ["false", "off"]:
53 return False
54 if a.lower() in ["none", "nul", "null"]:
55 return None
56 try:
57 ia = int(a)
58 except:
59 ia = None
60 try:
61 fa = float(a)
62 except:
63 fa = None
64 if ia is not None and fa is not None:
65 if ia == fa:
66 return ia
67 else:
68 return fa
69 else:
70 return str(a)
71
74 """
75 This class handles the EDNA configuration XML files. The structure of
76 the XML is described in the XSDataCommon data model.
77
78 If environment variable strings like "$XXX" or "${XXX}" is present in the
79 configuration file, the strings are replaced with the corresponding
80 environment variable content. For example, if "${CCP4} is present in the
81 XML string, the string "${CCP4}" is replaced by the environment variable $CCP4
82 content.
83 """
84
85
87 """"Set up semaphore for thread safeness and dictionary for config files"""
88 EDLogging.__init__(self)
89 self._dictConfigurationFiles = {}
90 self._dictPluginConfiguration = {}
91 if _strFileName is not None:
92 self.addConfigurationFile(_strFileName)
93
95 """Loads an XML/JSON config file into the dictionary if not already loaded"""
96 strFileName = os.path.abspath(_strFileName)
97 if not os.path.exists(strFileName):
98 self.WARNING("Trying to add configuration file but file %s doesn't exist!" % _strFileName)
99 else:
100 if strFileName in self._dictConfigurationFiles:
101 self.DEBUG("EDConfiguration.addConfigurationFile: File %s already parsed, in cache" % strFileName)
102 else:
103 self.DEBUG("EDConfiguration.addConfigurationFile: Parsing file %s" % strFileName)
104 strConfiguration = EDUtilsFile.readFileAndParseVariables(strFileName)
105 if strFileName.endswith(".xml"):
106 xsConfiguration = XSConfiguration.parseString(strConfiguration)
107 if xsConfiguration is not None :
108 dictConfig = {"__extend__":[]}
109 for other in xsConfiguration.XSImportConfiguration:
110 if other.directory not in [None, "None"]:
111 dictConfig["__extend__"].append(os.path.join(other.directory, other.name))
112 else:
113 dictConfig["__extend__"].append(other.name)
114
115 xsPluginList = xsConfiguration.getXSPluginList()
116 if xsPluginList is not None:
117 for pluginItem in xsPluginList.getXSPluginItem():
118 plugin_conf = {}
119 plugin_name = pluginItem.name
120 paramList = pluginItem.getXSParamList()
121 if paramList:
122 for paramItem in paramList.getXSParamItem():
123 plugin_conf[paramItem.name] = bestType(paramItem.value)
124 dictConfig[plugin_name] = plugin_conf
125 else:
126 dictConfig = json.loads(strConfiguration)
127
128 with self.locked():
129 self._dictConfigurationFiles[strFileName] = dictConfig
130
131 for importConfiguration in dictConfig["__extend__"]:
132 if importConfiguration.startswith(os.sep):
133 for ext in ["", ".json", ".xml" ]:
134 if os.path.isfile(importConfiguration + ext):
135 strImportPath = importConfiguration + ext
136 break
137 else:
138 for ext in ["", ".json", ".xml" ]:
139 path = os.path.join(os.path.dirname(strFileName), importConfiguration + ext)
140 if os.path.isfile(path):
141 strImportPath = path
142 break
143 self.DEBUG("Importing configuration file : %s" % strImportPath)
144 self.addConfigurationFile(strImportPath, _bReplace)
145
146
147 with self.locked():
148
149 for strPluginName in dictConfig:
150 if strPluginName == "__extend__":
151 continue
152 if strPluginName in self._dictPluginConfiguration:
153 if _bReplace:
154 self.DEBUG("EDConfiguration.addConfigurationFile: plugin configuration for %s already exists and will be replaced." % strPluginName)
155 self._dictPluginConfiguration[strPluginName] = dictConfig[strPluginName]
156 else:
157 self.DEBUG("EDConfiguration.addConfigurationFile: plugin configuration for %s already exists and will not be replaced." % strPluginName)
158 else:
159 self.DEBUG("EDConfiguration.addConfigurationFile: adding plugin configuration for %s." % strPluginName)
160 self._dictPluginConfiguration[strPluginName] = dictConfig[strPluginName]
161
162
164 """
165 This method returns the path to the Project configuration file.
166
167 @param _strPluginName: Name of the module
168 @type _strPluginName: python string
169
170 @return: The path to the project configuration file
171 @type: python string
172 """
173 strPathToProjectConfigurationFile = None
174 strCurrentDirectory = EDFactoryPluginStatic.getModuleLocation(_strPluginName)
175 if strCurrentDirectory is None:
176 self.WARNING("Cannot find path to configuration for plugin %s" % _strPluginName)
177 else:
178 with self.locked():
179 bConfFileFound = False
180 strPathToProjectConfigurationFile = None
181 strConfigurationFileBaseName = "XSConfiguration_%s" % EDUtilsPath.EDNA_SITE
182 while not bConfFileFound:
183 strPreviousDirectory = strCurrentDirectory
184 strCurrentDirectory = os.path.dirname(strCurrentDirectory)
185 if strCurrentDirectory in (EDUtilsPath.EDNA_HOME, strPreviousDirectory):
186 strPathToProjectConfigurationFile = None
187 break
188 strPathToConfigurationDirectory = os.path.abspath(os.path.join(strCurrentDirectory, "conf"))
189 for ext in [".json", ".xml"]:
190 strPathToProjectConfigurationFile = os.path.abspath(os.path.join(strPathToConfigurationDirectory, \
191 strConfigurationFileBaseName + ext))
192 self.DEBUG("Looking for configuration file for %s in %s" %
193 (_strPluginName, strPathToProjectConfigurationFile))
194 bConfFileFound = os.path.isfile(strPathToProjectConfigurationFile)
195 if bConfFileFound:
196 break
197 return strPathToProjectConfigurationFile
198
199
200
201
202
203
204 - def get(self, _strPluginName, default=None):
205 """
206 Returns the configuration for a given plugin as a dictionary.
207
208 If the plugin configuration is not in the cache the methods
209 'getPathToProjectConfigurationFile' and 'addConfigurationFile'
210 are called for attempting to load the plugin configuration
211 from a file (lazy loading).
212
213 @param _strPluginName: name of the plugin
214 @param default: optional default return value if plugin not loaded (e.g. {})
215 @return: configuration as a dict (or default value)
216 """
217 dictPluginConfiguration = default
218 if _strPluginName in self._dictPluginConfiguration:
219 dictPluginConfiguration = self._dictPluginConfiguration[_strPluginName]
220 else:
221 strPathToProjectConfigurationFile = self.getPathToProjectConfigurationFile(_strPluginName)
222 if strPathToProjectConfigurationFile is not None:
223 self.addConfigurationFile(strPathToProjectConfigurationFile, _bReplace=True)
224 if _strPluginName in self._dictPluginConfiguration:
225 dictPluginConfiguration = self._dictPluginConfiguration[_strPluginName]
226 return dictPluginConfiguration
227
229 return (key in self._dictPluginConfiguration)
230
232 """
233 edConfig["myPlugin"] -> {}
234 """
235 return self._dictPluginConfiguration.get(_strPluginName, {})
236
237 - def __setitem__(self, _strPluginName, plugin_config={}):
238 """
239 edConfig["myPlugin"]= {"timeout":5}
240
241 @param _strPluginName: name of the plugin as a string
242 @param plugin_config: configuration of a whole plugin as a dict
243 """
244 with self.locked():
245 self._dictPluginConfiguration[_strPluginName] = plugin_config
246
248 return len(self._dictPluginConfiguration)
249
251 """
252 Returns the number of plugins configured
253 """
254 return len(self._dictPluginConfiguration)
255
256
257
258
259
260
262 "Method offering compatibility with XML structure: deprecated !!!"
263 config = None
264 if _strPluginName in self._dictPluginConfiguration:
265 config = self._dictPluginConfiguration[_strPluginName]
266 else:
267 config = self.get(_strPluginName)
268 if config is not None:
269 return XSPluginItem(name=_strPluginName,
270 XSParamList=XSParamList([XSParamItem(name=i, value=str(config[i])) for i in config]))
271
272
273
275 "Compatibility with XML structure: deprecated"
276 if _xsPluginItem is not None:
277 if _xsPluginItem.name is not None:
278 strPluginName = _xsPluginItem.name
279 plugin_conf = {}
280 paramList = _xsPluginItem.getXSParamList()
281 if paramList:
282 for paramItem in paramList.getXSParamItem():
283 plugin_conf[paramItem.name] = bestType(paramItem.value)
284 if strPluginName in self._dictPluginConfiguration.keys():
285 self.DEBUG("Replacing configuration for plugin %s" % strPluginName)
286 else:
287 self.DEBUG("Setting configuration for plugin %s" % strPluginName)
288 with self.locked():
289 self._dictPluginConfiguration[strPluginName] = plugin_conf
290
291
293 "Get the configuration for one plugin and one config parameter, as a string"
294 config = None
295 if _strPluginName in self._dictPluginConfiguration:
296 config = self._dictPluginConfiguration[_strPluginName]
297 else:
298 config = self.get(_strPluginName)
299 if (config is not None) and (_strConfigurationName in config):
300 return str(config[_strConfigurationName])
301
302
303
304
305 @staticmethod
307 """
308 Returns the corresponding 'paramItem' for a given plugin name
309 -> Deprecated
310 """
311 xsParamList = _xsPluginItem.getXSParamList()
312 xsParamItemReturn = None
313
314 if (xsParamList != None):
315 xsParamItems = xsParamList.getXSParamItem()
316 for xsParamItem in xsParamItems:
317 if (xsParamItem.getName() == _pyStrParamName):
318 xsParamItemReturn = xsParamItem
319 break
320 return xsParamItemReturn
321
322
323 @classmethod
325 """
326 Returns the parameter value in a string format
327 -> Deprecated
328 """
329 strParamValue = None
330 xsParamItem = cls.getParamItem(_xsPluginItem, _pyStrParamName)
331 if xsParamItem is not None:
332 strParamValue = xsParamItem.getValue()
333 return strParamValue
334
335
336
337 @classmethod
339 """
340 Returns the parameter value in a integer format
341 -> Deprecated
342 """
343 strParamValue = cls.getStringParamValue(_xsPluginItem, _pyStrParamName)
344 try:
345 return int(strParamValue)
346 except TypeError:
347 return
348 except ValueError:
349 EDVerbose.ERROR("invalid literal for int(), got %s" % strParamValue)
350