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