Package Biskit :: Module ExeConfig
[hide private]
[frames] | no frames]

Source Code for Module Biskit.ExeConfig

  1  ## 
  2  ## Biskit, a toolkit for the manipulation of macromolecular structures 
  3  ## Copyright (C) 2004-2006 Raik Gruenberg & Johan Leckner 
  4  ## 
  5  ## This program is free software; you can redistribute it and/or 
  6  ## modify it under the terms of the GNU General Public License as 
  7  ## published by the Free Software Foundation; either version 2 of the 
  8  ## License, or any later version. 
  9  ## 
 10  ## This program is distributed in the hope that it will be useful, 
 11  ## but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 13  ## General Public License for more details. 
 14  ## 
 15  ## You find a copy of the GNU General Public License in the file 
 16  ## license.txt along with this program; if not, write to the Free 
 17  ## Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 18  ## 
 19   
 20  ## last $Author: graik $ 
 21  ## last $Date: 2007/04/06 10:16:07 $ 
 22  ## $Revision: 2.10 $ 
 23   
 24  """ 
 25  Collect settings for an external program from a configuration file. 
 26  """ 
 27   
 28  import ConfigParser 
 29  import user, os.path 
 30   
 31  from Biskit.Errors import BiskitError 
 32  from Biskit import EHandler 
 33   
 34  import Biskit.tools as T 
 35   
 36   
