Skip to content

README

liblaf.cherries.core.assets

Modules:

Classes:

  • AssetPluginProtocol –

    Hook surface for plugins that receive artifact paths.

  • AssetsManager –

    Stage independent inputs and declared outputs inside an active run.

  • Bundle –

    Base class for artifact companion-file discovery.

  • BundleItem –

    Related file discovered for a logged artifact.

  • BundleRegistry –

    Registry that expands logged artifacts through matching bundles.

Attributes:

bundles module-attribute

AssetPluginProtocol

Bases: Protocol


              flowchart TD
              liblaf.cherries.core.assets.AssetPluginProtocol[AssetPluginProtocol]

              

              click liblaf.cherries.core.assets.AssetPluginProtocol href "" "liblaf.cherries.core.assets.AssetPluginProtocol"
            

Hook surface for plugins that receive artifact paths.

Methods:

  • log_asset –

    Record an existing artifact path.

log_asset

log_asset(
    path: Path,
    *,
    metadata: Mapping[str, Any] | None = None,
    report: bool = True,
) -> None

Record an existing artifact path.

Parameters:

  • path (Path) –

    Existing file or directory to record.

  • metadata (Mapping[str, Any] | None, default: None ) –

    Optional artifact metadata, usually including type.

  • report (bool, default: True ) –

    Whether the path is the primary user-facing artifact. Companion files are logged with report=False.

Source code in src/liblaf/cherries/core/assets/_protocol.py
def log_asset(
    self,
    path: Path,
    *,
    metadata: Mapping[str, Any] | None = None,
    report: bool = True,
) -> None:
    """Record an existing artifact path.

    Args:
        path: Existing file or directory to record.
        metadata: Optional artifact metadata, usually including `type`.
        report: Whether the path is the primary user-facing artifact.
            Companion files are logged with `report=False`.
    """
    ...

AssetsManager

Stage independent inputs and declared outputs inside an active run.

Parameters:

  • working_dir (Path) –
  • plugins (AssetPluginProtocol) –
  • bundles (BundleRegistry, default: BundleRegistry(registry=[BundleLandmarks(suffixes={'.obj', '.vtp', '.ply', '.stl', '.vtr', '.vtkhdf', '.vts', '.vtu', '.vti'}), BundleSeries()]) ) –
  • summary (AssetsSummary, default: <dynamic> ) –

    Paths successfully reported during a run.

    The summary contains only primary artifacts. Bundle companions are sent to plugins, but omitted from this user-facing record.

  • pending (list[PendingAsset], default: <dynamic> ) –

    Built-in mutable sequence.

    If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

  • active (bool, default: False ) –
  • store (Store | None, default: None ) –
  • run_id (str | None, default: None ) –
  • bindings (list[dict[str, Any]], default: <dynamic> ) –

    Built-in mutable sequence.

    If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

  • retained_bundles (list[dict[str, Any]], default: <dynamic> ) –

    Built-in mutable sequence.

    If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

Methods:

Attributes:

active class-attribute instance-attribute

active: bool = False

bindings class-attribute instance-attribute

bindings: list[dict[str, Any]] = attrs.field(factory=list)

bundles class-attribute instance-attribute

bundles: BundleRegistry = attrs.field(default=bundles)

data_dir property

data_dir: Path

pending class-attribute instance-attribute

pending: list[PendingAsset] = attrs.field(factory=list)

plugins instance-attribute

retained_bundles class-attribute instance-attribute

retained_bundles: list[dict[str, Any]] = attrs.field(
    factory=list
)

run_id class-attribute instance-attribute

run_id: str | None = None

store class-attribute instance-attribute

store: Store | None = None

summary class-attribute instance-attribute

summary: AssetsSummary = attrs.field(factory=AssetsSummary)

temp_dir property

temp_dir: Path

working_dir instance-attribute

working_dir: Path

end

end() -> None
Source code in src/liblaf/cherries/core/assets/_manager.py
def end(self) -> None:
    self._check()
    self._validate_inputs()
    for pending in self.pending:
        if not pending.path.exists():
            msg = f"Required output was not written: {pending.path}"
            raise FileNotFoundError(msg)
        self.log_output(pending.path, metadata=pending.metadata)
    self.pending.clear()
    self._retain_bundles()

input

