Clean up exception handling in TestON core

    - Catch more specific exceptions
    - Clearer Style
    - Allow CTRL-C to exit the test cleanly whether from the TestON
      cli or ruinning as a script

Change-Id: I5c7d39b334c57e3e0162eef00f82a797a78144fd
diff --git a/TestON/bin/cli.py b/TestON/bin/cli.py
index ffe9d67..54d9781 100755
--- a/TestON/bin/cli.py
+++ b/TestON/bin/cli.py
@@ -93,15 +93,23 @@
         mail <mail-id or list of mail-ids seperated by comma>
         example 1, to execute the examples specified in the ~/examples diretory.
         '''
-        args = args.split()
-        options = {}
-        options = self.parseArgs(args,options)
-        options = dictToObj(options)
-        if not testthread:
-            test = TestThread(options)
-            test.start()
-        else :
-            print main.TEST+ " test execution paused, please resume that before executing to another test"
+        try:
+            args = args.split()
+            options = {}
+            options = self.parseArgs(args,options)
+            options = dictToObj(options)
+            if not testthread:
+                test = TestThread(options)
+                test.start()
+                while test.isAlive:
+                    test.join(1)
+            else :
+                print main.TEST+ " test execution paused, please resume that before executing to another test"
+        except KeyboardInterrupt, SystemExit:
+            print "Interrupt called, Exiting."
+            test._Thread__stop()
+            main.cleanup()
+            main.exit()
 
     def do_resume(self, line):
         '''
@@ -157,7 +165,7 @@
             else :
                 try :
                     dump.pprint(vars(main)[line])
-                except KeyError,e:
+                except KeyError as e:
                     print e
         else :
             print "There is no paused test "
@@ -261,7 +269,7 @@
                         options = self.testcasesInRange(index,option,args,options)
                 else :
                     options['testname'] = option
-        except IndexError,e:
+        except IndexError as e:
             print e
 
         return options
@@ -310,7 +318,11 @@
                 super(CLI, self).cmdloop(intro="")
                 self.postloop()
             except KeyboardInterrupt:
-                testthread.pause()
+                if testthread:
+                    testthread.pause()
+                else:
+                    print "KeyboardInterrupt, Exiting."
+                    sys.exit()
 
     def do_echo( self, line ):
         '''
@@ -337,7 +349,7 @@
         '''
         try:
             exec( line )
-        except Exception, e:
+        except Exception as e:
             output( str( e ) + '\n' )
 
     def do_interpret(self,line):
@@ -353,7 +365,7 @@
         try :
             translated_code = ospk.interpret(text=line)
             print translated_code
-        except AttributeError, e:
+        except AttributeError as e:
             print 'Dynamic params are not allowed in single statement translations'
 
     def do_do (self,line):
@@ -367,8 +379,9 @@
             try :
                 translated_code = ospk.interpret(text=line)
                 eval(translated_code)
-            except (AttributeError,SyntaxError), e:
-                print 'Dynamic params are not allowed in single statement translations'
+            except ( AttributeError, SyntaxError ) as e:
+                print 'Dynamic params are not allowed in single statement translations:'
+                print e
         else :
             print "Do will translate and execute the openspeak statement for the paused test.\nPlease use interpret to translate the OpenSpeak statement."
 
@@ -531,8 +544,8 @@
                         if not self.is_stop :
                             result = self.test_on.cleanup()
                         self.is_stop = True
-                except(KeyboardInterrupt):
-                    print "Recevied Interrupt,cleaning-up the logs and drivers before exiting"
+                except KeyboardInterrupt:
+                    print "Recevied Interrupt, cleaning-up the logs and drivers before exiting"
                     result = self.test_on.cleanup()
                     self.is_stop = True
 
@@ -542,9 +555,17 @@
         '''
         Will pause the test.
         '''
