Source code for compass.pipeline.targets

"""Stage-independent minimum targets for persisted shard records"""

import json
import math

from compass.exceptions import COMPASSValueError


[docs] def normalize_targets(targets): """Validate and copy a mapping of metric names to minimum values Parameters ---------- targets : dict or None Metric names and finite numeric lower bounds. ``None`` produces an empty mapping. Returns ------- dict Validated targets, independent of the input mapping. """ if targets is None: return {} if not isinstance(targets, dict): msg = "Targets must be a metric-to-minimum mapping" raise COMPASSValueError(msg) normalized = {} for metric, minimum in targets.items(): if not isinstance(metric, str) or not metric.strip(): msg = "Target metric names must be nonempty" raise COMPASSValueError(msg) if not _is_number(minimum): msg = f"Target '{metric}' requires a finite numeric minimum" raise COMPASSValueError(msg) normalized[metric.strip()] = minimum return normalized
[docs] def parse_target_options(options): """Parse repeated CLI targets, retaining the strictest minimum Parameters ---------- options : iterable of str Expressions using ``METRIC=MINIMUM`` syntax. Returns ------- dict Parsed targets. Repeated metrics use their largest minimum. """ targets = {} for option in options: metric, separator, raw_minimum = option.partition("=") if not separator: msg = f"Invalid target '{option}'; use METRIC=MINIMUM" raise COMPASSValueError(msg) try: minimum = json.loads(raw_minimum) except (ValueError, TypeError) as exc: msg = f"Invalid minimum in target '{option}'" raise COMPASSValueError(msg) from exc for name, value in normalize_targets({metric: minimum}).items(): targets[name] = max(targets.get(name, value), value) return targets
[docs] def evaluate_targets(record, targets, metrics): """Return unmet minimums using stage-provided metric accessors Parameters ---------- record : dict One persisted shard record. targets : dict Validated metric names and numeric minimums. metrics : dict Metric names mapped to callables accepting a record. Accessors return a finite number or ``None`` for unavailable values. Returns ------- list of dict Failures containing ``metric``, ``actual``, and ``minimum``. An empty list means every supplied target passed. """ failures = [] for metric, minimum in normalize_targets(targets).items(): if metric not in metrics: msg = f"Unknown shard target '{metric}'" raise COMPASSValueError(msg) actual = metrics[metric](record) if actual is not None and not _is_number(actual): msg = f"Shard metric '{metric}' must be a finite number" raise COMPASSValueError(msg) if actual is None or actual < minimum: failures.append( {"metric": metric, "actual": actual, "minimum": minimum} ) return failures
[docs] def shard_failures(record, targets, metrics, key="results"): """Evaluate default nonempty results and explicit shard minimums Parameters ---------- record : dict or None One search shard, or ``None`` when its file is missing. targets : dict Validated search minimum targets. metrics : dict Search metric accessors returned by target validation. key : str, default="results" The key in the record to check for nonempty results. By default, ``"results"``. Returns ------- list of dict Unmet default and explicit requirements for this shard. """ record = record or {} failures = [] if not record.get(key): failures.append({"metric": key, "actual": 0, "minimum": 1}) return failures + evaluate_targets(record, targets, metrics)
def _is_number(value): """Check for a finite numeric value without accepting booleans""" return ( isinstance(value, (int, float)) and not isinstance(value, bool) and (not isinstance(value, float) or math.isfinite(value)) )