input(
    path: StrPath,
    *,
    name: StrPath | None = None,
    source_run: str | None = None,
    metadata: Mapping[str, Any] | None = None,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def input(
    self,
    path: StrPath,
    *,
    name: StrPath | None = None,
    source_run: str | None = None,
    metadata: Mapping[str, Any] | None = None,
) -> Path:
    self._check()
    original = os.fspath(path)
    declaration = original
    replay = os.environ.get("CHERRIES_REPLAY_INPUTS")
    if replay:
        declaration = json.loads(Path(replay).read_text()).get(
            original, declaration
        )
    binding: dict[str, Any]
    if declaration.startswith(("sha256:", "sha256-tree:", "run:")):
        target, binding = self._reference_input(declaration, name, source_run)
    else:
        source = Path(declaration).expanduser().resolve(strict=True)
        target = self._target("inputs", name or source.name)
        _copy_verified(source, target)
        binding = {
            "asset_id": "sha256:" + hash_file(target) if target.is_file() else None
        }
        if source.is_file():
            self._companions(source, target)
    binding.update(
        {
            "source": original,
            "resolved_source": declaration,
            "staged_path": target.relative_to(self.working_dir).as_posix(),
        }
    )
    binding["input_snapshot"] = self._input_snapshot(target)
    binding["directory"] = target.is_dir()
    self.bindings.append(binding)
    self.summary.inputs.append(target)
    self.plugins.log_asset(
        target, metadata=_metadata_with_type(metadata, "input"), report=True
    )
    return target

log_asset

log_asset(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def log_asset(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path:
    return self._log(path, "artifacts", "asset", metadata, name)

log_input

log_input(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def log_input(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path:
    return self.input(path, name=name, metadata=metadata)

log_output

log_output(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def log_output(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path:
    return self._log(path, "outputs", "output", metadata, name)

log_temp

log_temp(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def log_temp(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    name: StrPath | None = None,
) -> Path:
    return self._log(path, "artifacts", "temp", metadata, name)

output

output(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    mkdir: bool = True,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def output(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    mkdir: bool = True,
) -> Path:
    target = self._target("outputs", path)
    if mkdir:
        target.parent.mkdir(parents=True, exist_ok=True)
    if any(item.path == target for item in self.pending):
        msg = f"output already declared: {path}"
        raise ValueError(msg)
    self.pending.append(
        PendingAsset(target, _metadata_with_type(metadata, "output"))
    )
    return target

temp

temp(
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    mkdir: bool = True,
) -> Path
Source code in src/liblaf/cherries/core/assets/_manager.py
def temp(
    self,
    path: StrPath,
    *,
    metadata: Mapping[str, Any] | None = None,
    mkdir: bool = True,
) -> Path:
    # Scratch metadata is accepted for old scripts but is not retained.
    del metadata
    target = self._target("scratch", path)
    if mkdir:
        target.parent.mkdir(parents=True, exist_ok=True)
    return target

Bundle

Bases: ABC


              flowchart TD
              liblaf.cherries.core.assets.Bundle[Bundle]

              

              click liblaf.cherries.core.assets.Bundle href "" "liblaf.cherries.core.assets.Bundle"
            

Base class for artifact companion-file discovery.

Methods:

  • ls_files –

    Yield files that should be logged with path.

  • match –

    Return whether this bundle can expand path.

ls_files abstractmethod

ls_files(path: Path) -> Iterable[BundleItem]

Yield files that should be logged with path.

Parameters:

  • path (Path) –

    Primary artifact path.

Returns:

  • Iterable[BundleItem] –

    Iterable of companion files and their optional/missing-file policy.

Source code in src/liblaf/cherries/core/assets/bundle/_abc.py
@abc.abstractmethod
def ls_files(self, path: Path) -> Iterable[BundleItem]:
    """Yield files that should be logged with `path`.

    Args:
        path: Primary artifact path.

    Returns:
        Iterable of companion files and their optional/missing-file policy.
    """
    raise NotImplementedError

match abstractmethod

match(path: Path) -> bool

Return whether this bundle can expand path.

Parameters:

  • path (Path) –

    Primary artifact path.

Returns:

Source code in src/liblaf/cherries/core/assets/bundle/_abc.py
@abc.abstractmethod
def match(self, path: Path) -> bool:
    """Return whether this bundle can expand `path`.

    Args:
        path: Primary artifact path.

    Returns:
        `True` when [`ls_files`][liblaf.cherries.core.assets.bundle.Bundle.ls_files]
        can yield companion files for `path`.
    """
    raise NotImplementedError

BundleItem

Bases: NamedTuple


              flowchart TD
              liblaf.cherries.core.assets.BundleItem[BundleItem]

              

              click liblaf.cherries.core.assets.BundleItem href "" "liblaf.cherries.core.assets.BundleItem"
            

Related file discovered for a logged artifact.

Attributes:

Parameters:

  • path (ForwardRef, default: None ) –
  • optional (ForwardRef, default: None ) –

optional instance-attribute

optional: bool

path instance-attribute

path: StrPath

BundleRegistry

Registry that expands logged artifacts through matching bundles.

Examples:

>>> registry = BundleRegistry(registry=[])
>>> list(registry.ls_files(Path("mesh.vtu")))
[]

Parameters:

  • registry (list[Bundle], default: [BundleLandmarks(suffixes={'.obj', '.vtp', '.ply', '.stl', '.vtr', '.vtkhdf', '.vts', '.vtu', '.vti'}), BundleSeries()] ) –

Methods:

  • ls_files –

    Yield companion files from every bundle that matches path.

  • register –

    Append bundle to the registry.

Attributes:

registry class-attribute instance-attribute

registry: list[Bundle] = attrs.field(
    factory=_default_registry
)

ls_files

ls_files(path: Path) -> Generator[BundleItem]

Yield companion files from every bundle that matches path.

Source code in src/liblaf/cherries/core/assets/bundle/_registry.py
def ls_files(self, path: Path) -> Generator[BundleItem]:
    """Yield companion files from every bundle that matches `path`."""
    for bundle in self.registry:
        if bundle.match(path):
            yield from bundle.ls_files(path)

register

register(bundle: Bundle) -> None

Append bundle to the registry.

Source code in src/liblaf/cherries/core/assets/bundle/_registry.py
def register(self, bundle: Bundle) -> None:
    """Append `bundle` to the registry."""
    self.registry.append(bundle)