-        print "Will pause the test's execution, after completion of this step.....\n\n\n\n"
-        cli.pause = True
-        self._stopevent.set()
+        if not cli.pause:
+            print "Will pause the test's execution, after completion of this step.....\n\n\n\n"
+            cli.pause = True
+            self._stopevent.set()
+        elif cli.pause and self.is_stop:
+            print "KeyboardInterrupt, Exiting."
+            self.test_on.exit()
+        else:
+            print "Recevied Interrupt, cleaning-up the logs and drivers before exiting"
+            result = self.test_on.cleanup()
+            self.is_stop = True
 
     def play(self):
         '''
diff --git a/TestON/core/teston.py b/TestON/core/teston.py
index 4e53ee2..17893a1 100644
--- a/TestON/core/teston.py
+++ b/TestON/core/teston.py
@@ -146,8 +146,10 @@
             try :
                 self.configDict = xmldict.xml_to_dict(xml)
                 return self.configDict
-            except Exception:
+            except IOError:
                 print "There is no such file to parse " + self.configFile
+        else:
+            print "There is no such file to parse " + self.configFile
 
     def componentInit(self,component):
         '''
@@ -400,7 +402,13 @@
                             print "Disconnecting from " + str(tempObject.name) + ": " + \
                                   str(tempObject)
                             tempObject.disconnect()
-                        except Exception:
+                        except KeyboardInterrupt:
+                            pass
+                        except KeyError:
+                            # Component not created yet
+                            self.log.warn( "Could not find the component " +
+                                           str( component ) )
+                        except StandardError:
                             self.log.exception( "Exception while disconnecting from " +
                                                  str( component ) )
                             result = self.FALSE
@@ -408,7 +416,14 @@
                     for driver in self.componentDictionary.keys():
                         try:
                             vars(self)[driver].close_log_handles()
-                        except Exception:
+                        except KeyboardInterrupt:
+                            pass
+                        except KeyError:
+                            # Component not created yet
+                            self.log.warn( "Could not find the component " +
+                                           str( driver ) + " while trying to" +
+                                           " close log file" )
+                        except StandardError:
                             self.log.exception( "Exception while closing log files for " +
                                                  str( driver ) )
                             result = self.FALSE
@@ -440,7 +455,7 @@
                 for component in self.componentDictionary.keys():
                     tempObject  = vars(self)[component]
                     result = tempObject.onfail()
-            except(Exception),e:
+            except StandardError as e:
                 print str(e)
                 result = self.FALSE
         else:
@@ -448,7 +463,7 @@
                 for component in components:
                     tempObject  = vars(self)[component]
                     result = tempObject.onfail()
-            except(Exception),e:
+            except StandardError as e:
                 print str(e)
                 result = self.FALSE
 
@@ -558,7 +573,7 @@
             try :
                 import json
                 response_dict = json.loads(response)
-            except Exception:
+            except StandardError:
                 self.log.exception( "Json Parser is unable to parse the string" )
             return response_dict
         elif ini_match :
@@ -573,8 +588,8 @@
             self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
             try :
                 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
-            except Exception, e:
-                self.log.exception( e )
+            except StandardError:
+                self.log.exception()
             return response_dict
 
     def dict_to_return_format(self,response,return_format,response_dict):
@@ -635,7 +650,10 @@
                 try:
                     thread._Thread__stop()
                 except:
-                    print(str(thread.getName()) + ' could not be terminated' )
+                    # NOTE: We should catch any exceptions while trying to
+                    # close the thread so that we can try to close the other
+                    # threads as well
+                    print( str( thread.getName() ) + ' could not be terminated' )
         sys.exit()
 
 def verifyOptions(options):
@@ -760,7 +778,7 @@
         main.exit()
     try :
         testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
-    except(ImportError):
+    except ImportError:
         print "There was an import error, it might mean that there is no test named "+main.TEST
         main.exit()
 
@@ -773,12 +791,12 @@
 def verifyParams():
     try :
         main.params = main.params['PARAMS']
-    except(KeyError):
+    except KeyError:
         print "Error with the params file: Either the file not specified or the format is not correct"
         main.exit()
     try :
         main.topology = main.topology['TOPOLOGY']
-    except(KeyError):
+    except KeyError:
         print "Error with the Topology file: Either the file not specified or the format is not correct"
         main.exit()
 
diff --git a/TestON/core/testparser.py b/TestON/core/testparser.py
index 24b1ca2..aab4388 100644
--- a/TestON/core/testparser.py
+++ b/TestON/core/testparser.py
@@ -46,7 +46,7 @@
                 try :
                     while not re.match('^\s*(\'\'\')|^\s*(\"\"\")',testFileList[index],0) :
                         index = index + 1
