Source code for runtimepy.net.arbiter.result

"""
A module implementing a simple, application-result interface.
"""

# built-in
from enum import StrEnum
import logging
from typing import NamedTuple, Optional

# third-party
from vcorelib.logging import LoggerType
from vcorelib.math import nano_str


[docs] class ResultState(StrEnum): """Possible outcomes of an application method.""" PASS = "pass" FAIL = "fail" NOT_RUN = "not run" EXCEPTION = "exception" def __bool__(self) -> bool: """Convert an enum instance to boolean.""" return self is ResultState.PASS @property def log_level(self) -> int: """Get a log level for this result state.""" if self is ResultState.NOT_RUN: return logging.WARNING return logging.INFO if bool(self) else logging.ERROR
[docs] @staticmethod def from_int(data: int) -> "ResultState": """Create result state from an integer.""" return ResultState.PASS if data == 0 else ResultState.FAIL
[docs] class AppResult(NamedTuple): """A container for application-result information.""" method: str state: ResultState = ResultState.NOT_RUN code: Optional[int] = None exception: Optional[Exception] = None duration_ns: Optional[int] = None
[docs] def log( self, overall_idx: int, stage_idx: int, logger: LoggerType ) -> None: """Log information about this result.""" fmt = "%d.%d %s: %s" fmt_args = [overall_idx, stage_idx, self.method, str(self.state)] if self.code is not None: fmt += " (%d)" fmt_args.append(self.code) if self.duration_ns: fmt += " %ss." fmt_args.append(nano_str(self.duration_ns, is_time=True)) if self.exception is not None: logger.exception(fmt + " -", *fmt_args, exc_info=self.exception) else: logger.log(self.state.log_level, fmt, *fmt_args)
# App methods can run in parallel, group them as a stage. StageResult = list[AppResult]
[docs] def log_stage( overall_idx: int, result: StageResult, logger: LoggerType = None ) -> bool: """Log the results of a stage.""" success = True for idx, instance in enumerate(result): if logger is not None: instance.log(overall_idx, idx, logger) success &= bool(instance.state) return success
# The overall application's result is a collection of stage results. OverallResult = list[StageResult]
[docs] def results(result: OverallResult, logger: LoggerType = None) -> bool: """Log overall results.""" if logger is not None: logger.info("========================================") success = True for idx, instance in enumerate(result): success &= log_stage(idx, instance, logger=logger) if logger is not None: logger.info("========================================") return success