Module EDApplication
[hide private]
[frames] | no frames]

Source Code for Module EDApplication

  1  # 
  2  #    Project: The EDNA Kernel 
  3  #             http://www.edna-site.org 
  4  # 
  5  #    Copyright (C) 2008-2012 European Synchrotron Radiation Facility 
  6  #                            Grenoble, France 
  7  # 
  8  #    Principal authors: Marie-Francoise Incardona (incardon@esrf.fr) 
  9  #                       Olof Svensson (svensson@esrf.fr)  
 10  #                       Jerome Kieffer 
 11  # 
 12  #    This program is free software: you can redistribute it and/or modify 
 13  #    it under the terms of the GNU Lesser General Public License as published 
 14  #    by the Free Software Foundation, either version 3 of the License, or 
 15  #    (at your option) any later version. 
 16  # 
 17  #    This program is distributed in the hope that it will be useful, 
 18  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 19  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 20  #    GNU Lesser General Public License for more details. 
 21  # 
 22  #    You should have received a copy of the GNU General Public License 
 23  #    and the GNU Lesser General Public License  along with this program.   
 24  #    If not, see <http://www.gnu.org/licenses/>. 
 25  # 
 26  from __future__ import with_statement 
 27  __authors__ = [ "Marie-Francoise Incardona", "Olof Svensson", "Jerome Kieffer" ] 
 28  __contact__ = "svensson@esrf.fr" 
 29  __license__ = "LGPLv3+" 
 30  __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" 
 31   
 32  import os, sys, time 
 33  from EDThreading            import Semaphore 
 34  from EDCommandLine          import EDCommandLine 
 35  from EDVerbose              import EDVerbose 
 36  from EDConfigurationStatic  import EDConfigurationStatic 
 37  from EDMessage              import EDMessage 
 38  from EDUtilsPath            import EDUtilsPath 
 39  from EDUtilsFile            import EDUtilsFile 
 40  from EDFactoryPluginStatic  import EDFactoryPluginStatic 