-                except IndexError,e:
+                except IndexError:
                     print ''
 
             # skip empty lines and single line comments
@@ -58,11 +58,9 @@
         index = 0
         statementsList = self.statementsList
         while index < len(statementsList):
-            #print statementsList[index]
             m= re.match('def\s+CASE(\d+)',statementsList[index],0)
             self.caseBlock = []
             if m:
-                #print m.group(1)
                 index = index + 1
                 try :
                     while not re.match('\s*def\s+CASE(\d+)',statementsList[index],0) :
@@ -72,11 +70,9 @@
                         else :
                             break
                     index = index - 1
-                except IndexError,e:
-                    #print 'IndexError'
+                except IndexError:
                     print ''
                 self.caseCode [str(m.group(1))] = self.caseBlock
-                #print "Case CODE "+self.caseCode [str(m.group(1))]
             index = index + 1
         return self.caseCode
 
@@ -108,8 +104,7 @@
                         else :
                             break
                     index = index - 1
-                except IndexError,e:
-                    #print 'IndexError'
+                except IndexError:
                     print ''
                 stepCode[step] = stepBlock
                 step = step + 1
diff --git a/TestON/core/utilities.py b/TestON/core/utilities.py
index 02ade72..8cd81e5 100644
--- a/TestON/core/utilities.py
+++ b/TestON/core/utilities.py
@@ -121,8 +121,9 @@
         try :
             opcode = operators[str(arguments["OPERATOR"])][valuetype] if arguments["OPERATOR"] == 'equals' else operators[str(arguments["OPERATOR"])]
 
-        except KeyError:
+        except KeyError as e:
             print "Key Error in assertion"
+            print e
             return main.FALSE
 
         if opcode == '=~':
@@ -179,8 +180,9 @@
         if not isinstance(msg,str):
             try:
                 eval(str(msg))
-            except SyntaxError:
-                print "functin definition is not write"
+            except SyntaxError as e:
+                print "function definition is not right"
+                print e
 
         main.last_result = result
         return result
@@ -191,7 +193,6 @@
         '''
         newArgs = {}
         for key,value in kwargs.iteritems():
-            #currentKey =  str.upper(key)
             if isinstance(args,list) and str.upper(key) in args:
                 for each in args:
                     if each==str.upper(key):
@@ -199,8 +200,6 @@
                     elif each != str.upper(key) and (newArgs.has_key(str(each)) == False ):
                         newArgs[str(each)] = None
 
-
-
         return newArgs
 
     def send_mail(self):
@@ -211,7 +210,7 @@
                 sub = "Result summary of \""+main.TEST+"\" run on component \""+main.test_target+"\" Version \""+vars(main)[main.test_target].get_version()+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
             else :
                 sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
-        except KeyError,AttributeError:
+        except ( KeyError, AttributeError ):
             sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
 
         msg['Subject'] = sub
@@ -250,7 +249,7 @@
             try :
                 parsedInfo = ConfigObj(self.fileName)
                 return parsedInfo
-            except Exception:
+            except StandardError:
                 print "There is no such file to parse "+fileName
         else:
             return 0
diff --git a/TestON/core/xmldict.py b/TestON/core/xmldict.py
index 2cc47da..8d1dcf4 100644
--- a/TestON/core/xmldict.py
+++ b/TestON/core/xmldict.py
@@ -37,7 +37,7 @@
         root = ElementTree.XML(root_or_str)
     try :
         return {root.tag: _from_xml(root, strict)}
-    except Exception:
+    except StandardError:
         return None
 
 def dict_to_xml(dict_xml):
diff --git a/TestON/core/xmlparser.py b/TestON/core/xmlparser.py
index e2cfb1d..f12f69c 100644
--- a/TestON/core/xmlparser.py
+++ b/TestON/core/xmlparser.py
@@ -39,7 +39,7 @@
             try :
                 parsedInfo = xmldict.xml_to_dict(xml)
                 return parsedInfo
-            except Exception as e:
+            except StandardError as e:
                 print "Error parsing file " + fileName + ": " + e.message
         else :
             print "File name is not correct"