Source code for mixing.egress

"""Canonical *egress*: route a produced result to its destination.

Across ``mixing``, every result-producing function takes a single ``output``
parameter whose **role** is constant — "what to do with the result" — while its
**type** is open:

====================  ===================================================
``output`` value      behavior
====================  ===================================================
``None``              return the in-memory result (object producers) or
                      save next to the input (file producers); see below
a **file path**       write the result there; return the ``Path``
a **directory**       write with an auto-derived name; return the ``Path``
a **callable**        return ``output(result)`` — the general escape hatch
====================  ===================================================

There are two flavors of producer, modeled by two helpers:

- :func:`deliver` — *object-first*: ``output=None`` returns the in-memory
  object (e.g. an :class:`~mixing.audio.Audio`). Used by editing functions that
  build a value you may want to keep chaining.
- :func:`write_egress` — *file-first*: ``output=None`` saves to a default path
  (typically beside the input) and returns it. Used by file→file operations
  whose whole point is to produce a file.

Both accept the same ``output`` forms, so callers learn one mental model.
``Output`` is the shared type alias.
"""

from __future__ import annotations

import os
from pathlib import Path
from typing import Any, Callable, Union

PathLike = Union[str, "os.PathLike[str]"]

#: An egress target: nothing, a filesystem path/dir, or a result-consuming sink.
Output = Union[None, PathLike, Callable[[Any], Any]]

__all__ = [
    "Output",
    "PathLike",
    "is_path_output",
    "is_sink",
    "resolve_output_path",
    "deliver",
    "write_egress",
]


[docs] def is_path_output(output: object) -> bool: """True if ``output`` denotes a filesystem path (``str`` / ``os.PathLike``).""" return isinstance(output, (str, os.PathLike))
[docs] def is_sink(output: object) -> bool: """True if ``output`` is a result-consuming callable (not a path).""" return callable(output) and not is_path_output(output)
def _looks_like_dir(output: PathLike) -> bool: """Heuristic: an existing directory, or a path with a trailing separator.""" if Path(output).is_dir(): return True raw = os.fspath(output) return raw.endswith(("/", os.sep))
[docs] def resolve_output_path(output: PathLike, *, default_name: str) -> Path: """Resolve a path/dir ``output`` to a concrete file ``Path`` (parents created). A directory ``output`` (existing, or with a trailing separator) is joined with ``default_name``. Only call this when ``output`` is a path — not ``None`` and not a sink. """ path = Path(output).expanduser() if _looks_like_dir(output): path = path / default_name path.parent.mkdir(parents=True, exist_ok=True) return path
[docs] def deliver( result: Any, output: Output, *, write: Callable[[Any, Path], Any], default_name: str, ) -> Any: """Object-first egress: route an in-memory ``result`` to ``output``. - ``None`` → return ``result`` unchanged (no I/O). - sink callable → return ``output(result)``. - path/dir → ``write(result, path)`` then return the ``Path``. Args: result: the produced in-memory value (e.g. an ``Audio``). output: the egress target (see module docstring). write: ``write(result, path)`` persists ``result`` to ``path``. default_name: filename to use when ``output`` is a directory. """ if output is None: return result if is_sink(output): return output(result) path = resolve_output_path(output, default_name=default_name) write(result, path) return path
[docs] def write_egress( output: Output, *, default_path: PathLike, write: Callable[[Path], Any], ) -> Any: """File-first egress: for operations whose primary effect is writing a file. - ``None`` → write to ``default_path`` (e.g. beside the input) and return it. - sink callable → write to ``default_path``, then return ``output(path)``. - path/dir → write to that file (dir → ``default_path``'s name inside it). Args: output: the egress target (see module docstring). default_path: where to write when ``output`` is ``None`` / a sink, and the source of the auto filename when ``output`` is a directory. write: ``write(path)`` performs the actual encode to ``path``. """ default_path = Path(default_path) if is_sink(output) or output is None: target = default_path elif _looks_like_dir(output): target = Path(output).expanduser() / default_path.name else: target = Path(output).expanduser() target.parent.mkdir(parents=True, exist_ok=True) write(target) return output(target) if is_sink(output) else target