def _execute_impl(code: str, suite: TestSuite, defaults: TestDefaults = TestDefaults(), stdout=None, stderr=None, listeners=[], drivers=[], outputdir=None, interactive_keywords=True, logger=None): # This will help raise runtime exceptions traceback = [] LOGGER.register_error_listener( lambda: traceback.extend(get_error_details())) # Clear selector completion highlights for driver in yield_current_connection( drivers, SeleniumConnectionsListener.NAMES + ["jupyter"]): try: clear_selector_highlights(driver) except BrokenOpenConnection: close_current_connection(drivers, driver) if logger is not None: logger.debug("Compiling code: \n%s", code) # Copy keywords/variables/libraries in case of failure imports = get_items_copy(suite.resource.imports) variables = get_items_copy(suite.resource.variables) keywords = get_items_copy(suite.resource.keywords) # Compile AST model = get_model( StringIO(code), data_only=False, curdir=os.getcwd().replace("\\", "\\\\"), ) ErrorReporter(code).visit(model) SettingsBuilder(suite, defaults).visit(model) SuiteBuilder(suite, defaults).visit(model) # Strip variables/keyword duplicates strip_duplicate_items(suite.resource.variables) strip_duplicate_items(suite.resource.keywords) for listener in listeners: # Notify suite variables to the listener if isinstance(listener, GlobalVarsListener): listener.suite_vars = [ var.name for var in suite.resource.variables ] new_imports = [ item for item in get_items_copy(suite.resource.imports) if item not in imports ] for new_import in new_imports: new_import.source = suite.source new_variables = [ item for item in get_items_copy(suite.resource.variables) if item not in variables ] for new_variable in new_variables: new_variable.source = suite.source # If there is no test, allow the user to interact with defined keywords by providing widgets new_keywords = [ item for item in get_items_copy(suite.resource.keywords) if item not in keywords ] for new_keyword in new_keywords: new_keyword.actual_source = suite.source if not suite.tests and new_keywords and interactive_keywords: return None, [ get_interactive_keyword( suite, keyword, # stdout=stdout, stderr=stderr, listeners=[ listener for listener in listeners if not isinstance(listener, StatusEventListener) ], drivers=drivers, logger=logger) for keyword in new_keywords ] # Set default streams # By default stdout is no-op if stdout is None: stdout = NoOpStream() if logger is not None: logger.debug("Executing code") # Execute suite result = suite.run(outputdir=outputdir, stdout=stdout, stderr=stderr, listener=listeners) if len(traceback) != 0: # Reset keywords/variables/libraries set_items(suite.resource.imports, imports) set_items(suite.resource.variables, variables) set_items(suite.resource.keywords, keywords) clean_items(suite.tests) error_msg = '\n'.join(traceback) if logger is not None: logger.debug("Execution error: %s", error_msg) raise TestSuiteError(error_msg) for listener in listeners: if isinstance(listener, RobotKeywordsIndexerListener): listener.import_from_suite_data(suite) # Detect RPA suite.rpa = get_rpa_mode(model) report = None if suite.tests: report = generate_report(suite, outputdir) # Remove tests run so far, # this is needed so that we don't run them again in the next execution clean_items(suite.tests) return result, report