41 42 43 -class EDApplication(object):
44 """ 45 This is the main EDNA application class. This class can be sub-classed for any specific application need. 46 An EDNA application is able to launch an entry point plugin. It accepts the following parameter: 47 --execute : name of the plugin to be executed 48 --inputFile : related plugin data (xml input data file name) 49 --outputFile : related plugin result (xml output data file name) 50 --conf : configuration file name 51 --basedir : where the application working directory should go 52 --DEBUG or --debug : turns on debugging 53 -v or --version : Displays the application name and version 54 --verbose : Turns on verbose mode 55 --no-log : Turns off logging 56 -h or --help : Prints out an usage message 57 """ 58 59 CONFIGURATION_PARAM_LABEL = "--conf" 60 PLUGIN_PARAM_LABEL = "--execute" 61 DATASET_PARAM_LABEL = "--inputFile" 62 OUTPUT_PARAM_LABEL = "--outputFile" 63 DATASET_BASE_DIRECTORY = "--basedir" 64 DEBUG_PARAM_LABEL_1 = "--DEBUG" 65 DEBUG_PARAM_LABEL_2 = "--debug" 66 VERSION_PARAM_LABEL_1 = "-v" 67 VERSION_PARAM_LABEL_2 = "--version" 68 VERBOSE_MODE_LABEL = "--verbose" 69 NO_LOG_LABEL = "--no-log" 70 HELP_LABEL_1 = "-h" 71 HELP_LABEL_2 = "--help" 72 73 __edConfiguration = None 74 __edFactoryPlugin = None 75 __semaphore = Semaphore() 76 77
78 - def __init__(self, _strName="EDApplication", \ 79 _strVersion="1.0.1", \ 80 _strPluginName=None, \ 81 _strConfigurationFileName=None, \ 82 _strDataInputFilePath=None, \ 83 _edLogFile=None, \ 84 _strBaseDir=None, \ 85 _strWorkingDir=None, \ 86 _strDataOutputFilePath=None):
87 self.__strName = _strName 88 self.__strVersion = _strVersion 89 self.__strPluginName = _strPluginName 90 self.__strConfigurationFileName = _strConfigurationFileName 91 self.__strDataInputFilePath = _strDataInputFilePath 92 self.__strDataOutputFilePath = _strDataOutputFilePath 93 self.__edLogFile = _edLogFile 94 self.__strBaseDir = _strBaseDir 95 self.__strWorkingDir = _strWorkingDir 96 self.__strFullApplicationWorkingDirectory = None 97 self.__strXMLData = None 98 self.__listErrorMessages = [] 99 self.__listWarningMessages = [] 100 self.__xsDataOutput = None 101 self.__edObtainedOutputDataFile = None 102 self.__strDataOutputFilePath = None 103 self.__edPlugin = None 104 self.__edCommandLine = EDCommandLine(sys.argv) 105 self.__strApplicationInstanceName = self.__strName + "_" + time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time())) 106 self.__strLogFileName = self.__strApplicationInstanceName + ".log" 107 self.__bIsFailure = False 108 self.__strCurrentWorkingDirectory = os.getcwd() 109 self.__strConfigurationHome = None 110 self.__strPathToLogFile = None
111 112
113 - def execute(self):
114 """ 115 This is the main execute method which executes preProcess, process and postProcess. 116 """ 117 self.preProcess() 118 self.process() 119 self.postProcess()
120 121
122 - def preProcess(self):
123 """ 124 Creates the application working directory (log dir) 125 Initializes the configuration 126 retrieves the plugin xml data to be passed to the plugin 127 """ 128 EDVerbose.DEBUG("EDApplication.preProcess") 129 self.processCommandline() 130 if (not self.__bIsFailure): 131 # Check that the plugin can be located 132 strPluginLocation = EDFactoryPluginStatic.getFactoryPlugin().getModuleLocation(self.__strPluginName) 133 if (strPluginLocation is None): 134 EDVerbose.error("Plugin %s cannot be loaded!" % self.__strPluginName) 135 self.__bIsFailure = True 136 # Check that the input file can be read 137 if (self.getDataInputFilePath() is not None) and (not os.path.exists(self.__strDataInputFilePath)): 138 EDVerbose.error("Input XML file not found : %s" % self.__strDataInputFilePath) 139 self.__bIsFailure = True 140 # Check that the output file can be created 141 if (self.__strDataOutputFilePath is not None): 142 strOutputDirectory = os.path.dirname(self.__strDataOutputFilePath) 143 if (strOutputDirectory is None or strOutputDirectory == ""): 144 strOutputDirectory = os.getcwd() 145 self.__strDataOutputFilePath = os.path.join(strOutputDirectory, self.__strDataOutputFilePath) 146 if (not os.access(strOutputDirectory, os.W_OK)): 147 EDVerbose.error("Output directory not writable: %s" % strOutputDirectory) 148 self.__bIsFailure = True 149 elif (os.path.exists(self.__strDataOutputFilePath)): 150 if (not os.access(self.__strDataOutputFilePath, os.W_OK)): 151 EDVerbose.error("Output file not writable: %s" % self.__strDataOutputFilePath) 152 self.__bIsFailure = True 153 if (not self.__bIsFailure): 154 EDVerbose.DEBUG("EDApplication.PLUGIN_PARAM_LABEL: " + EDApplication.PLUGIN_PARAM_LABEL) 155 156 if self.__strConfigurationFileName is not None: 157 # Load the configuration file 158 if (os.path.exists(self.__strConfigurationFileName)): 159 EDVerbose.screen("Loading Configuration file: %s" % self.__strConfigurationFileName) 160 EDConfigurationStatic.addConfigurationFile(self.__strConfigurationFileName, _bReplace=True) 161 else: 162 EDVerbose.warning("Cannot find configuration file: %s" % self.__strConfigurationFileName) 163 pyDictionary = {} 164 pyDictionary[ "${EDNA_HOME}" ] = EDUtilsPath.getEdnaHome() 165 if self.getDataInputFilePath() is not None: 166 self.__strXMLData = EDUtilsFile.readFileAndParseVariables(self.getDataInputFilePath(), pyDictionary) 167 # Create the application working directory 168 if(self.__strWorkingDir is None): 169 self.__strWorkingDir = self.__strApplicationInstanceName 170 self.createApplicationWorkingDirectory()
171 172
173 - def process(self):
174 """ 175 Calls the Plugin to be executed 176 """ 177 if (not self.__bIsFailure): 178 self.__edPlugin = EDFactoryPluginStatic.loadPlugin(self.__strPluginName) 179 if(self.__edPlugin is not None): 180 self.__edPlugin.setBaseDirectory(self.__strFullApplicationWorkingDirectory) 181 self.__edPlugin.setBaseName(self.__strPluginName) 182 self.__edPlugin.setDataInput(self.__strXMLData) 183 self.__edPlugin.connectSUCCESS(self.doSuccessActionPlugin) 184 self.__edPlugin.connectFAILURE(self.doFailureActionPlugin) 185 EDVerbose.DEBUG("EDApplication.process: Executing " + self.__strPluginName) 186 self.__edPlugin.execute() 187 self.__edPlugin.synchronize() 188 else: 189 EDVerbose.error(EDMessage.ERROR_PLUGIN_NOT_LOADED_02 % ('EDApplication.process', self.__strPluginName)) 190 self.__bIsFailure = True
191 192 193 194
195 - def processCommandline(self):
196 """ 197 This method is intended to be overridden by applications who 198 would like to implement their own command line handling. 199 200 This default method implements the following workflow: 201 - Check for debug, verbose and log file command line options 202 203 """ 204 EDVerbose.DEBUG("EDApplication.execute") 205 EDVerbose.log(self.__edCommandLine.getCommandLine()) 206 self.processCommandLineDebugVerboseLogFile() 207 # Determine the base directory 208 if(self.__strBaseDir is None): 209 self.processCommandLineBaseDirectory() 210 # Set the name of the log file 211 self.__strPathToLogFile = os.path.abspath(os.path.join(self.__strBaseDir, self.__strLogFileName)) 212 EDVerbose.setLogFileName(self.__strPathToLogFile) 213 self.processCommandLineHelp() 214 if (not self.__bIsFailure): 215 self.processCommandLineVersion() 216 if (not self.__bIsFailure): 217 # Name of the plugin to be executed 218 if (self.__strPluginName is None): 219 self.processCommandLinePluginName() 220 # Path to the input XML file 221 if (self.__strDataInputFilePath is None): 222 self.processCommandLineInputFilePath() 223 # Path to the output XML file 224 if(self.__strDataOutputFilePath is None): 225 self.processCommandLineOutputFilePath() 226 if (self.__bIsFailure): 227 self.usage() 228 if (not self.__bIsFailure): 229 # If strConfigurationFileName is None, this means that it has not been given to the constructor\ 230 # It has been given by the command line\ 231 if(self.__strConfigurationFileName is None): 232 self.__strConfigurationFileName = self.getCommandLineArgument(EDApplication.CONFIGURATION_PARAM_LABEL)
233 234 235
237 EDVerbose.DEBUG("EDApplication.processCommandLineDebugVerboseLogFile") 238 EDVerbose.setVerboseOff() 239 # Check if no log file 240 if (self.__edCommandLine.existCommand(EDApplication.NO_LOG_LABEL)): 241 EDVerbose.setLogFileOff() 242 EDVerbose.DEBUG("Log file output switched off") 243 # Check if debug mode 244 if (self.__edCommandLine.existCommand(EDApplication.DEBUG_PARAM_LABEL_1) or 245 self.__edCommandLine.existCommand(EDApplication.DEBUG_PARAM_LABEL_2)): 246 EDVerbose.setVerboseDebugOn() 247 EDVerbose.DEBUG("Debug Mode [ON]") 248 # Check if verbose 249 if (self.__edCommandLine.existCommand(EDApplication.VERBOSE_MODE_LABEL)): 250 EDVerbose.setVerboseOn()
251 252
253 - def processCommandLineHelp(self):
254 EDVerbose.DEBUG("EDApplication.processCommandLineHelp") 255 if (self.__edCommandLine.existCommand(EDApplication.HELP_LABEL_1) 256 or self.__edCommandLine.existCommand(EDApplication.HELP_LABEL_2)): 257 EDVerbose.setVerboseOn() 258 self.usage() 259 self.__bIsFailure = True
260 261
263 EDVerbose.DEBUG("EDApplication.processCommandLineVersion") 264 if (self.__edCommandLine.existCommand(EDApplication.VERSION_PARAM_LABEL_1) or 265 self.__edCommandLine.existCommand(EDApplication.VERSION_PARAM_LABEL_2)): 266 EDVerbose.setVerboseOn() 267 EDVerbose.screen("%s version %s" % (self.__strName, self.__strVersion)) 268 self.__bIsFailure = True
269 270 271
273 """ 274 """ 275 EDVerbose.DEBUG("EDApplication.processCommandLinePluginName") 276 if (not self.__edCommandLine.existCommand(EDApplication.PLUGIN_PARAM_LABEL)): 277 EDVerbose.error("No %s command line argument found!" % EDApplication.PLUGIN_PARAM_LABEL) 278 self.__bIsFailure = True 279 else: 280 self.__strPluginName = self.getCommandLineArgument(EDApplication.PLUGIN_PARAM_LABEL) 281 EDVerbose.DEBUG("EDApplication.processCommandLinePluginName : %s = %s" % (EDApplication.PLUGIN_PARAM_LABEL, self.__strPluginName))
282 283
285 """ 286 """ 287 EDVerbose.DEBUG("EDApplication.processCommandLineInputFilePath") 288 if (not self.__edCommandLine.existCommand(EDApplication.DATASET_PARAM_LABEL)): 289 EDVerbose.error("No %s command line argument found!" % EDApplication.DATASET_PARAM_LABEL) 290 self.__bIsFailure = True 291 else: 292 self.__strDataInputFilePath = self.getCommandLineArgument(EDApplication.DATASET_PARAM_LABEL) 293 EDVerbose.DEBUG("EDApplication.initApplication : %s = %s" % (EDApplication.DATASET_PARAM_LABEL, self.__strDataInputFilePath))
294 295
297 """ 298 """ 299 EDVerbose.DEBUG("EDApplication.processCommandLineOutputFilePath") 300 if (not self.__edCommandLine.existCommand(EDApplication.OUTPUT_PARAM_LABEL)): 301 EDVerbose.DEBUG("No %s command line argument found" % EDApplication.OUTPUT_PARAM_LABEL) 302 else: 303 self.__strDataOutputFilePath = self.getCommandLineArgument(EDApplication.OUTPUT_PARAM_LABEL) 304 EDVerbose.DEBUG("EDApplication.initApplication : %s = %s" % (EDApplication.OUTPUT_PARAM_LABEL, self.__strDataOutputFilePath))
305 306
308 """ 309 """ 310 EDVerbose.DEBUG("EDApplication.processCommandLineBaseDirectory") 311 self.__strBaseDir = self.getCommandLineArgument(EDApplication.DATASET_BASE_DIRECTORY) 312 if(self.__strBaseDir is None): 313 self.__strBaseDir = os.getcwd() 314 EDVerbose.DEBUG("Base directory set to current working directory = %s" % (self.__strBaseDir)) 315 else: 316 EDVerbose.DEBUG("%s = %s" % (EDApplication.DATASET_BASE_DIRECTORY, self.__strBaseDir))
317 318 319 320 321
322 - def postProcess(self):
323 """ 324 """ 325 # Restore the current working directory 326 os.chdir(self.__strCurrentWorkingDirectory)
327 328 329 @classmethod
330 - def usage(cls):
331 """ 332 Print usage... 333 """ 334 EDVerbose.screen("") 335 EDVerbose.screen("Usage: ") 336 EDVerbose.screen("") 337 EDVerbose.screen("%35s : Name of the plugin to be executed" % (cls.PLUGIN_PARAM_LABEL)) 338 EDVerbose.screen("") 339 EDVerbose.screen("%35s : Path to the XML input file" % (cls.DATASET_PARAM_LABEL)) 340 EDVerbose.screen("") 341 EDVerbose.screen("-----------------------------------------------------------------------------------------------------------") 342 EDVerbose.screen("") 343 EDVerbose.screen(" Additional options available:") 344 EDVerbose.screen("") 345 EDVerbose.screen("%35s : Path to the file wich will contain the XML output" % (cls.OUTPUT_PARAM_LABEL)) 346 EDVerbose.screen("") 347 EDVerbose.screen("%35s : Base directory, i.e. working directory for the application" % (cls.DATASET_BASE_DIRECTORY)) 348 EDVerbose.screen("") 349 EDVerbose.screen("%35s : Verbose mode" % (cls.VERBOSE_MODE_LABEL)) 350 EDVerbose.screen("") 351 EDVerbose.screen("%35s : XSConfiguration file" % (cls.CONFIGURATION_PARAM_LABEL)) 352 EDVerbose.screen("") 353 EDVerbose.screen("%35s : Executable version info" % (cls.VERSION_PARAM_LABEL_1 + " or " + cls.VERSION_PARAM_LABEL_2)) 354 EDVerbose.screen("") 355 EDVerbose.screen("%35s : DEBUG log traces" % (cls.DEBUG_PARAM_LABEL_1 + " or " + cls.DEBUG_PARAM_LABEL_2)) 356 EDVerbose.screen("") 357 EDVerbose.screen("%35s : No log file" % (cls.NO_LOG_LABEL)) 358 EDVerbose.screen("") 359 EDVerbose.screen("%35s : This help message" % (cls.HELP_LABEL_1 + " or " + cls.HELP_LABEL_2)) 360 EDVerbose.screen("")
361 362 363 @classmethod
364 - def getFactoryPlugin(cls):
365 EDVerbose.WARNING("the use of EDclsetFactoryPlugin is deprecated. Please use EDFactoryPluginStatic.getFactoryPlugin instead.") 366 return EDFactoryPluginStatic.getFactoryPlugin
367 368 369 @classmethod
370 - def loadPlugin(cls, _strPluginName):
371 EDVerbose.WARNING("The use of EDApplication.loadPlugin is deprecated. Please use EDFactoryPluginStatic.getFactoryPlugin instead.") 372 return EDFactoryPluginStatic.loadPlugin(_strPluginName)
373 374 375 @classmethod
376 - def loadModule(cls, _strModuleName):
377 EDVerbose.WARNING("The use of EDApplication.loadModule is deprecated. Please use EDFactoryPluginStatic.getFactoryPlugin instead.") 378 EDFactoryPluginStatic.loadModule(_strModuleName)
379 380
381 - def getDataInputFilePath(self):
382 return self.__strDataInputFilePath
383 384
385 - def getBaseDir(self):
386 """ 387 Getter for base directory 388 @return: path of the base directory 389 @rtype: string 390 """ 391 return self.__strBaseDir
392 393
395 """ 396 Created the working directory of the application (<date>-<application name>) 397 First tries to retrieve the base dir from --basedir option or related parameter from constructor 398 Otherwise tries to retrieve it from EDNA_BASE_DIRECTORY environment variable 399 Otherwise put the base dir as the current directory 400 """ 401 EDVerbose.DEBUG("EDApplication.createApplicationWorkingDirectory") 402 strBaseDirectory = self.getBaseDir() 403 strDateTime = time.strftime("%Y%m%d-%H%M%S", time.localtime(time.time())) 404 self.__strFullApplicationWorkingDirectory = os.path.join(strBaseDirectory, self.__strWorkingDir) 405 # Check that a folder / file with the same name already exists 406 if(os.path.exists(self.__strFullApplicationWorkingDirectory) or \ 407 os.path.exists(self.__strFullApplicationWorkingDirectory)): 408 # It does exist so we have to modify the name of the working directory 409 iIndex = 1 410 bContinueFlag = True 411 while (bContinueFlag): 412 self.__strFullApplicationWorkingDirectory = os.path.join(strBaseDirectory, 413 "%s_%d" % \ 414 (strDateTime, \ 415 iIndex)) 416 if(os.path.isdir(self.__strFullApplicationWorkingDirectory) or \ 417 os.path.exists(self.__strFullApplicationWorkingDirectory)): 418 iIndex += 1 419 else: 420 bContinueFlag = False 421 # Make the directory 422 os.mkdir(self.__strFullApplicationWorkingDirectory) 423 # Change it to be the current working directory 424 os.chdir(self.__strFullApplicationWorkingDirectory)
425 426
428 return self.__strFullApplicationWorkingDirectory
429
431 return self.__strCurrentWorkingDirectory
432 433
434 - def doSuccessActionPlugin(self, _edPlugin):
435 """ 436 """ 437 EDVerbose.DEBUG("EDApplication.doSuccessActionPlugin") 438 # Print the potential Warnings and Errors 439 self.__listWarningMessages = _edPlugin.getListOfWarningMessages() 440 EDVerbose.DEBUG("EDApplication.doSuccessActionPlugin: Plugin %s Successful with : %i Warnings " % (_edPlugin.getPluginName(), len(self.__listWarningMessages))) 441 for warningMessage in self.__listWarningMessages: 442 EDVerbose.screen(warningMessage) 443 self.__listErrorMessages = _edPlugin.getListOfErrorMessages() 444 EDVerbose.DEBUG("EDApplication.doSuccessActionPlugin: Plugin %s Successful with : %i Errors" % (_edPlugin.getPluginName(), len(self.__listErrorMessages))) 445 for errorMessage in self.__listErrorMessages: 446 EDVerbose.error(errorMessage) 447 if (_edPlugin.hasDataOutput()): 448 xsDataOutput = _edPlugin.getDataOutput() 449 if (xsDataOutput is not None and self.__strDataOutputFilePath is not None): 450 xsDataOutput.exportToFile(self.__strDataOutputFilePath) 451 if (xsDataOutput is not None and self.__edObtainedOutputDataFile is not None): 452 xsDataOutput.exportToFile(self.__edObtainedOutputDataFile)
453 454
455 - def doFailureActionPlugin(self, _edPlugin):
456 EDVerbose.DEBUG("EDApplication.doFailureActionPlugin") 457 458 # Print the potential Warnings and Errors 459 EDVerbose.DEBUG("EDApplication.doFailureActionPlugin: Plugin %s failed" % _edPlugin.getClassName()) 460 self.__listWarningMessages = _edPlugin.getListOfWarningMessages() 461 for warningMessage in self.__listWarningMessages: 462 EDVerbose.screen(warningMessage) 463 464 self.__listErrorMessages = _edPlugin.getListOfErrorMessages() 465 for errorMessage in self.__listErrorMessages: 466 EDVerbose.screen(errorMessage) 467 if (_edPlugin.hasDataOutput()): 468 xsDataOutput = _edPlugin.getDataOutput() 469 if (xsDataOutput is not None and self.__strDataOutputFilePath is not None): 470 xsDataOutput.exportToFile(self.__strDataOutputFilePath) 471 if (xsDataOutput is not None and self.__edObtainedOutputDataFile is not None): 472 xsDataOutput.exportToFile(self.__edObtainedOutputDataFile)
473 474
475 - def getPlugin(self):
476 return self.__edPlugin
477 478
479 - def getPluginOutputData(self):
480 return self.__xsDataOutput
481 482
483 - def getWarningMessages(self):
484 return self.__listWarningMessages
485 486
487 - def getErrorMessages(self):
488 return self.__listErrorMessages
489 490
491 - def getEdCommandLine(self):
492 return self.__edCommandLine
493 494
495 - def getCommandLine(self):
496 return self.__edCommandLine.getCommandLine()
497 498
499 - def getCommandLineArguments(self):
500 with self.__class__.__semaphore: 501 edCommandLine = self.__edCommandLine.getCommandLine() 502 return edCommandLine
503
504 - def getCommandLineArgument(self, _strKey):
505 with self.__class__.__semaphore: 506 strCommandLineArgument = self.__edCommandLine.getArgument(_strKey) 507 return strCommandLineArgument
508 509 @classmethod
510 - def synchronizeOn(cls):
511 """ 512 Lock the whole class 513 """ 514 cls.__semaphore.acquire()
515 516 517 @classmethod
518 - def synchronizeOff(cls):
519 """ 520 Unlock the whole class 521 """ 522 cls.__semaphore.release()
523 524
525 - def getApplicationName(self):
526 return self.__strName + "-" + self.__strVersion
527 528
529 - def getWorkingDir(self):
530 """ 531 Getter for working dir 532 @rtype: string 533 @return working dir 534 """ 535 return self.__strWorkingDir
536 537
538 - def setWorkingDir(self, _strDir):
539 """ 540 Setter for working dir 541 @type _strDir: string 542 @param _strDir: working dir 543 """ 544 self.__strWorkingDir = _strDir
545 546
547 - def isFailure(self):
548 return self.__bIsFailure
549 550
551 - def setFailure(self, _bFailure):
552 self.__bIsFailure = _bFailure
553 554
555 - def getPluginName(self):
556 return self.__strPluginName
557