# Buggy code
def start(
    self,
    config,
    instance,
    cutoff=None,
    memory_limit=None,
    seed=12345,
    instance_specific="0",
):
    """
    wrapper function for ExecuteTARun.run() to check configuration budget before the runs
    and to update stats after run

    Parameters
    ----------
        config : dictionary
            dictionary param -> value
        instance : string
            problem instance
        cutoff : double
            runtime cutoff
        seed : int
            random seed
        instance_specific: str
            instance specific information (e.g., domain file or solution)

    Returns
    -------
        status: enum of StatusType (int)
            {SUCCESS, TIMEOUT, CRASHED, ABORT}
        cost: float
            cost/regret/quality (float) (None, if not returned by TA)
        runtime: float
            runtime (None if not returned by TA)
        additional_info: dict
            all further additional run information
    """

    if self.stats.is_budget_exhausted():
        self.logger.debug(
            "Skip target algorithm run due to exhausted configuration budget"
        )
        return StatusType.ABORT, np.nan, 0, {"misc": "exhausted bugdet -- ABORT"}

    if cutoff is not None:
        cutoff = int(math.ceil(cutoff))
    if memory_limit is not None:
        memory_limit = int(math.ceil(memory_limit))

    additional_arguments = {}

    if self._supports_memory_limit is True:
        additional_arguments["memory_limit"] = memory_limit
    else:
        raise ValueError(
            "Target algorithm executor %s does not support "
            "restricting the memory usage." % self.__class__.__name__
        )

    status, cost, runtime, additional_info = self.run(
        config=config,
        instance=instance,
        cutoff=cutoff,
        seed=seed,
        instance_specific=instance_specific,
        **additional_arguments,
    )
    # update SMAC stats
    self.stats.ta_runs += 1
    self.stats.ta_time_used += float(runtime)

    self.logger.debug(
        "Return: Status: %d, cost: %f, time. %f, additional: %s"
        % (status, cost, runtime, str(additional_info))
    )

    return status, cost, runtime, additional_info


# Traceback (AttributeError)
Traceback (most recent call last):
File "/home/lindauer/git/SMAC3/scripts/smac", line 20, in <module>
smac.main_cli()
File "/home/lindauer/git/SMAC3/smac/smac_cli.py", line 47, in main_cli
smbo.run(max_iters=args_.max_iterations)
File "/home/lindauer/git/SMAC3/smac/smbo/smbo.py", line 282, in run
self.incumbent = self.run_initial_design()
File "/home/lindauer/git/SMAC3/smac/smbo/smbo.py", line 239, in run_initial_design
instance_specific=self.scenario.instance_specific.get(rand_inst, "0"))
File "/home/lindauer/git/SMAC3/smac/tae/execute_ta_run.py", line 103, in start
if self._supports_memory_limit is True:
AttributeError: 'ExecuteTARunOld' object has no attribute '_supports_memory_limit'

# Fixed code
def start(
    self,
    config,
    instance,
    cutoff=None,
    memory_limit=None,
    seed=12345,
    instance_specific="0",
):
    """
    wrapper function for ExecuteTARun.run() to check configuration budget before the runs
    and to update stats after run

    Parameters
    ----------
        config : dictionary
            dictionary param -> value
        instance : string
            problem instance
        cutoff : double
            runtime cutoff
        seed : int
            random seed
        instance_specific: str
            instance specific information (e.g., domain file or solution)

    Returns
    -------
        status: enum of StatusType (int)
            {SUCCESS, TIMEOUT, CRASHED, ABORT}
        cost: float
            cost/regret/quality (float) (None, if not returned by TA)
        runtime: float
            runtime (None if not returned by TA)
        additional_info: dict
            all further additional run information
    """

    if self.stats.is_budget_exhausted():
        self.logger.debug(
            "Skip target algorithm run due to exhausted configuration budget"
        )
        return StatusType.ABORT, np.nan, 0, {"misc": "exhausted bugdet -- ABORT"}

    if cutoff is not None:
        cutoff = int(math.ceil(cutoff))
    if memory_limit is not None:
        memory_limit = int(math.ceil(memory_limit))

    additional_arguments = {}

    if self._supports_memory_limit is True:
        additional_arguments["memory_limit"] = memory_limit
    elif self._supports_memory_limit is False and memory_limit is not None:
        raise ValueError(
            "Target algorithm executor %s does not support "
            "restricting the memory usage." % self.__class__.__name__
        )

    status, cost, runtime, additional_info = self.run(
        config=config,
        instance=instance,
        cutoff=cutoff,
        seed=seed,
        instance_specific=instance_specific,
        **additional_arguments,
    )
    # update SMAC stats
    self.stats.ta_runs += 1
    self.stats.ta_time_used += float(runtime)

    if self.run_obj == "runtime":
        if status != StatusType.SUCCESS:
            cost = cutoff * self.par_factor
        else:
            cost = runtime

    self.logger.debug(
        "Return: Status: %d, cost: %f, time. %f, additional: %s"
        % (status, cost, runtime, str(additional_info))
    )

    return status, cost, runtime, additional_info