37 -class ExeConfigError( BiskitError ):
38 pass
39
40 -class CaseSensitiveConfigParser( ConfigParser.SafeConfigParser ):
41 """ 42 Change ConfigParser so that it doesn't convert option names to lower case. 43 """
44 - def optionxform(self, optionstr):
45 return optionstr
46 47
48 -class ExeConfig( object ):
49 50 """ 51 ExeConfig 52 ========= 53 54 Manage the settings that Executor needs for calling an external 55 program. 56 57 ExeConfig is initialised with a program name and expects to find 58 the configuration for this program in 59 C{ ~/.biskit/exe_|name|.dat }. Only if nothing is found there, it looks 60 for C{ external/defaults/exe_|name|.dat } in the biskit installation 61 folder. If neither of the two files are found, an error is raised 62 (strict=1) or the binary is assumed to be |name| and must be 63 accessible in the search path (strict=0). 64 65 66 Example 67 ------- 68 69 The configuration file (exe_name.dat) should look like this:: 70 71 ---- start example configuration file ---- 72 [BINARY] 73 74 comment=the emacs editor 75 bin=emacs 76 cwd= 77 shell=0 78 shellexe= 79 pipes=0 80 ## Use new environment containing only variables given below 81 replaceEnv=0 82 83 [ENVIRONMENT] 84 85 HOME= 86 EMACS_CONFIG=~/.emacs/config.dat 87 ---- end of example file ---- 88 89 90 This example config would ask Executor to look for an executable 91 called 'emacs' in the local search path. Before running it, 92 executor should check that a variable $HOME exists in the local 93 shell environment (or raise an error otherwise) and set the 94 variable $EMACS_CONFIG to the given path. 95 96 The other settings specify how the program call is done (see also 97 Python 2.4 subprocess.Popen() ): 98 99 - cwd ... working directory (empty -- current working directory) 100 - shell ... wrap process in separate shell 101 - shellexe ... which shell (empty -- sh) 102 - pipes ... paste input via STDIN, collect output at STDOUT 103 104 Missing options are reset to their default value; See 105 L{ ExeConfig.reset() }. All entries in section BINARY are put into the 106 name space of the ExeConfig object. That means an ExeConfig object x 107 created from the above file can be used as follows: 108 109 >>> x = ExeConfig( 'emacs' ) 110 >>> x.cwd == None 111 >>> True 112 >>> print x.comment 113 >>> the emacs editor 114 """ 115 116 ## static fields 117 PATH_CONF = user.home + '/.biskit' 118 PATH_CONF_DEFAULT = os.path.join( T.projectRoot(), 'external/defaults' ) 119 SECTION_BIN = 'BINARY' 120 SECTION_ENV = 'ENVIRONMENT' 121
122 - def __init__( self, name, strict=1 ):
123 """ 124 @param name: unique name of the program 125 @type name: str 126 @param strict: insist on a config file exe_name.dat 127 and do not tolerate missing environment variables 128 (default: 1) 129 @type strict: 0|1 130 131 @raise ExeConfigError: if strict==1 and config file incomplete/missing 132 """ 133 self.name = name #: identifier 134 #: path to configuration file 135 self.dat = os.path.join( self.PATH_CONF, 'exe_%s.dat' % name ) 136 137 if not os.path.exists( self.dat ): 138 self.dat = os.path.join( self.PATH_CONF_DEFAULT,'exe_%s.dat'%name ) 139 140 #: True if a configuration file was found 141 self.dat_found = os.path.exists( self.dat ) 142 143 self.strict = strict 144 145 self.env_checked = 0 ## environment was verified 146 147 if strict and not self.dat_found: 148 149 raise ExeConfigError,\ 150 'Could not find configuration file %s for program %s.'\ 151 % (self.dat, self.name) 152 153 self.conf = CaseSensitiveConfigParser() 154 self.conf.read( self.dat ) 155 156 self.reset() 157 self.update()
158 159
160 - def reset( self ):
161 """ 162 Reset all required parameters. Called at creation 163 """ 164 ## default values 165 self.comment = 'no comment or missing configuration file' 166 self.bin = self.name 167 self.shell = 0 168 self.shellexe = None 169 self.pipes = 0 170 self.cwd = None #'./' 171 172 self.replaceEnv = 0 173 self.env = None
174 175
176 - def update( self ):
177 """ 178 Load settings from associated configuration file (if available). 179 Is automatically called at creation. 180 181 @raise ExeConfigError: if section [BINARY] was not found in the file 182 """ 183 ## get parameters from config file if available; type-cast values 184 try: 185 dconf = self.conf.items( self.SECTION_BIN ) 186 187 for key, value in dconf: 188 189 ## default type is string 190 t = type( self.__dict__.get( key, '' ) ) 191 192 ## leave default value if None is given 193 if value is not '': 194 self.__dict__[ key ] = t( value ) 195 196 except ConfigParser.NoSectionError: 197 if self.strict: 198 raise ExeConfigError,\ 199 'Could not find BINARY section in %s.' % self.dat 200 201 try: 202 self.env = self.conf.items( self.SECTION_ENV ) 203 except: 204 pass
205 206
207 - def validate( self ):
208 """ 209 Validate the path to the binary. 210 211 @raise ExeConfigError: if environment is not fit for running 212 the program 213 """ 214 try: 215 self.bin = T.absbinary( self.bin ) 216 217 missing = self.update_environment() 218 report = '%s is missing environment variables: %r'\ 219 % (self.name, missing ) 220 221 if missing and self.strict: 222 raise ExeConfigError, report 223 224 if missing: 225 EHandler.warning( report ) 226 227 except IOError, why: 228 raise ExeConfigError, str(why) + ' Check %s!' % self.dat
229 230
231 - def environment( self ):
232 """ 233 Get needed environment variables. 234 235 @return: dictionary with environment for subprocess.Popen 236 OR None, if no environment was specified 237 @rtype: {str:str} OR None 238 239 @raise ExeConfigError: if env was not yet checked by update_environment 240 """ 241 if not self.env_checked: 242 raise ExeConfigError, 'Environment not yet checked, validate()!' 243 244 if self.env is None: 245 return None 246 247 r = {} 248 for key,value in self.env: 249 r[ key ] = value 250 251 return r
252 253
254 - def update_environment( self ):
255 """ 256 Check for missing environment settings. 257 258 @return: names of required but missing environment variables 259 @rtype: [str] 260 """ 261 missing = [] 262 263 if self.env: 264 265 for i in range( len( self.env) ): 266 267 key, value = self.env[ i ] 268 269 if value is '': 270 271 if os.getenv( key ) is None: 272 missing += [ key ] 273 else: 274 self.env[ i ] = (key, os.getenv( key ) ) 275 276 self.env_checked = 1 277 278 return missing
279 280
281 - def __repr__( self ):
282 s = 'ExeConfig for %s' % self.name 283 for k,v in self.__dict__.items(): 284 s += '\n%10s \t%r' % (k,v) 285 return s
286
287 - def __str__( self ):
288 return self.__repr__()
289 290 291 292 ############# 293 ## TESTING 294 ############# 295 import Biskit.test as BT 296
297 -class Test(BT.BiskitTest):
298 """ExeConfig test""" 299
300 - def test_ExeConfig( self ):
301 """ExeConfig test (validate xclock)""" 302 303 x = ExeConfig( 'xclock', strict=1 ) 304 x.validate() 305 306 if self.local: 307 print x.bin 308 309 self.assertEquals( True, 'xclock' in x.bin )
310 311 312 if __name__ == '__main__': 313 314 BT.localTest() 315