Skip to content

climate_ref.executor.result_handling #

Execute diagnostics in different environments

We support running diagnostics in different environments, such as locally, in a separate process, or in a container. These environments are represented by climate_ref.executor.Executor classes.

The simplest executor is the LocalExecutor, which runs the diagnostic in the same process. This is useful for local testing and debugging.

handle_execution_result(config, database, execution, result) #

Handle the result of a diagnostic execution

This will update the diagnostic execution result with the output of the diagnostic execution. The output will be copied from the scratch directory to the executions directory.

Parameters:

Name Type Description Default
config Config

The configuration to use

required
database Database

The active database session to use

required
execution Execution

The diagnostic execution result DB object to update

required
result ExecutionResult

The result of the diagnostic execution, either successful or failed

required
Source code in packages/climate-ref/src/climate_ref/executor/result_handling.py
def handle_execution_result(
    config: "Config",
    database: Database,
    execution: Execution,
    result: "ExecutionResult",
) -> None:
    """
    Handle the result of a diagnostic execution

    This will update the diagnostic execution result with the output of the diagnostic execution.
    The output will be copied from the scratch directory to the executions directory.

    Parameters
    ----------
    config
        The configuration to use
    database
        The active database session to use
    execution
        The diagnostic execution result DB object to update
    result
        The result of the diagnostic execution, either successful or failed
    """
    # Always copy log data to the results directory
    try:
        _copy_file_to_results(
            config.paths.scratch,
            config.paths.results,
            execution.output_fragment,
            EXECUTION_LOG_FILENAME,
        )
    except FileNotFoundError:
        logger.error(
            f"Could not find log file {EXECUTION_LOG_FILENAME} in scratch directory: {config.paths.scratch}"
        )
        execution.mark_failed()
        return

    if not result.successful or result.metric_bundle_filename is None:
        logger.error(f"{execution} failed")
        execution.mark_failed()
        return

    logger.info(f"{execution} successful")

    _copy_file_to_results(
        config.paths.scratch,
        config.paths.results,
        execution.output_fragment,
        result.metric_bundle_filename,
    )

    if result.output_bundle_filename:
        _copy_file_to_results(
            config.paths.scratch,
            config.paths.results,
            execution.output_fragment,
            result.output_bundle_filename,
        )
        _handle_output_bundle(
            config,
            database,
            execution,
            result.to_output_path(result.output_bundle_filename),
        )

    cv = CV.load_from_file(config.paths.dimensions_cv)

    if result.series_filename:
        # Process the series values if they are present
        # This will ingest the series values into the database
        _process_execution_series(config=config, database=database, result=result, execution=execution, cv=cv)

    # Process the scalar values
    # This will ingest the scalar values into the database
    _process_execution_scalar(database=database, result=result, execution=execution, cv=cv)

    # TODO: This should check if the result is the most recent for the execution,
    # if so then update the dirty fields
    # i.e. if there are outstanding executions don't make as clean
    execution.execution_group.dirty = False

    # Finally, mark the execution as successful
    execution.mark_successful(result.as_relative_path(result.metric_bundle_filename))