Source code for phenotypic.tune._search_space._targets

"""Typed parameter-reference targets for search-space knobs.

A ``Knob`` addresses a pipeline parameter by a structured ``KnobTarget`` — one
of ``Param`` (a flat field on a top-level op), ``Presence`` (an op on/off
toggle), or ``Nested`` (a depth-1 nested-op leaf). Each renders the canonical
``.key`` string the engine already consumes (``build_pipeline`` is untouched),
so targets are a typed authoring/serialization layer over the existing keys.

The public surface lives in the ``phenotypic.tune.targets`` subpackage; these
classes are accessed as ``targets.Param(...)``. This module imports neither
``_space`` nor ``_infer`` (it sits below both, so there is no import cycle).
"""
from __future__ import annotations

from typing import Annotated, Literal, Optional, Union

from pydantic import BaseModel, ConfigDict, Field

#: The presence-toggle dunder segment (an op on/off flag in the key grammar).
_ENABLED = "__enabled__"


class _TargetBase(BaseModel):
    """Shared config for every target value-model (frozen, no extra fields)."""

    model_config = ConfigDict(frozen=True, extra="forbid")


[docs] class Param(_TargetBase): """A flat scalar field on the top-level op at ``op`` — key ``"<op>.<field>"``. Args: op: The op's position index in the pipeline. field: The scalar field name on that op. op_class: Optional class-name cross-check — when set, the ``TuningSpec`` validator asserts the op at ``op`` is this class (posture C: always populated by discovery / inference). """ kind: Literal["param"] = "param" op: int field: str op_class: Optional[str] = None @property def key(self) -> str: """The canonical ``"<op>.<field>"`` key string.""" return f"{self.op}.{self.field}"
[docs] class Presence(_TargetBase): """An op on/off toggle — key ``"<op>[.<Class>].__enabled__"``. Args: op: The op's position index. op_class: The op's class name; when set, renders the classed key form and is cross-checked by the ``TuningSpec`` validator. """ kind: Literal["presence"] = "presence" op: int op_class: Optional[str] = None @property def key(self) -> str: """The canonical presence key (classed when ``op_class`` is set).""" if self.op_class: return f"{self.op}.{self.op_class}.{_ENABLED}" return f"{self.op}.{_ENABLED}"
[docs] class Nested(_TargetBase): """A depth-1 nested-op leaf — key ``"<op>.<field>[<index>].<leaf>"``. Args: op: The parent (top-level) op's position index. field: The parent's operation-valued list field. index: The slot in that list. leaf: The scalar field on the nested op. op_class: Optional class-name cross-check of the *parent* op at ``op``. """ kind: Literal["nested"] = "nested" op: int field: str index: int leaf: str op_class: Optional[str] = None @property def key(self) -> str: """The canonical ``"<op>.<field>[<index>].<leaf>"`` key string.""" return f"{self.op}.{self.field}[{self.index}].{self.leaf}"
#: The discriminated union a ``Knob.target`` holds. KnobTarget = Annotated[Union[Param, Presence, Nested], Field(discriminator="kind")]
[docs] def parse_key(key: str) -> "KnobTarget": """Parse a canonical key string into a structured ``KnobTarget``. The pipeline-free inverse of ``KnobTarget.key`` — a purely *structural* parse; op-range / field-existence checks happen later against the pipeline in the ``TuningSpec`` validator. ``op_class`` is recovered only from the classed presence form (``"0.GaussianBlur.__enabled__"``); flat and nested keys do not encode a class, so their ``op_class`` is ``None``. Args: key: A canonical key, e.g. ``"0.sigma"`` / ``"0.GaussianBlur.__enabled__"`` / ``"0.refiners[1].min_size"``. Returns: The matching ``Param`` / ``Presence`` / ``Nested``. Raises: ValueError: When the first segment is not an int position, or the key matches none of the three grammars. """ parts = key.split(".") try: op = int(parts[0]) except ValueError as exc: raise ValueError(f"key {key!r} does not start with an int position") from exc # Nested: a "<field>[<index>]" segment selects the nested grammar. for i, segment in enumerate(parts[1:], start=1): if "[" in segment and segment.endswith("]"): field, _, idx = segment[:-1].partition("[") leaf = ".".join(parts[i + 1:]) if not field or not idx.isdigit() or not leaf: raise ValueError(f"key {key!r} has a malformed nested segment") if "[" in leaf: # Mirror build_pipeline's canonical depth-1 cap: the leaf must # not carry a further "[i]" segment (e.g. "0.f[1].g[2].h"). raise ValueError( f"key {key!r} exceeds the nesting depth cap of 1 " "(the leaf must not carry a further '[i]' segment)" ) return Nested(op=op, field=field, index=int(idx), leaf=leaf) # Presence: trailing "__enabled__" (classed three-part or bare two-part). if parts[-1] == _ENABLED: if len(parts) == 3: if not parts[1]: # "0..__enabled__" — an empty class segment would render the bare # key, a non-round-tripping parse; reject it like build_pipeline. raise ValueError(f"presence key {key!r} has an empty class segment") return Presence(op=op, op_class=parts[1]) if len(parts) == 2: return Presence(op=op) raise ValueError(f"presence key {key!r} is malformed") # Flat: "<op>.<field>". if len(parts) == 2: return Param(op=op, field=parts[1]) raise ValueError(f"key {key!r} is not a recognised flat/presence/nested key")
def with_op_class(target: "KnobTarget", ordered_ops: list) -> "KnobTarget": """Return ``target`` with ``op_class`` filled from the op at ``target.op``. Posture C: discovery / inference always stamp ``op_class`` so every programmatic target is wrong-op cross-checked. An out-of-range ``op`` is returned untouched (the ``TuningSpec`` validator reports the range error). Args: target: The target to enrich. ordered_ops: The pipeline's ops in position order. Returns: A copy with ``op_class = type(ordered_ops[target.op]).__name__``, or the unchanged ``target`` when ``op`` is out of range. """ if not 0 <= target.op < len(ordered_ops): return target return target.model_copy( update={"op_class": type(ordered_ops[target.op]).__name__} )