1 """GNUmed: Mid-level configuration editor object.
2
3 Theory of operation:
4
5 ConfigSourceDB/File holds config data (read from backend or file) and related
6 config definitions. Definitions are retrieved automatically from a given config
7 definition file (if available). See _defaultDefSourceTable below for standard file
8 names.
9
10 First get a list of available config parameters through getAllParamNames (returns
11 names + metadata), get the values using GetConfigData, change, check for validity
12 using isValid (if definition data and parameter definition is available) and
13 set data using SetConfigData.
14 License: GNU Public License
15 """
16
17
18 __version__ = "$Revision: 1.10 $"
19 __author__ = "H.Berger,K.Hilbert"
20
21 import sys, os, string, types, pickle
22
23 from Gnumed.pycommon import gmCfg, gmPG2
24
25 _log = gmLog.gmDefLog
26 if __name__ == '__main__':
27 _log.SetAllLogLevels(gmLog.lData)
28 _ = lambda x:x
29
30 _log.Log(gmLog.lData, __version__)
31 _cfg = gmCfg.gmDefCfgFile
32 _defaultDefSourceTable = {
33 'DB:CURRENT_USER_CURRENT_WORKPLACE': 'config-definitions/DBDefault.definitions',
34 'DB:CURRENT_USER_DEFAULT_WORKPLACE' : 'config-definitions/DBDefault.definitions',
35 'DB:DEFAULT_USER_CURRENT_WORKPLACE' : 'config-definitions/DBDefault.definitions',
36 'DB:DEFAULT_USER_DEFAULT_WORKPLACE' : 'config-definitions/DBDefault.definitions',
37 'gnumed.conf': 'config-definitions/gnumed.conf.definitions'
38 }
39
40
42 """Base class for interface to access config data and definitions on a single
43 configuration source (config file, user/workplace specific backend data
44 collection.
45 The source name will be used to retrieve the config definitions from
46 a config definition source (file, DB) automatically.
47 """
48
49 _DefinitionSourceTable = None
50
51 - def __init__(self,aSourceType=None,aSourceName=None,aDataSource=None):
65
66
67
70
71
73 """ get type of parameter value """
74
75
76
77 definitionType = None
78
79 if not self.mDefinitionSource is None:
80 definitionName = self.mDataSource.getRawName(aParam)
81 definitionType = self.mDefinitionSource.getParamType(definitionName)
82
83 if not definitionType is None:
84 mType = definitionType
85 else:
86 mType = self.mDataSource.getParamType(aParam)
87
88 return mType
89
90
91 - def castType(self, aParam = None, aValue=None):
92 """ cast type of entered parameter value to the previously existing type."""
93
94 castType = self.getParamType(aParam)
95 if castType == 'str_array':
96 castedVal = string.split(aValue,'\n')
97 if not type(castedVal) is types.ListType:
98 castedVal = [str(castedVal)]
99 elif castType == 'numeric':
100 if not type(eval(aValue)) in (types.IntType, types.FloatType, types.LongType):
101 castedVal = None
102 else:
103 castedVal = eval(aValue)
104 elif castType == 'string':
105 castedVal = str(aValue)
106
107 return castedVal
108
109
125
126
127
128
130 """
131 Get all parameter names from backend or a file.
132 Returns dict of names + metadata.
133 format:
134 dict {'name1': [namepart_2,namepart_1,owner,type,description],
135 'name2': [option,group,owner,type,description],...}
136 usually the full name is a composition of namepart_1 +_2,
137 but don't rely on the order - it depends on whether you get
138 data from DB or file. type is the type as found in the data
139 (one of 'string', 'string_arr' or 'numeric'). description is the
140 description supplied with the data, not the one given in the
141 parameter definition file ! Use getDescription() to get the right
142 one.
143 """
144 if not self.mDataSource is None:
145 return self.mDataSource.getAllNames()
146
148 """
149 Set config data for a aParam to aValue.
150 """
151 return self.mDataSource.SetConfigData(aParam,aValue)
152
154 """
155 Get config data for a aParam.
156 """
157 return self.mDataSource.GetConfigData(aParam)
158
159
161 """
162 Adds config new config parameter.
163 """
164 return self.mDataSource.AddConfigParam(aParam,aType,aValue,aDescription)
165
167 """Get config data for a aParam."""
168 return self.mDataSource.getRawName(aParam)
169
171 """ return true if config definition object is available"""
172 return ( not self.mDefinitionSource is None)
173
174
176 """
177 Returns true if config definition is available for this
178 parameter.
179 """
180 return self.mDefinitionSource.hasParameter(aParam)
181
182
184 """
185 Returns true if aValue matches config definition for this
186 parameter.
187 """
188 return self.mDefinitionSource.isValid(aParam,aValue)
189
190
191
193 """Interface to access config data and definitions in a single
194 configuration user/workplace specific backend data collection.
195 """
196 - def __init__(self, aSourceName=None,aUser = None, aWorkplace = 'xxxDEFAULTxxx'):
197 try:
198 mConfigDataSource = ConfigDataDB(aUser,aWorkplace)
199 except:
200 mConfigDataSource = None
201
202 ConfigSource.__init__(self,"DB",aSourceName,mConfigDataSource)
203
204
205
207 """
208 Interface to access config data and definitions in a config file.
209 """
210 - def __init__(self, aSourceName=None,aFileName=None):
211 try:
212 mConfigDataSource = ConfigDataFile(aFileName)
213 except:
214 mConfigDataSource = None
215
216 ConfigSource.__init__(self,"FILE",aSourceName,mConfigDataSource)
217
218
220 if not self.mDataSource is None:
221 return self.mDataSource.GetFullPath()
222
223
225 """Describes a gnumed configuration parameter.
226 """
227 - def __init__(self,aParamName = None,aParamType = None,aValidValsList = None,aParamDescription = None):
228 self.mName = aParamName
229 self.mType = aParamType
230 self.mDescription = aParamDescription
231
232
233
234
235
236
237
238 self.mValidVals = aValidValsList
239
240
242 if self.mType == "string":
243 return self.__isString(aValue)
244 elif self.mType == "str_array":
245 return self.__isStringArray(aValue)
246 elif self.mType == "numeric":
247 return self.__isNumeric(aValue)
248 else:
249 _log.Log (gmLog.lPanic, "isValid %s - %s %s" % (self.mName, self.mType, aValue))
250 return 0
251
252
254 if type(aValue) == types.StringType or type (s) == types.UnicodeType:
255 if self.mValidVals is None:
256 return 1
257 elif str(aValue) in (self.mValidVals):
258 return 1
259 return 0
260
261
263
264 if type(aValue) == types.ListType:
265 for s in (aValue):
266 if not (type(s) == types.StringType or type (s) == types.UnicodeType):
267 return 0
268 return 1
269 return 0
270
271
273 if type(aValue) in (types.IntType, types.FloatType, types.LongType):
274 if self.mValidVals is None:
275 return 1
276 elif str(aValue) in (self.mValidVals):
277 return 1
278 return 0
279
280
281
282
283
285 """ holds config definitions read from a file/DB.
286 this will contain:
287 a) config parameter names
288 b) config parameter description (optional)
289 c) config parameter type
290 d) config parameter valid values (if type is select_from_list)
291 e) config information version (must match the version used in ConfigData)
292 """
293
294 - def __init__(self, aDefinitionSource=None):
295
296
297 self.__mParameterDefinitions = {}
298 self.__mVersion = None
299
300 if aDefinitionSource is None:
301 _log.Log(gmLog.lWarn, "No configuration definition source specified")
302
303
304
305 raise TypeError, "No configuration definition source specified !"
306 else:
307 self.__mDefinitionSource = aDefinitionSource
308 if not self.__getDefinitions():
309 raise IOError, "cannot load definitions"
310
311
313 return self.__mParameterDefinitions.has_key(aParameterName)
314
315
316 - def isValid(self,aParameterName=None,aValue=None):
317 if self.hasParameter(aParameterName):
318 return self.__mParameterDefinitions[aParameterName].isValid(aValue)
319 else:
320 return 0
321
322
324 if self.hasParameter(aParameterName):
325 return self.__mParameterDefinitions[aParameterName].mType
326
327
329 if self.hasParameter(aParameterName):
330 return self.__mParameterDefinitions[aParameterName].mDescription
331
332
334 """get config definitions"""
335
336
337 try:
338 cfgDefSource = gmCfg.cCfgFile(aFile = self.__mDefinitionSource, \
339 flags=gmCfg.cfg_SEARCH_STD_DIRS | gmCfg.cfg_IGNORE_CMD_LINE)
340
341 except:
342 exc = sys.exc_info()
343 _log.LogException("Unhandled exception while opening config file [%s]" % self.__mDefinitionSource, exc,verbose=0)
344 return None
345
346 cfgData = cfgDefSource.getCfg()
347 groups = cfgDefSource.getGroups()
348
349 if not '_config_version_' in (groups):
350 _log.Log(gmLog.lWarn, "No configuration definition version defined.")
351 _log.Log(gmLog.lWarn, "Matching definitions to config data is unsafe.")
352 _log.Log(gmLog.lWarn, "Config data will be read-only by default.")
353 self.mVersion = None
354 else:
355 version = cfgDefSource.get('_config_version_', "version")
356
357 self.__mVersion = version
358 _log.Log(gmLog.lInfo, "Found config parameter definition version %s in %s" % (version,self.__mDefinitionSource))
359
360
361
362
363 for paramName in groups:
364
365 if paramName == '_config_version_':
366 continue
367
368 paramType = cfgDefSource.get(paramName, "type")
369 if paramType is None:
370 continue
371
372
373
374 paramDescription = cfgDefSource.get(paramName, "description")
375 if paramDescription is None:
376 continue
377
378 validValuesRaw = None
379
380 if "validvalue" in (cfgDefSource.getOptions(paramName)):
381 validValuesRaw = cfgDefSource.get(paramName, "validvalues")
382
383 validVals = None
384 if not validValuesRaw is None:
385 if type(validValuesRaw) == types.ListType:
386 validVals = validValuesRaw
387
388
389 self.__mParameterDefinitions
390 self.__mParameterDefinitions[paramName] = ParameterDefinition(paramName,paramType,validVals,paramDescription)
391 return 1
392
393
394
395
396
397
399 """
400 Base class. Derived classes hold config data for a particular
401 backend user/workplace combination, config file etc.
402 this will contain:
403 a) config parameter names
404 b) config parameter values
405 c) config information version (must match the version used in ConfigDefinition)
406 """
407
409 self.type = aType
410 self.mConfigData = {}
411
412
415
418
421
424
427
428
430 """
431 Returns the parameter type as found in the data source.
432 """
433 try:
434 return self.mConfigData[aParameterName][3]
435 except KeyError:
436
437
438 return None
439
440
442 """
443 Returns the parameter type as found in the data source.
444 """
445 try:
446 return self.mConfigData[aParameterName][4]
447 except KeyError:
448 return None
449
450
451
453 """
454 Class that holds config data for a particular user/workplace pair
455 """
456
457
458
459 _dbcfg = None
460
461 - def __init__(self, aUser = None, aWorkplace = 'xxxDEFAULTxxx'):
471
473 """
474 Gets Config Data for a particular parameter.
475 Returns parameter value.
476 """
477 try:
478
479 name=self.mConfigData[aParameterName][0]
480 cookie = self.mConfigData[aParameterName][1]
481
482
483 result = ConfigDataDB._dbcfg.get2 (
484 workplace=self.mWorkplace,
485
486 cookie = cookie,
487 option = name,
488 bias = 'user'
489 )
490 except:
491 _log.Log(gmLog.lErr, "Cannot get parameter value for [%s]" % aParameterName )
492 return None
493 return result
494
495
497 """
498 Sets Config Data for a particular parameter.
499 """
500 try:
501 name=self.mConfigData[aParameterName][0]
502 cookie = self.mConfigData[aParameterName][1]
503 result=ConfigDataDB._dbcfg.set (
504 workplace = self.mWorkplace,
505
506 cookie = cookie,
507 option = name,
508 value = aValue,
509 )
510 except:
511 _log.Log(gmLog.lErr, "Cannot set parameter value for [%s]" % aParameterName )
512 return None
513 return 1
514
515
516
517 - def AddConfigParam(self, aParameterName, aType = None ,aValue=None,aDescription = None):
518 """
519 Adds a new config parameter.
520 Note: You will have to re-read the cache (call GetAllNames())
521 in order to change this parameter afterwards.
522 """
523
524 if self.mConfigData.has_key(aParameterName):
525 return None
526
527
528
529
530 pNameParts = string.split(aParameterName,".")
531
532 if pNameParts[-1][0] == '_':
533 cookie = pNameParts[-1][1:]
534 option = string.join(pNameParts[:-1],".")
535 else:
536 cookie = None
537 option = aParameterName
538
539
540 if option is None:
541 return None
542
543 try:
544 result=ConfigDataDB._dbcfg.set (
545 workplace = self.mWorkplace,
546
547 cookie = cookie,
548 option = option,
549 value = aValue,
550 )
551 except:
552 _log.Log(gmLog.lErr, "Cannot set parameter value for [%s]" % aParameterName )
553 return None
554
555
556
557
558 return 1
559
561 """
562 fetch names and parameter data from backend. Returns list of
563 parameter names where cookie and real name are concatenated.
564 Refreshes the parameter cache, too.
565 """
566 result=ConfigDataDB._dbcfg.getAllParams(self.mUser,self.mWorkplace)
567 if not result:
568 return None
569 else:
570
571
572
573
574
575
576
577 mParamNames = []
578
579 for param in result:
580 name = param[0]
581 cookie = param[1]
582 if cookie == 'xxxDEFAULTxxx':
583 cookie_part = ""
584 else:
585 cookie_part = "._%s" % cookie
586
587 newName = name + cookie_part
588
589 self.mConfigData[newName]=param
590
591 mParamNames.append(newName)
592
593
594
595 return mParamNames
596
597
599 """
600 Returns the parameter name without possible cookie part(s).
601 Needed to indentify matching config definition entry.
602 """
603 try:
604 return self.mConfigData[aParameterName][0]
605 except KeyError:
606 return None
607
608
610 """
611 Class that holds config data for a particular config file
612 """
614 """ Init config file """
615 ConfigData.__init__(self,"FILE")
616
617 self.filename = aFilename
618 self.__cfgfile = None
619 self.fullPath = None
620
621
622 try:
623 self.__cfgfile = gmCfg.cCfgFile(aFile = self.filename)
624
625
626
627
628 self.fullPath = self.__cfgfile.cfgName
629
630 except:
631 _log.LogException("Can't open config file !", sys.exc_info(), verbose=0)
632 raise ConstructorError, "ConfigDataFile: couldn't open config file"
633
634
636 """ returns the absolute path to the config file in use"""
637 return self.fullPath
638
639
641 """
642 Gets Config Data for a particular parameter.
643 Returns parameter value.
644 """
645 name=self.mConfigData[aParameterName][0]
646 group = self.mConfigData[aParameterName][1]
647 try:
648 result=self.__cfgfile.get(group,name)
649 except:
650 _log.Log(gmLog.lErr, "Cannot get parameter value for [%s]" % aParameterName )
651 return None
652 return result
653
654
656 """
657 Sets Config Data for a particular parameter.
658 """
659 option = self.mConfigData[aParameterName][0]
660 group = self.mConfigData[aParameterName][1]
661 try:
662 result=self.__cfgfile.set(aGroup = group,
663 anOption = option,
664 aValue = aValue)
665 self.__cfgfile.store()
666 except:
667 _log.Log(gmLog.lErr, "Cannot set parameter value for [%s]" % aParameterName )
668 return None
669 return 1
670
671
672 - def AddConfigParam(self, aParameterName, aType = None ,aValue=None, aDescription =None):
673 """
674 Adds a new config parameter.
675 """
676 pNameParts = string.split(aParameterName,".")
677
678 option = pNameParts[-1:][1:]
679 group = string.join(pNameParts[:-1],".")
680 if option is None or group is None:
681 return None
682
683 try:
684 result=self.__cfgfile.set(aGroup = group,
685 anOption = option,
686 aValue = aValue,
687 aComment = aDescription)
688 self.__cfgfile.store()
689 except:
690 _log.Log(gmLog.lErr, "Cannot set parameter value for [%s]" % aParameterName )
691 return None
692 return 1
693
694
696 """
697 fetch names and parameter data from config file. Returns list of
698 parameter names where group and option name are concatenated.
699 """
700
701
702
703
704 groups = self.__cfgfile.getGroups()
705 if len(groups) == 0:
706 return None
707 mParamNames = []
708 for group in (groups):
709 options = self.__cfgfile.getOptions(group)
710 if len(options) == 0:
711 continue
712 else:
713 for option in (options):
714 currType=type(self.__cfgfile.get(group,option))
715 if currType in (types.IntType, types.FloatType, types.LongType):
716 myType = 'numeric'
717 elif currType is types.StringType:
718 myType = 'string'
719 elif currType is types.ListType:
720 myType = 'str_array'
721 else:
722
723
724 mType = 'string'
725
726 description = self.__cfgfile.getComment(group,option)
727 if description is []:
728 description = ''
729 else:
730 myDescription = string.join(description,'\n')
731 optionData=[option,group,'',myType,myDescription]
732
733 newName = group + '.' + option
734 self.mConfigData[newName] = optionData
735 mParamNames.append(newName)
736
737
738
739
740 return mParamNames
741
742
744 """
745 Returns the parameter name without possible cookie part(s).
746 Needed to indentify matching config definition entry.
747 """
748
749
750
751 return aParameterName
752
753
754
755 -def exportDBSet(filename,aUser = None, aWorkplace = 'xxxDEFAULTxxx'):
756 """
757 Fetches a backend stored set of config options (defined by user and workplace)
758 and returns it as a plain text file.
759 NOTE: This will not write "valid value" information, since this is only
760 hold in config definition files !
761 Returns: 1 for success, 0 if no parameters were found, None on failure.
762 """
763 try:
764 expConfigSource = ConfigSourceDB("export",aUser,aWorkplace)
765 except:
766 _log.Log(gmLog.lErr, "Cannot open config set [%s@%s]." % (aUser,aWorkplace))
767 return None
768
769 try:
770 file = open(filename,"w")
771 except:
772 _log.Log(gmLog.lErr, "Cannot open output file %s." % (filename))
773 raise
774
775 paramList = expConfigSource.getAllParamNames()
776 if paramList is None:
777 _log.Log(gmLog.lInfo, "DB-set [%s,%s]contained no data." % (aUser,aWorkplace))
778 return 0
779 text = ''
780 for param in (paramList):
781 description = expConfigSource.getDescription(param)
782 cType = expConfigSource.getParamType(param)
783 value = expConfigSource.getConfigData(param)
784
785
786 if cType in ['string','numeric','str_array']:
787 valuestr = value
788 else:
789 valuestr = pickle.dumps(value)
790
791 file.write( "[%s]\ntype = %s\ndescription = %s\nvalue = %s\n\n" % \
792 (param,cType,description,value))
793 return len(paramList)
794
795 -def importDBSet(filename,aUser = None, aWorkplace = 'xxxDEFAULTxxx'):
796 """get config definitions from a file exported with
797 exportDBSet()."""
798
799
800 try:
801 importFile = gmCfg.cCfgFile(aFile = filename, \
802 flags= gmCfg.cfg_IGNORE_CMD_LINE)
803
804 except:
805 exc = sys.exc_info()
806 _log.LogException("Unhandled exception while opening input file [%s]" % filename, exc,verbose=0)
807 return None
808
809 try:
810 importConfigSource = ConfigSourceDB("export",aUser,aWorkplace)
811 except:
812 _log.Log(gmLog.lErr, "Cannot open config set [%s@%s]." % (aUser,aWorkplace))
813 return None
814
815 existingParamList = importConfigSource.getAllParamNames()
816
817 importData = importFile.getCfg()
818 groups = importFile.getGroups()
819
820
821 successfully_stored = 0
822 for paramName in groups:
823
824 if paramName == "":
825 continue
826 paramType = importFile.get(paramName, "type")
827 if paramType is None:
828 continue
829
830
831
832 paramDescription = importFile.get(paramName, "description")
833 if paramDescription is None:
834 continue
835
836
837 paramValueStr = importFile.get(paramName, "value")
838 if paramDescription is None:
839 continue
840 else:
841 if paramType in ['string','numeric','str_array']:
842 paramValue = eval(repr(paramValueStr))
843 else:
844 paramValue = pickle.loads(paramValueStr)
845
846 if existingParamList is not None and paramName in (existingParamList):
847 if not importConfigSource.getParamType(paramName) == paramType:
848
849
850
851 _log.Log(gmLog.lWarn,
852 "Cannot store config parameter [%s]: different type stored already." % paramName)
853 else:
854
855 s=importConfigSource.setConfigData(paramName,paramValue)
856 if s is None:
857 _log.Log(gmLog.lWarn,
858 "Cannot store config parameter [%s] to set [%s@%s]." % (paramName,aUser,aWorkplace))
859 else:
860 successfully_stored = successfully_stored + 1
861
862 else:
863
864 s=importConfigSource.addConfigParam(paramName,paramType,paramValue,paramDescription)
865 if s is None:
866 _log.Log(gmLog.lWarn,
867 "Cannot store config parameter [%s] to set [%s@%s]." % (paramName,aUser,aWorkplace))
868 else:
869 successfully_stored = successfully_stored + 1
870 return successfully_stored
871
872
873