From 0eb66c07cb6a5166b23756b1a4d2e83b9c819f2e Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:15:34 -0400 Subject: [PATCH 1/6] Python 3 extracts tracebacks differently from Python 2 --- seleniumbase/core/log_helper.py | 24 +++++++++++++++++++----- seleniumbase/fixtures/base_case.py | 13 +++++++++---- seleniumbase/plugins/base_plugin.py | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/seleniumbase/core/log_helper.py b/seleniumbase/core/log_helper.py index b3c8a537690..e82b7f39579 100755 --- a/seleniumbase/core/log_helper.py +++ b/seleniumbase/core/log_helper.py @@ -10,7 +10,7 @@ def log_screenshot(test_logpath, driver): driver.get_screenshot_as_file(screenshot_path) -def log_test_failure_data(test_logpath, driver, browser): +def log_test_failure_data(test, test_logpath, driver, browser): basic_info_name = settings.BASIC_INFO_NAME basic_file_path = "%s/%s" % (test_logpath, basic_info_name) log_file = codecs.open(basic_file_path, "w+", "utf-8") @@ -18,10 +18,24 @@ def log_test_failure_data(test_logpath, driver, browser): data_to_save = [] data_to_save.append("Last_Page: %s" % last_page) data_to_save.append("Browser: %s " % browser) - data_to_save.append("Traceback: " + ''.join( - traceback.format_exception(sys.exc_info()[0], - sys.exc_info()[1], - sys.exc_info()[2]))) + if sys.version.startswith('3') and hasattr(test, '_outcome'): + if test._outcome.errors: + try: + exc_message = test._outcome.errors[0][1][1].msg + traceback_address = test._outcome.errors[0][1][2] + traceback_list = traceback.format_list( + traceback.extract_tb(traceback_address)[1:]) + traceback_message = ''.join(traceback_list).strip() + except: + exc_message = "(Unknown Exception)" + traceback_message = "(Unknown Traceback)" + data_to_save.append("Traceback: " + traceback_message) + data_to_save.append("Exception: " + exc_message) + else: + data_to_save.append("Traceback: " + ''.join( + traceback.format_exception(sys.exc_info()[0], + sys.exc_info()[1], + sys.exc_info()[2]))) log_file.writelines("\r\n".join(data_to_save)) log_file.close() diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index b0c5c0ca1ea..3584ba486fc 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1405,12 +1405,18 @@ def tearDown(self): You'll need to add the following line to the subclass's tearDown(): super(SubClassOfBaseCase, self).tearDown() """ + is_exception = False + if sys.version.startswith('3') and hasattr(self, '_outcome'): + if self._outcome.errors: + is_exception = True + else: + is_exception = sys.exc_info()[1] is not None if self.page_check_failures: print( "\nWhen using self.check_assert_***() methods in your tests, " "remember to call self.process_checks() afterwards. " "Now calling in tearDown()...\nFailures Detected:") - if not sys.exc_info()[1]: + if not is_exception: self.process_checks() else: self.process_checks(print_only=True) @@ -1428,7 +1434,6 @@ def tearDown(self): self._testMethodName) if self.with_selenium: # Save a screenshot if logging is on when an exception occurs - is_exception = sys.exc_info()[1] is not None if is_exception: self._add_pytest_html_extra() if self.with_testing_base and is_exception: @@ -1441,7 +1446,7 @@ def tearDown(self): # Log everything if nothing specified (if testing_base) log_helper.log_screenshot(test_logpath, self.driver) log_helper.log_test_failure_data( - test_logpath, self.driver, self.browser) + self, test_logpath, self.driver, self.browser) log_helper.log_page_source(test_logpath, self.driver) else: if self.with_screen_shots: @@ -1449,7 +1454,7 @@ def tearDown(self): test_logpath, self.driver) if self.with_basic_test_info: log_helper.log_test_failure_data( - test_logpath, self.driver, self.browser) + self, test_logpath, self.driver, self.browser) if self.with_page_source: log_helper.log_page_source( test_logpath, self.driver) diff --git a/seleniumbase/plugins/base_plugin.py b/seleniumbase/plugins/base_plugin.py index 53b12bdcbf3..515231fa574 100755 --- a/seleniumbase/plugins/base_plugin.py +++ b/seleniumbase/plugins/base_plugin.py @@ -123,7 +123,7 @@ def __log_all_options_if_none_specified(self, test): test_logpath = self.options.log_path + "/" + test.id() log_helper.log_screenshot(test_logpath, test.driver) log_helper.log_test_failure_data( - test_logpath, test.driver, test.browser) + test, test_logpath, test.driver, test.browser) log_helper.log_page_source(test_logpath, test.driver) def addSuccess(self, test, capt): From bd22816614980abedc47a64061ed7391c378a4f0 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:19:13 -0400 Subject: [PATCH 2/6] Simplify if statement based on past code --- seleniumbase/fixtures/base_case.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 3584ba486fc..9672066d18e 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1471,14 +1471,14 @@ def tearDown(self): self.display.stop() self.display = None if self.with_db_reporting: - if sys.exc_info()[1] is not None: + if is_exception: self.__insert_test_result(constants.State.ERROR, True) else: self.__insert_test_result(constants.State.PASS, False) runtime = int(time.time() * 1000) - self.execution_start_time self.testcase_manager.update_execution_data( self.execution_guid, runtime) - if self.with_s3_logging and (sys.exc_info()[1] is not None): + if self.with_s3_logging and is_exception: """ After each testcase, upload logs to the S3 bucket. """ s3_bucket = S3LoggingBucket() guid = str(uuid.uuid4().hex) From 6fa9d2710fc00c4d444448cca589b4f1fddf2aa3 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:20:17 -0400 Subject: [PATCH 3/6] Make the code Python 3 compatible --- seleniumbase/fixtures/base_case.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 9672066d18e..d21ff43edf7 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1126,13 +1126,23 @@ def _get_exception_message(self): """ This method extracts the message from an exception if there was an exception that occurred during the test, assuming that the exception was in a try/except block and not thrown. """ - exception_info = sys.exc_info()[1] - if hasattr(exception_info, 'msg'): - exc_message = exception_info.msg - elif hasattr(exception_info, 'message'): - exc_message = exception_info.message + if sys.version.startswith('3') and hasattr(self, '_outcome'): + exception_info = self._outcome.errors + if exception_info: + try: + exc_message = exception_info[0][1][1] + except: + exc_message = "(Unknown Exception)" + else: + exc_message = "(Unknown Exception)" else: - exc_message = '(Unknown Exception)' + exception_info = sys.exc_info()[1] + if hasattr(exception_info, 'msg'): + exc_message = exception_info.msg + elif hasattr(exception_info, 'message'): + exc_message = exception_info.message + else: + exc_message = '(Unknown Exception)' return exc_message def _package_check(self): From b7d2e43fb0dd510ccaa844537d813e576d9ae75a Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:25:52 -0400 Subject: [PATCH 4/6] Renaming a variable for readability --- seleniumbase/fixtures/base_case.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index d21ff43edf7..18366f48640 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1415,18 +1415,18 @@ def tearDown(self): You'll need to add the following line to the subclass's tearDown(): super(SubClassOfBaseCase, self).tearDown() """ - is_exception = False + has_exception = False if sys.version.startswith('3') and hasattr(self, '_outcome'): if self._outcome.errors: - is_exception = True + has_exception = True else: - is_exception = sys.exc_info()[1] is not None + has_exception = sys.exc_info()[1] is not None if self.page_check_failures: print( "\nWhen using self.check_assert_***() methods in your tests, " "remember to call self.process_checks() afterwards. " "Now calling in tearDown()...\nFailures Detected:") - if not is_exception: + if not has_exception: self.process_checks() else: self.process_checks(print_only=True) @@ -1444,9 +1444,9 @@ def tearDown(self): self._testMethodName) if self.with_selenium: # Save a screenshot if logging is on when an exception occurs - if is_exception: + if has_exception: self._add_pytest_html_extra() - if self.with_testing_base and is_exception: + if self.with_testing_base and has_exception: test_logpath = self.log_path + "/" + test_id if not os.path.exists(test_logpath): os.makedirs(test_logpath) @@ -1481,14 +1481,14 @@ def tearDown(self): self.display.stop() self.display = None if self.with_db_reporting: - if is_exception: + if has_exception: self.__insert_test_result(constants.State.ERROR, True) else: self.__insert_test_result(constants.State.PASS, False) runtime = int(time.time() * 1000) - self.execution_start_time self.testcase_manager.update_execution_data( self.execution_guid, runtime) - if self.with_s3_logging and is_exception: + if self.with_s3_logging and has_exception: """ After each testcase, upload logs to the S3 bucket. """ s3_bucket = S3LoggingBucket() guid = str(uuid.uuid4().hex) From 67ab233c883de08b89ab6a452ac1984740957456 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:27:11 -0400 Subject: [PATCH 5/6] Make the GUI Test Runner compatible with Python 3 --- examples/gui_test_runner.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/gui_test_runner.py b/examples/gui_test_runner.py index 4e2e13bfc7a..301ba09e664 100755 --- a/examples/gui_test_runner.py +++ b/examples/gui_test_runner.py @@ -3,7 +3,12 @@ Run by Typing: "python gui_test_runner.py" ''' -from Tkinter import Tk, Frame, Button, Label +try: + # Python 2 + from Tkinter import Tk, Frame, Button, Label +except: + # Python 3 + from tkinter import Tk, Frame, Button, Label import os From 2690e305a15aef28afd4f857b26c8074bfd768f7 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 24 Jul 2017 22:28:52 -0400 Subject: [PATCH 6/6] Version 1.4.4 --- server_setup.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_setup.py b/server_setup.py index 7a6dc66b606..a3ec190bfec 100755 --- a/server_setup.py +++ b/server_setup.py @@ -8,7 +8,7 @@ setup( name='seleniumbase', - version='1.4.3', + version='1.4.4', description='Test Automation Framework - http://seleniumbase.com', long_description='Automation Framework for Simple & Reliable Web Testing', platforms='Mac * Windows * Linux * Docker', diff --git a/setup.py b/setup.py index 95591c75498..0f808284665 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name='seleniumbase', - version='1.4.3', + version='1.4.4', description='Test Automation Framework - http://seleniumbase.com', long_description='Automation Framework for Simple & Reliable Web Testing', platforms='Mac * Windows * Linux * Docker',