Skip to content

liblaf.grapes

Modules:

Type Aliases:

Classes:

Functions:

Attributes:

MISSING module-attribute

MISSING: Final[MissingType] = MISSING

__commit_id__ module-attribute

__commit_id__: str | None = None

__version__ module-attribute

__version__: str = '9.3.5.dev7+gefe5162e2'

__version_tuple__ module-attribute

__version_tuple__: tuple[int | str, ...] = (
    9,
    3,
    5,
    "dev7",
    "gefe5162e2",
)

config module-attribute

config: Config = Config()

json module-attribute

json = Serde(decoder=decode, encoder=encode)

toml module-attribute

toml = Serde(decoder=decode, encoder=encode)

yaml module-attribute

yaml = Serde(decoder=decode, encoder=encode)

MissingType

MissingType = Literal[MISSING]

BaseTimer

Bases: Timings


              flowchart TD
              liblaf.grapes.BaseTimer[BaseTimer]
              liblaf.grapes.timing._timings.Timings[Timings]

                              liblaf.grapes.timing._timings.Timings --> liblaf.grapes.BaseTimer
                


              click liblaf.grapes.BaseTimer href "" "liblaf.grapes.BaseTimer"
              click liblaf.grapes.timing._timings.Timings href "" "liblaf.grapes.timing._timings.Timings"
            

Parameters:

  • label

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • clocks

    (Sequence[ClockName], default: ('perf',) ) –
  • cb_start

    (Callback | None, default: None ) –
  • cb_stop

    (Callback | None, default: <function log_record at 0x7f8a6ee77320> ) –
  • cb_finish

    (Callback | None, default: <function log_summary at 0x7f8a6ee77740> ) –

Attributes:

Methods:

cb_finish class-attribute instance-attribute

cb_finish: Callback | None = log_summary

cb_start class-attribute instance-attribute

cb_start: Callback | None = None

cb_stop class-attribute instance-attribute

cb_stop: Callback | None = log_record

clocks class-attribute instance-attribute

clocks: Sequence[ClockName] = field(default=DEFAULT_CLOCKS)

default_clock property

default_clock: ClockName

label class-attribute instance-attribute

label: str | None = field(default=None)

name class-attribute instance-attribute

name: str | None = field(default=None)

timings class-attribute instance-attribute

timings: dict[ClockName, list[float]] = field(
    factory=lambda: defaultdict(list), init=False
)

__attrs_post_init__

__attrs_post_init__() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def __attrs_post_init__(self) -> None:
    _warnings_hide = True
    if self.label is None and self.name is not None:
        warnings.warn(
            "'name' parameter is deprecated. Please use 'label' instead.",
            DeprecationWarning,
        )
        self.label = self.name

__bool__

__bool__() -> bool
Source code in src/liblaf/grapes/timing/_base.py
def __bool__(self) -> bool:
    return True

__len__

__len__() -> int
Source code in src/liblaf/grapes/timing/_timings.py
def __len__(self) -> int:
    return len(self.timings[self.default_clock])

clear

clear() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def clear(self) -> None:
    self.timings.clear()
    self._start_time.clear()
    self._stop_time.clear()

elapsed

elapsed(clock_name: ClockName | None = None) -> float
Source code in src/liblaf/grapes/timing/_timings.py
def elapsed(self, clock_name: ClockName | None = None) -> float:
    clock_name = clock_name or self.default_clock
    stop_time: float
    if clock_name in self._stop_time:
        stop_time = self._stop_time[clock_name]
    else:
        stop_time = clock(clock_name)
    return stop_time - self._start_time[clock_name]

finish

finish() -> None
Source code in src/liblaf/grapes/timing/_base.py
def finish(self) -> None:
    _logging_hide = True
    if self.cb_finish is not None:
        self.cb_finish(self)

log_record

log_record(
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | RateLimitItem | None = "1/second",
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_record(
    self,
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | limits.RateLimitItem | None = "1/second",
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_record(index=index)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            )
        },
    )

log_summary

log_summary(
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | RateLimitItem | None = None,
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_summary(
    self,
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | limits.RateLimitItem | None = None,
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_summary(stats=stats)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            ),
            "markup": lambda: self.pretty_summary(stats=stats, rich_markup=True),
        },
    )

pretty_record

pretty_record(index: int = -1) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_record(self, index: int = -1) -> str:
    name: str = self.label or "Timer"
    items: list[str] = [
        f"{clock_name}: {pretty.pretty_duration(self.timings[clock_name][index])}"
        for clock_name in self.clocks
    ]
    items_str: str = ", ".join(items)
    return f"{name} > {items_str}"

pretty_summary

pretty_summary(
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_summary(
    self,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str:
    name: str = self.label or "Timer"
    header: str = f"{name} (count: {len(self)})"
    if len(self) == 0:
        return header
    lines: list[str] = []
    for clock_name in self.clocks:
        stats_str: list[str] = []
        for stat in stats:
            stat_name: str
            value: str
            stat_name, value = pretty_statistic(
                self.timings[clock_name], stat, rich_markup=rich_markup
            )
            stats_str.append(f"{stat_name}: {value}")
        line: str = f"{clock_name} > {', '.join(stats_str)}"
        lines.append(line)
    if len(self.clocks) == 1:
        return f"{header} {lines[0]}"
    return f"{header}\n" + "\n".join(lines)

start

start() -> None
Source code in src/liblaf/grapes/timing/_base.py
def start(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        self._start_time[clock_name] = clock(clock_name)
    self._stop_time.clear()
    if self.cb_start is not None:
        self.cb_start(self)

stop

stop() -> None
Source code in src/liblaf/grapes/timing/_base.py
def stop(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        stop_time: float = clock(clock_name)
        self._stop_time[clock_name] = stop_time
        self.timings[clock_name].append(stop_time - self._start_time[clock_name])
    if self.cb_stop is not None:
        self.cb_stop(self)

BenchResults

Parameters:

Methods:

Attributes:

outputs instance-attribute

outputs: dict[str, list[Any]]

sizes instance-attribute

sizes: list[float]

timings instance-attribute

timings: dict[str, list[float]]

plot

plot(
    *,
    relative_to: str | None = None,
    xlabel: str = "Size",
    ylabel: str = "Time (sec)",
    log_scale: bool = True,
) -> Figure
Source code in src/liblaf/grapes/bench/_results.py
def plot(
    self,
    *,
    relative_to: str | None = None,
    xlabel: str = "Size",
    ylabel: str = "Time (sec)",
    log_scale: bool = True,
) -> Figure:
    with deps.optional_deps("liblaf-grapes", "bench"):
        import matplotlib.pyplot as plt

    if relative_to is None:
        relative_to = min(self.timings.keys(), key=lambda k: self.timings[k][-1])

    fig: Figure
    ax0: Axes
    ax1: Axes
    fig, (ax0, ax1) = plt.subplots(1, 2, sharex="all", figsize=(12.8, 4.8))

    for label, timings in self.timings.items():
        ax0.plot(self.sizes, timings, label=label)
        base: list[float] = self.timings[relative_to]
        relative: list[float] = [t / b for t, b in zip(timings, base, strict=True)]
        ax1.plot(self.sizes, relative, label=label)

    ax0.grid(which="both", linestyle="--")
    ax0.legend()
    ax0.set_xlabel(xlabel)
    ax0.set_ylabel(ylabel)

    ax1.grid(which="both", linestyle="--")
    ax1.legend()
    ax1.set_xlabel(xlabel)
    ax1.set_ylabel(f"{ylabel} (relative to {relative_to})")

    if log_scale:
        ax0.set_xscale("log")
        ax0.set_yscale("log")
        ax1.set_xscale("log")

    fig.tight_layout()
    return fig

Bencher

Parameters:

  • min_time

    (float, default: 0.2 ) –
  • timeout

    (float, default: 10.0 ) –
  • warmup

    (int, default: 1 ) –

Methods:

Attributes:

min_time class-attribute instance-attribute

min_time: float = 0.2

timeout class-attribute instance-attribute

timeout: float = 10.0

warmup class-attribute instance-attribute

warmup: int = 1

bench

bench[C: Callable](
    func: C, /, *, label: str | None = None
) -> C
bench[C: Callable](
    *, label: str | None = None
) -> Callable[[C], C]
Source code in src/liblaf/grapes/bench/_bencher.py
def bench(
    self, func: Callable | None = None, *, label: str | None = None
) -> Callable:
    if func is None:
        return functools.partial(self.bench, label=label)
    if label is None:
        label = func.__name__
    self._registry[label] = func
    return func

run

run() -> BenchResults
Source code in src/liblaf/grapes/bench/_bencher.py
def run(self) -> BenchResults:
    inputs: Sequence[tuple[Sequence, Mapping]] = list(self._setup())
    sizes_and_inputs: list[tuple[float, tuple[Sequence, Mapping]]] = [
        (self._size_fn(*args, **kwargs), (args, kwargs)) for args, kwargs in inputs
    ]
    sizes_and_inputs.sort(key=lambda x: x[0])
    sizes: Sequence[float] = [size for size, _ in sizes_and_inputs]
    inputs = [(args, kwargs) for _, (args, kwargs) in sizes_and_inputs]
    outputs: dict[str, list[Any]] = {}
    timings: dict[str, list[float]] = {}
    for label, func in self._registry.items():
        outputs_name: list[Any] = []
        timings_name: list[float] = []
        for size, (args, kwargs) in zip(sizes, inputs, strict=True):
            output: Any
            elapsed: float
            output, elapsed = self._bench(func, args, kwargs)
            outputs_name.append(output)
            timings_name.append(elapsed)
            logger.debug("Bench %s(%g) took %g sec", label, size, elapsed)
            if elapsed > self.timeout:
                logger.warning("Bench %s(%g) timed out", label, size)
                break
        if len(timings_name) < len(sizes):
            n_remain: int = len(sizes) - len(timings_name)
            outputs_name.extend([None] * n_remain)
            timings_name.extend([math.inf] * n_remain)
        timings[label] = timings_name
        outputs[label] = outputs_name
    return BenchResults(outputs=outputs, sizes=list(sizes), timings=timings)

setup

setup[
    C: Callable[..., Iterable[tuple[Sequence, Mapping]]]
](func: C) -> C
Source code in src/liblaf/grapes/bench/_bencher.py
def setup[C: Callable[..., Iterable[tuple[Sequence, Mapping]]]](self, func: C) -> C:
    self._setup = func
    return func

size

size[C: Callable[..., float]](func: C) -> C
Source code in src/liblaf/grapes/bench/_bencher.py
def size[C: Callable[..., float]](self, func: C) -> C:
    self._size_fn = func
    return func

DispatchLookupError

DispatchLookupError(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
)

Bases: LookupError


              flowchart TD
              liblaf.grapes.DispatchLookupError[DispatchLookupError]

              

              click liblaf.grapes.DispatchLookupError href "" "liblaf.grapes.DispatchLookupError"
            

Parameters:

Methods:

Attributes:

Source code in src/liblaf/grapes/errors/_dispatch.py
def __init__(
    self, func: Callable, args: Sequence[Any] = (), kwargs: Mapping[str, Any] = {}
) -> None:
    params = Params(args=args, kwargs=kwargs)
    self.__attrs_init__(func=func, params=params)  # pyright: ignore[reportAttributeAccessIssue]

func instance-attribute

func: Callable

params instance-attribute

params: Params

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_dispatch.py
def __str__(self) -> str:
    from liblaf.grapes import pretty

    pretty_call: str = pretty.pretty_call(
        self.func, self.params.args, self.params.kwargs
    )
    return f"`{pretty_call}` could not be resolved."

LazyRepr

LazyRepr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs

__wrapped__ cached property

__wrapped__: str

args instance-attribute

args = args

func instance-attribute

func: Callable[P, str] = func

kwargs instance-attribute

kwargs = kwargs

__repr__

__repr__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __repr__(self) -> str:
    return self.__wrapped__

LazyStr

LazyStr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs

__wrapped__ cached property

__wrapped__: str

args instance-attribute

args = args

func instance-attribute

func: Callable[P, str] = func

kwargs instance-attribute

kwargs = kwargs

__str__

__str__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __str__(self) -> str:
    return self.__wrapped__

MatchError

Bases: ValueError


              flowchart TD
              liblaf.grapes.MatchError[MatchError]

              

              click liblaf.grapes.MatchError href "" "liblaf.grapes.MatchError"
            

Parameters:

Methods:

Attributes:

typ class-attribute instance-attribute

typ: str | type = 'match'

value instance-attribute

value: Any

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_match.py
def __str__(self) -> str:
    cls: str = self.typ if isinstance(self.typ, str) else self.typ.__qualname__
    return f"{self.value!r} is not a valid {cls}."

Progress

Progress(
    *columns: str | ProgressColumn,
    limit: str | RateLimitItem | None = None,
    limiter: RateLimiter | None = None,
    logger: Logger | None = None,
    speed_estimate_period: float = 30.0,
    get_time: GetTimeCallable | None = None,
    disable: bool = False,
    expand: bool = False,
)

Bases: Progress


              flowchart TD
              liblaf.grapes.Progress[Progress]

              

              click liblaf.grapes.Progress href "" "liblaf.grapes.Progress"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/rich/progress/_progress.py
def __init__(
    self,
    *columns: str | ProgressColumn,
    limit: str | limits.RateLimitItem | None = None,
    limiter: limits.strategies.RateLimiter | None = None,
    logger: logging.Logger | None = None,
    # RichProgress options
    speed_estimate_period: float = 30.0,
    get_time: GetTimeCallable | None = None,
    disable: bool = False,
    expand: bool = False,
) -> None:
    super().__init__(
        *columns,
        console=Console(quiet=True),
        auto_refresh=False,
        speed_estimate_period=speed_estimate_period,
        get_time=get_time,
        disable=disable,
        expand=expand,
    )
    if limit is None:
        limit = limits.RateLimitItemPerSecond(1)
    elif isinstance(limit, str):
        limit = limits.parse(limit)
    self.limit = limit
    if limiter is None:
        limiter = limits.strategies.SlidingWindowCounterRateLimiter(
            limits.storage.MemoryStorage()
        )
    self.limiter = limiter
    if logger is None:
        logger = autolog
    self.logger = logger

limit instance-attribute

limit: RateLimitItem = limit

limiter instance-attribute

limiter: RateLimiter = limiter

logger instance-attribute

logger: Logger = logger

stale class-attribute instance-attribute

stale: bool = False

advance

advance(task_id: TaskID, advance: float = 1) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def advance(self, task_id: TaskID, advance: float = 1) -> None:
    _logging_hide = True
    self.stale = True
    super().advance(task_id, advance)
    self.refresh()

get_default_columns classmethod

get_default_columns() -> tuple[str | ProgressColumn, ...]
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
@classmethod
def get_default_columns(cls) -> tuple[str | ProgressColumn, ...]:  # pyright: ignore[reportIncompatibleMethodOverride]
    return (
        # SpinnerColumn(),
        TextColumn("{task.description}", style="progress.description"),
        BarColumn(),
        TaskProgressColumn(),
        MofNCompleteColumn(),
        "[",
        TimeElapsedColumn(),
        "<",
        TimeRemainingColumn(),
        ",",
        RateColumn(),
        "]",
    )

refresh

refresh(*, force: bool = False) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def refresh(self, *, force: bool = False) -> None:
    _logging_hide = True
    if self.stale and (self.limiter.hit(self.limit) or force):
        self.stale = False
        self.logger.info(self.get_renderable())

reset

reset(
    task_id: TaskID,
    *,
    start: bool = True,
    total: float | None = None,
    completed: int = 0,
    visible: bool | None = None,
    description: str | None = None,
    **fields: Any,
) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def reset(
    self,
    task_id: TaskID,
    *,
    start: bool = True,
    total: float | None = None,
    completed: int = 0,
    visible: bool | None = None,
    description: str | None = None,
    **fields: Any,
) -> None:
    _logging_hide = True
    self.stale = True
    super().reset(
        task_id,
        start=start,
        total=total,
        completed=completed,
        visible=visible,
        description=description,
        **fields,
    )

start

start() -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def start(self) -> None:
    pass

stop

stop() -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def stop(self) -> None:
    _logging_hide = True
    self.refresh(force=True)

update

update(
    task_id: TaskID,
    *,
    total: float | None = None,
    completed: float | None = None,
    advance: float | None = None,
    description: str | None = None,
    visible: bool | None = None,
    refresh: bool = False,
    **fields: Any,
) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def update(
    self,
    task_id: TaskID,
    *,
    total: float | None = None,
    completed: float | None = None,
    advance: float | None = None,
    description: str | None = None,
    visible: bool | None = None,
    refresh: bool = False,
    **fields: Any,
) -> None:
    _logging_hide = True
    self.stale = True
    super().update(
        task_id,
        total=total,
        completed=completed,
        advance=advance,
        description=description,
        visible=visible,
        refresh=refresh,
        **fields,
    )

Timer

Bases: BaseTimer, AbstractContextManager


              flowchart TD
              liblaf.grapes.Timer[Timer]
              liblaf.grapes.timing._base.BaseTimer[BaseTimer]
              liblaf.grapes.timing._timings.Timings[Timings]

                              liblaf.grapes.timing._base.BaseTimer --> liblaf.grapes.Timer
                                liblaf.grapes.timing._timings.Timings --> liblaf.grapes.timing._base.BaseTimer
                



              click liblaf.grapes.Timer href "" "liblaf.grapes.Timer"
              click liblaf.grapes.timing._base.BaseTimer href "" "liblaf.grapes.timing._base.BaseTimer"
              click liblaf.grapes.timing._timings.Timings href "" "liblaf.grapes.timing._timings.Timings"
            

Parameters:

  • label

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • clocks

    (Sequence[ClockName], default: ('perf',) ) –
  • cb_start

    (Callback | None, default: None ) –
  • cb_stop

    (Callback | None, default: <function log_record at 0x7f8a6ee77320> ) –
  • cb_finish

    (Callback | None, default: <function log_summary at 0x7f8a6ee77740> ) –

Attributes:

Methods:

cb_finish class-attribute instance-attribute

cb_finish: Callback | None = log_summary

cb_start class-attribute instance-attribute

cb_start: Callback | None = None

cb_stop class-attribute instance-attribute

cb_stop: Callback | None = log_record

clocks class-attribute instance-attribute

clocks: Sequence[ClockName] = field(default=DEFAULT_CLOCKS)

default_clock property

default_clock: ClockName

label class-attribute instance-attribute

label: str | None = field(default=None)

name class-attribute instance-attribute

name: str | None = field(default=None)

timings class-attribute instance-attribute

timings: dict[ClockName, list[float]] = field(
    factory=lambda: defaultdict(list), init=False
)

__attrs_post_init__

__attrs_post_init__() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def __attrs_post_init__(self) -> None:
    _warnings_hide = True
    if self.label is None and self.name is not None:
        warnings.warn(
            "'name' parameter is deprecated. Please use 'label' instead.",
            DeprecationWarning,
        )
        self.label = self.name

__bool__

__bool__() -> bool
Source code in src/liblaf/grapes/timing/_base.py
def __bool__(self) -> bool:
    return True

__call__

__call__[C: Callable](func: C) -> C
__call__[I: Iterable](iterable: I) -> I
Source code in src/liblaf/grapes/timing/_timer.py
def __call__(self, func_or_iterable: Callable | Iterable, /) -> Any:
    if callable(func_or_iterable):
        return timed_callable(func_or_iterable, self)
    return TimedIterable(func_or_iterable, self)

__enter__

__enter__() -> Self
Source code in src/liblaf/grapes/timing/_timer.py
@override  # contextlib.AbstractContextManager
def __enter__(self) -> Self:
    _logging_hide = True
    self.start()
    return self

__exit__

__exit__(
    exc_type: type[BaseException] | None,
    exc_value: BaseException | None,
    traceback: TracebackType | None,
) -> None
Source code in src/liblaf/grapes/timing/_timer.py
@override  # contextlib.AbstractContextManager
def __exit__(
    self,
    exc_type: type[BaseException] | None,
    exc_value: BaseException | None,
    traceback: types.TracebackType | None,
    /,
) -> None:
    _logging_hide = True
    self.stop()

__len__

__len__() -> int
Source code in src/liblaf/grapes/timing/_timings.py
def __len__(self) -> int:
    return len(self.timings[self.default_clock])

clear

clear() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def clear(self) -> None:
    self.timings.clear()
    self._start_time.clear()
    self._stop_time.clear()

elapsed

elapsed(clock_name: ClockName | None = None) -> float
Source code in src/liblaf/grapes/timing/_timings.py
def elapsed(self, clock_name: ClockName | None = None) -> float:
    clock_name = clock_name or self.default_clock
    stop_time: float
    if clock_name in self._stop_time:
        stop_time = self._stop_time[clock_name]
    else:
        stop_time = clock(clock_name)
    return stop_time - self._start_time[clock_name]

finish

finish() -> None
Source code in src/liblaf/grapes/timing/_base.py
def finish(self) -> None:
    _logging_hide = True
    if self.cb_finish is not None:
        self.cb_finish(self)

log_record

log_record(
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | RateLimitItem | None = "1/second",
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_record(
    self,
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | limits.RateLimitItem | None = "1/second",
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_record(index=index)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            )
        },
    )

log_summary

log_summary(
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | RateLimitItem | None = None,
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_summary(
    self,
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | limits.RateLimitItem | None = None,
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_summary(stats=stats)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            ),
            "markup": lambda: self.pretty_summary(stats=stats, rich_markup=True),
        },
    )

pretty_record

pretty_record(index: int = -1) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_record(self, index: int = -1) -> str:
    name: str = self.label or "Timer"
    items: list[str] = [
        f"{clock_name}: {pretty.pretty_duration(self.timings[clock_name][index])}"
        for clock_name in self.clocks
    ]
    items_str: str = ", ".join(items)
    return f"{name} > {items_str}"

pretty_summary

pretty_summary(
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_summary(
    self,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str:
    name: str = self.label or "Timer"
    header: str = f"{name} (count: {len(self)})"
    if len(self) == 0:
        return header
    lines: list[str] = []
    for clock_name in self.clocks:
        stats_str: list[str] = []
        for stat in stats:
            stat_name: str
            value: str
            stat_name, value = pretty_statistic(
                self.timings[clock_name], stat, rich_markup=rich_markup
            )
            stats_str.append(f"{stat_name}: {value}")
        line: str = f"{clock_name} > {', '.join(stats_str)}"
        lines.append(line)
    if len(self.clocks) == 1:
        return f"{header} {lines[0]}"
    return f"{header}\n" + "\n".join(lines)

start

start() -> None
Source code in src/liblaf/grapes/timing/_base.py
def start(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        self._start_time[clock_name] = clock(clock_name)
    self._stop_time.clear()
    if self.cb_start is not None:
        self.cb_start(self)

stop

stop() -> None
Source code in src/liblaf/grapes/timing/_base.py
def stop(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        stop_time: float = clock(clock_name)
        self._stop_time[clock_name] = stop_time
        self.timings[clock_name].append(stop_time - self._start_time[clock_name])
    if self.cb_stop is not None:
        self.cb_stop(self)

TodoError

Bases: NotImplementedError


              flowchart TD
              liblaf.grapes.TodoError[TodoError]

              

              click liblaf.grapes.TodoError href "" "liblaf.grapes.TodoError"
            

Parameters:

  • message

    (str, default: 'not yet implemented' ) –
  • assignee

    (str | None, default: None ) –

Methods:

Attributes:

assignee class-attribute instance-attribute

assignee: str | None = None

message class-attribute instance-attribute

message: str = 'not yet implemented'

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_misc.py
def __str__(self) -> str:
    msg: str = "TODO"
    if self.assignee:
        msg += f"({self.assignee})"
    msg += f": {self.message}"
    return msg

UnreachableError

Bases: AssertionError


              flowchart TD
              liblaf.grapes.UnreachableError[UnreachableError]

              

              click liblaf.grapes.UnreachableError href "" "liblaf.grapes.UnreachableError"
            

Parameters:

  • message

    (str | None, default: None ) –

Methods:

Attributes:

message class-attribute instance-attribute

message: str | None = None

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_misc.py
def __str__(self) -> str:
    msg: str = "internal error: entered unreachable code"
    if self.message:
        msg += f": {self.message}"
    return msg

areidentical

areidentical(*seqs: Iterable[Any]) -> bool

Determine if sequences are identical element-wise. This lazily evaluates the sequences and stops as soon as the result is determined.

Examples:

>>> areidentical([1, 2, 3], (1, 2, 3))
True
>>> areidentical([1, 2, 3], [1, 2])
False
Source code in src/liblaf/grapes/itertools/_toolz.py
def areidentical(*seqs: Iterable[Any]) -> bool:
    """Determine if sequences are identical element-wise. This lazily evaluates the sequences and stops as soon as the result is determined.

    Examples:
        >>> areidentical([1, 2, 3], (1, 2, 3))
        True

        >>> areidentical([1, 2, 3], [1, 2])
        False
    """
    return not any(tlz.diff(*seqs, default=object()))

array_kind

array_kind(obj: Any) -> str | None
Source code in src/liblaf/grapes/typing/_array.py
def array_kind(obj: Any) -> str | None:
    # ref: <https://github.com/arogozhnikov/einops/blob/43a12ee010a844f3ad57bf404d27e4ee2d151131/einops/_backends.py>
    # ref: <https://github.com/patrick-kidger/wadler_lindig/blob/03ed125c04766008fb3f2eaa611fd3627b09de3d/wadler_lindig/_definitions.py#L254-L265>
    for module_name, type_name in _ARRAY_KINDS:
        module: types.ModuleType | None = sys.modules.get(module_name)
        if module is None:
            continue
        if isinstance(obj, getattr(module, type_name)):
            return module_name
    return None

as_iterable

as_iterable(
    obj: Any, base_type: ClassInfo | None = (str, bytes)
) -> Iterable

.

Examples:

If obj is iterable, return an iterator over its items:

>>> obj = (1, 2, 3)
>>> as_iterable(obj)
(1, 2, 3)

If obj is not iterable, return a one-item iterable containing obj:

>>> obj = 1
>>> as_iterable(obj)
(1,)

If obj is None, return an empty iterable:

>>> obj = None
>>> as_iterable(None)
()

By default, binary and text strings are not considered iterable:

>>> obj = "foo"
>>> as_iterable(obj)
('foo',)

If base_type is set, objects for which isinstance(obj, base_type) returns True won't be considered iterable.

>>> obj = {"a": 1}
>>> as_iterable(obj)
{'a': 1}
>>> as_iterable(obj, base_type=dict)  # Treat dicts as a unit
({'a': 1},)

Set base_type to None to avoid any special handling and treat objects Python considers iterable as iterable:

>>> obj = "foo"
>>> as_iterable(obj, base_type=None)
'foo'
References
  1. more_itertools.always_iterable
Source code in src/liblaf/grapes/itertools/_as_iterable.py
def as_iterable(obj: Any, base_type: ClassInfo | None = (str, bytes)) -> Iterable:
    """.

    Examples:
        If `obj` is iterable, return an iterator over its items:

        >>> obj = (1, 2, 3)
        >>> as_iterable(obj)
        (1, 2, 3)

        If `obj` is not iterable, return a one-item iterable containing `obj`:

        >>> obj = 1
        >>> as_iterable(obj)
        (1,)

        If `obj` is `None`, return an empty iterable:

        >>> obj = None
        >>> as_iterable(None)
        ()

        By default, binary and text strings are not considered iterable:

        >>> obj = "foo"
        >>> as_iterable(obj)
        ('foo',)

        If `base_type` is set, objects for which `isinstance(obj, base_type)` returns ``True`` won't be considered iterable.

        >>> obj = {"a": 1}
        >>> as_iterable(obj)
        {'a': 1}
        >>> as_iterable(obj, base_type=dict)  # Treat dicts as a unit
        ({'a': 1},)

        Set `base_type` to `None` to avoid any special handling and treat objects Python considers iterable as iterable:

        >>> obj = "foo"
        >>> as_iterable(obj, base_type=None)
        'foo'

    References:
        1. [`more_itertools.always_iterable`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable)
    """
    if obj is None:
        return ()
    if base_type is not None and isinstance(obj, base_type):
        return (obj,)
    if isinstance(obj, Iterable):
        return obj
    return (obj,)

as_sequence

as_sequence(
    obj: Any, base_type: ClassInfo | None = (str, bytes)
) -> Sequence

.

Examples:

If obj is iterable, return an iterator over its items:

>>> obj = (1, 2, 3)
>>> as_sequence(obj)
(1, 2, 3)

If obj is not iterable, return a one-item iterable containing obj:

>>> obj = 1
>>> as_sequence(obj)
(1,)

If obj is None, return an empty iterable:

>>> obj = None
>>> as_sequence(None)
()

By default, binary and text strings are not considered iterable:

>>> obj = "foo"
>>> as_sequence(obj)
('foo',)

If base_type is set, objects for which isinstance(obj, base_type) returns True won't be considered iterable.

>>> obj = {"a": 1}
>>> as_sequence(obj)
({'a': 1},)
>>> as_sequence(obj, base_type=dict)  # Treat dicts as a unit
({'a': 1},)

Set base_type to None to avoid any special handling and treat objects Python considers iterable as iterable:

>>> obj = "foo"
>>> as_sequence(obj, base_type=None)
'foo'
References
  1. more_itertools.always_iterable
Source code in src/liblaf/grapes/itertools/_as_sequence.py
def as_sequence(obj: Any, base_type: ClassInfo | None = (str, bytes)) -> Sequence:
    """.

    Examples:
        If `obj` is iterable, return an iterator over its items:

        >>> obj = (1, 2, 3)
        >>> as_sequence(obj)
        (1, 2, 3)

        If `obj` is not iterable, return a one-item iterable containing `obj`:

        >>> obj = 1
        >>> as_sequence(obj)
        (1,)

        If `obj` is `None`, return an empty iterable:

        >>> obj = None
        >>> as_sequence(None)
        ()

        By default, binary and text strings are not considered iterable:

        >>> obj = "foo"
        >>> as_sequence(obj)
        ('foo',)

        If `base_type` is set, objects for which `isinstance(obj, base_type)` returns ``True`` won't be considered iterable.

        >>> obj = {"a": 1}
        >>> as_sequence(obj)
        ({'a': 1},)
        >>> as_sequence(obj, base_type=dict)  # Treat dicts as a unit
        ({'a': 1},)

        Set `base_type` to `None` to avoid any special handling and treat objects Python considers iterable as iterable:

        >>> obj = "foo"
        >>> as_sequence(obj, base_type=None)
        'foo'

    References:
        1. [`more_itertools.always_iterable`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable)
    """
    if obj is None:
        return ()
    if base_type is not None and isinstance(obj, base_type):
        return (obj,)
    if isinstance(obj, Sequence):
        return obj
    return (obj,)

auto_rich_repr

auto_rich_repr[T: type](
    cls: T, *, rich_repr: bool | None = None
) -> T
auto_rich_repr[T: type](
    *, rich_repr: bool | None = None
) -> Callable[[T], T]
Source code in src/liblaf/grapes/rich/repr/_auto.py
def auto_rich_repr(cls: type | None = None, *, rich_repr: bool | None = None) -> Any:
    if cls is None:
        return functools.partial(auto_rich_repr, rich_repr=rich_repr)
    if rich_repr is None:
        rich_repr = not hasattr(cls, "__rich_repr__")
    if rich_repr and has_fields(cls):
        cls.__rich_repr__ = rich_repr_fieldz
    return cls

compact

compact[T](iterable: Iterable[T | None]) -> Iterator[T]

Filter an iterable on "truthy" values.

Examples:

>>> results = [0, 1, 2, None, 3, False]
>>> list(compact(results))
[1, 2, 3]
Source code in src/liblaf/grapes/itertools/_toolz.py
def compact[T](iterable: Iterable[T | None]) -> Iterator[T]:
    """Filter an iterable on "truthy" values.

    Examples:
        >>> results = [0, 1, 2, None, 3, False]
        >>> list(compact(results))
        [1, 2, 3]
    """
    return tlz.filter(None, iterable)

contains

contains[T](
    obj: Container[T],
    key: T,
    deprecated_keys: Iterable[T] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> bool

.

Examples:

>>> import pytest
>>> data = {"a": 1, "b": 2}
>>> contains(data, "a")
True
>>> contains(data, "missing")
False
>>> with pytest.deprecated_call():
...     contains(data, "c", deprecated_keys=["missing", "b"])
True
Source code in src/liblaf/grapes/compat/_operator.py
def contains[T](
    obj: Container[T],
    key: T,
    deprecated_keys: Iterable[T] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> bool:
    """.

    Examples:
        >>> import pytest
        >>> data = {"a": 1, "b": 2}
        >>> contains(data, "a")
        True
        >>> contains(data, "missing")
        False
        >>> with pytest.deprecated_call():
        ...     contains(data, "c", deprecated_keys=["missing", "b"])
        True
    """
    _warnings_hide = True
    if key in obj:
        return True
    for deprecated_key in deprecated_keys:
        if deprecated_key in obj:
            warnings.warn(
                msg.format_map({"deprecated_key": deprecated_key, "key": key}),
                DeprecationWarning,
            )
            return True
    return False

dec_hook

dec_hook(
    typ: type,
    obj: Any,
    /,
    *,
    pydantic_options: PydanticValidateOptions | None = None,
) -> Any
Source code in src/liblaf/grapes/serde/_decode.py
def dec_hook(
    typ: type, obj: Any, /, *, pydantic_options: PydanticValidateOptions | None = None
) -> Any:
    if issubclass(typ, pydantic.BaseModel):
        pydantic_options = pydantic_options or {}
        return typ.model_validate(obj, **pydantic_options)
    return typ(obj)

enc_hook

enc_hook(obj: Any, /, **_kwargs) -> Any
Source code in src/liblaf/grapes/serde/_encode.py
@functools.singledispatch
def enc_hook(obj: Any, /, **_kwargs) -> Any:
    msg: str = f"Objects of type {type(obj)} are not supported"
    raise NotImplementedError(msg)

entrypoint

entrypoint() -> Path
Source code in src/liblaf/grapes/magic/_entrypoint.py
def entrypoint() -> Path:
    return Path(sys.argv[0])

first_not_none

first_not_none[T](*args: T | None) -> T

Returns the first not None value in the args.

Examples:

>>> first_not_none(1, 2)
1
>>> first_not_none(None, 1)
1
References
  1. more_itertools.first_true
Source code in src/liblaf/grapes/itertools/_first_not_none.py
def first_not_none[T](*args: T | None) -> T:
    """Returns the first `not None` value in the `args`.

    Examples:
        >>> first_not_none(1, 2)
        1
        >>> first_not_none(None, 1)
        1

    References:
        1. [`more_itertools.first_true`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first_true)
    """
    return next(arg for arg in args if arg is not None)

get_console cached

get_console(**kwargs) -> Console
Source code in src/liblaf/grapes/rich/_get_console.py
@wraps(Console)
@functools.cache
def get_console(**kwargs) -> Console:
    if kwargs.get("theme") is None:
        kwargs["theme"] = default_theme()
    file: IO[str] | None = kwargs.get("file")
    stderr: bool = file is None and kwargs.get("stderr", False)
    stdout: bool = file is None and not stderr
    if "force_terminal" not in kwargs and (stdout or stderr) and magic.in_ci():
        kwargs["force_terminal"] = True
    if "width" not in kwargs and (
        (stdout and not sys.stdout.isatty())
        or (stderr and not sys.stderr.isatty())
        or (file is not None and not os.isatty(file.fileno()))
    ):
        kwargs["width"] = 128
    if stdout:
        rich.reconfigure(**kwargs)
        return rich.get_console()
    return Console(**kwargs)

get_timer

get_timer(wrapper: Any) -> BaseTimer
get_timer[T](wrapper: Any, default: T) -> BaseTimer | T
Source code in src/liblaf/grapes/timing/_utils.py
def get_timer(wrapper: Any, default: Any = MISSING) -> Any:
    if default is MISSING:
        return ft.wrapt_getattr(wrapper, "timer")
    return ft.wrapt_getattr(wrapper, "timer", default)

getitem

getitem[KT, VT](
    obj: SupportsGetItem[KT, VT],
    key: KT,
    deprecated_keys: Iterable[KT] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> VT

.

Examples:

>>> import pytest
>>> data = {"a": 1, "b": 2}
>>> getitem(data, "a")
1
>>> with pytest.raises(KeyError):
...     getitem(data, "missing")
>>> with pytest.deprecated_call():
...     getitem(data, "c", deprecated_keys=["missing", "b"])
2
Source code in src/liblaf/grapes/compat/_operator.py
def getitem[KT, VT](
    obj: SupportsGetItem[KT, VT],
    key: KT,
    deprecated_keys: Iterable[KT] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> VT:
    """.

    Examples:
        >>> import pytest
        >>> data = {"a": 1, "b": 2}
        >>> getitem(data, "a")
        1
        >>> with pytest.raises(KeyError):
        ...     getitem(data, "missing")
        >>> with pytest.deprecated_call():
        ...     getitem(data, "c", deprecated_keys=["missing", "b"])
        2
    """
    _warnings_hide = True
    try:
        return obj[key]
    except KeyError:
        pass
    for deprecated_key in deprecated_keys:
        try:
            value: VT = obj[deprecated_key]
        except KeyError:
            continue
        warnings.warn(
            msg.format_map({"deprecated_key": deprecated_key, "key": key}),
            DeprecationWarning,
        )
        return value
    raise KeyError(key)

has_ansi

has_ansi(s: str) -> bool

.

Examples:

>>> has_ansi("\x1b[31m red text \x1b[0m")
True
>>> has_ansi("plain text")
False
Source code in src/liblaf/grapes/pretty/_ansi.py
def has_ansi(s: str, /) -> bool:
    r""".

    Examples:
        >>> has_ansi("\x1b[31m red text \x1b[0m")
        True
        >>> has_ansi("plain text")
        False
    """
    return "\x1b" in s

in_ci

in_ci() -> bool
Source code in src/liblaf/grapes/magic/_ci.py
def in_ci() -> bool:
    return env.bool("CI", False)

is_array

is_array(obj: Any) -> bool
Source code in src/liblaf/grapes/typing/_array.py
def is_array(obj: Any) -> bool:
    return array_kind(obj) is not None

keyjoin

keyjoin[KT, VT](
    leftkey: KT,
    leftseq: Iterable[Mapping[KT, VT]],
    rightkey: KT,
    rightseq: Iterable[Mapping[KT, VT]],
) -> Iterator[Mapping[KT, VT]]

Inner join two sequences of dictionaries on specified keys, merging matches with right value precedence.

Examples:

>>> people = [
...     {"id": 0, "name": "Anonymous Guy", "location": "Unknown"},
...     {"id": 1, "name": "Karan", "location": "San Francisco"},
...     {"id": 2, "name": "Matthew", "location": "Oakland"},
... ]
>>> hobbies = [
...     {"person_id": 1, "hobby": "Tennis"},
...     {"person_id": 1, "hobby": "Acting"},
...     {"person_id": 2, "hobby": "Biking"},
... ]
>>> list(keyjoin("id", people, "person_id", hobbies))
[{'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Tennis'}, {'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Acting'}, {'id': 2, 'name': 'Matthew', 'location': 'Oakland', 'person_id': 2, 'hobby': 'Biking'}]
Source code in src/liblaf/grapes/itertools/_toolz.py
def keyjoin[KT, VT](
    leftkey: KT,
    leftseq: Iterable[Mapping[KT, VT]],
    rightkey: KT,
    rightseq: Iterable[Mapping[KT, VT]],
) -> Iterator[Mapping[KT, VT]]:
    """Inner join two sequences of dictionaries on specified keys, merging matches with right value precedence.

    Examples:
        >>> people = [
        ...     {"id": 0, "name": "Anonymous Guy", "location": "Unknown"},
        ...     {"id": 1, "name": "Karan", "location": "San Francisco"},
        ...     {"id": 2, "name": "Matthew", "location": "Oakland"},
        ... ]
        >>> hobbies = [
        ...     {"person_id": 1, "hobby": "Tennis"},
        ...     {"person_id": 1, "hobby": "Acting"},
        ...     {"person_id": 2, "hobby": "Biking"},
        ... ]
        >>> list(keyjoin("id", people, "person_id", hobbies))
        [{'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Tennis'}, {'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Acting'}, {'id': 2, 'name': 'Matthew', 'location': 'Oakland', 'person_id': 2, 'hobby': 'Biking'}]
    """
    return itertools.starmap(tlz.merge, tlz.join(leftkey, leftseq, rightkey, rightseq))

len_or_none

len_or_none(iterable: Iterable) -> int | None
Source code in src/liblaf/grapes/itertools/_len_or_none.py
4
5
6
7
8
def len_or_none(iterable: Iterable) -> int | None:
    try:
        return len(iterable)  # pyright: ignore[reportArgumentType]
    except TypeError:
        return None

load

load(
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
) -> Any
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: type[T],
) -> T
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: Any,
) -> Any
Source code in src/liblaf/grapes/serde/_load.py
def load(path: StrPath, /, *, force_ext: str | None = None, **kwargs) -> Any:
    path = Path(path)
    ext: str = force_ext or path.suffix
    return readers[ext](path, **kwargs)

memorize

memorize[**P, T](
    func: Callable[P, T],
    /,
    *,
    memory: Memory | None = ...,
    ignore: list[str] | None = ...,
    verbose: int | None = ...,
    mmap_mode: Literal["r+", "r", "w+", "c"] | None = ...,
    cache_validation_callback: Callable[[Metadata], bool]
    | None = ...,
    bytes_limit: int | str | None = ...,
    items_limit: int | None = ...,
    age_limit: timedelta | None = ...,
) -> MemorizedFunc[P, T]
memorize[**P, T](
    *,
    memory: Memory | None = None,
    ignore: list[str] | None = ...,
    verbose: int | None = ...,
    mmap_mode: Literal["r+", "r", "w+", "c"] | None = ...,
    cache_validation_callback: Callable[[Metadata], bool]
    | None = ...,
    bytes_limit: int | str | None = ...,
    items_limit: int | None = ...,
    age_limit: timedelta | None = ...,
) -> Callable[[Callable[P, T]], MemorizedFunc[P, T]]
Source code in src/liblaf/grapes/functools/_memorize.py
def memorize(func: Callable | None = None, /, **kwargs: Any) -> Any:
    if func is None:
        return functools.partial(memorize, **kwargs)
    memory: joblib.Memory | None = kwargs.pop("memory", None)
    if memory is None:
        memory = make_memory()
    cache_kwargs: dict[str, Any] = pick(
        {"ignore", "verbose", "mmap_mode", "cache_validation_callback"}, kwargs
    )
    reduce_size_kwargs: dict[str, Any] = pick(
        {"bytes_limit", "items_limit", "age_limit"}, kwargs
    )
    reduce_size_kwargs.setdefault("bytes_limit", config.joblib.memory.bytes_limit.get())

    @wrapt.decorator
    def wrapper[**P, T](
        wrapped: Callable[P, T],
        _instance: Any,
        args: tuple[Any, ...],
        kwargs: dict[str, Any],
    ) -> T:
        result: Any = wrapped(*args, **kwargs)
        memory.reduce_size(**reduce_size_kwargs)
        return result

    func = memory.cache(func, **cache_kwargs)
    func = wrapper(func)
    wrapt_setattr(func, "memory", memory)
    return func

omit

omit[KT, VT](
    denylist: Container[KT], dictionary: Mapping[KT, VT]
) -> dict[KT, VT]

Return a subset of the provided dictionary with keys not contained in the denylist.

Examples:

>>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
>>> omit(["a", "b"], alphabet)
{'c': 3, 'd': 4}
Source code in src/liblaf/grapes/itertools/_toolz.py
def omit[KT, VT](denylist: Container[KT], dictionary: Mapping[KT, VT]) -> dict[KT, VT]:
    """Return a subset of the provided dictionary with keys not contained in the denylist.

    Examples:
        >>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
        >>> omit(["a", "b"], alphabet)
        {'c': 3, 'd': 4}
    """
    return tlz.keyfilter(lambda k: k not in denylist, dictionary)

optional_deps

optional_deps(
    package: str | None = None, extra: str | None = None
) -> Generator[None]
Source code in src/liblaf/grapes/deps/_optional.py
@contextlib.contextmanager
def optional_deps(
    package: str | None = None, extra: str | None = None
) -> Generator[None]:
    try:
        yield
    except ImportError as err:
        raise MissingOptionalDependencyError(
            err, package=package, extra=extra
        ) from None

pdoc

pdoc(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pdoc.py
@wraps(wl.pdoc)
def pdoc(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> wl.AbstractDoc:
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pdoc(obj, **kwargs)

pformat

pformat(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> str

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pformat.py
@wraps(wl.pformat)
def pformat(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> str:
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pformat(obj, **kwargs)

pick

pick[KT, VT](
    allowlist: Container[KT], dictionary: Mapping[KT, VT]
) -> dict[KT, VT]

Return a subset of the provided dictionary with keys contained in the allowlist.

Examples:

>>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
>>> pick(["a", "b"], alphabet)
{'a': 1, 'b': 2}
Source code in src/liblaf/grapes/itertools/_toolz.py
def pick[KT, VT](allowlist: Container[KT], dictionary: Mapping[KT, VT]) -> dict[KT, VT]:
    """Return a subset of the provided dictionary with keys contained in the allowlist.

    Examples:
        >>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
        >>> pick(["a", "b"], alphabet)
        {'a': 1, 'b': 2}
    """
    return tlz.keyfilter(lambda k: k in allowlist, dictionary)

pprint

pprint(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> None

Pretty-prints an object to stdout.

Examples:

array:

>>> import numpy as np
>>> pprint(np.zeros((2, 3)))
array([[0., 0., 0.],
       [0., 0., 0.]])
>>> pprint(np.zeros((20, 30)))
f64[20,30](numpy)

datetime:

>>> import datetime
>>> pprint(datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC))
1970-01-01T00:00:00+00:00

dataclass:

>>> import dataclasses
>>> import numpy as np
>>> @dataclasses.dataclass
... class MyDataclass:
...     x: list[str]
...     y: np.ndarray
>>> obj = MyDataclass(["lorem", "ipsum", "dolor sit amet"], np.zeros((2, 3)))
>>> pprint(obj, width=30, indent=4)
MyDataclass(
    x=[
        'lorem',
        'ipsum',
        'dolor sit amet'
    ],
    y=array([[0., 0., 0.],
             [0., 0., 0.]])
)

dict:

>>> pprint({"jack": 4098, "sjoerd": 4127})
{'jack': 4098, 'sjoerd': 4127}

pydantic:

>>> import pydantic
>>> class MyModel(pydantic.RootModel[list[str]]): ...
>>> obj = MyModel(["lorem", "ipsum", "dolor sit amet"])
>>> pprint(obj)
MyModel['lorem', 'ipsum', 'dolor sit amet']

rich.repr:

>>> import rich
>>> class Bird:
...     def __rich_repr__(self):
...         yield "penguin"
...         yield "eats", ["fish"]
...         yield "fly", False, True
...         yield "extinct", False, False
>>> pprint(Bird())
Bird('penguin', eats=['fish'], fly=False)

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pprint.py
def pprint(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> None:
    """Pretty-prints an object to stdout.

    Examples:
        array:

        >>> import numpy as np
        >>> pprint(np.zeros((2, 3)))
        array([[0., 0., 0.],
               [0., 0., 0.]])
        >>> pprint(np.zeros((20, 30)))
        f64[20,30](numpy)

        datetime:

        >>> import datetime
        >>> pprint(datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC))
        1970-01-01T00:00:00+00:00

        dataclass:

        >>> import dataclasses
        >>> import numpy as np
        >>> @dataclasses.dataclass
        ... class MyDataclass:
        ...     x: list[str]
        ...     y: np.ndarray
        >>> obj = MyDataclass(["lorem", "ipsum", "dolor sit amet"], np.zeros((2, 3)))
        >>> pprint(obj, width=30, indent=4)
        MyDataclass(
            x=[
                'lorem',
                'ipsum',
                'dolor sit amet'
            ],
            y=array([[0., 0., 0.],
                     [0., 0., 0.]])
        )

        dict:

        >>> pprint({"jack": 4098, "sjoerd": 4127})
        {'jack': 4098, 'sjoerd': 4127}

        pydantic:

        >>> import pydantic
        >>> class MyModel(pydantic.RootModel[list[str]]): ...
        >>> obj = MyModel(["lorem", "ipsum", "dolor sit amet"])
        >>> pprint(obj)
        MyModel['lorem', 'ipsum', 'dolor sit amet']

        rich.repr:

        >>> import rich
        >>> class Bird:
        ...     def __rich_repr__(self):
        ...         yield "penguin"
        ...         yield "eats", ["fish"]
        ...         yield "fly", False, True
        ...         yield "extinct", False, False
        >>> pprint(Bird())
        Bird('penguin', eats=['fish'], fly=False)
    """
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pprint(obj, **kwargs)

pretty_call

pretty_call(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
    **wl_kwargs,
) -> str

.

Examples:

>>> def foo(a: int, b: int, c: int = 3): ...
>>> print(pretty_call(foo, (1, 2), {"c": 4}))
foo(1, 2, 4)
Source code in src/liblaf/grapes/pretty/_call.py
def pretty_call(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
    **wl_kwargs,
) -> str:
    """.

    Examples:
        >>> def foo(a: int, b: int, c: int = 3): ...
        >>> print(pretty_call(foo, (1, 2), {"c": 4}))
        foo(1, 2, 4)
    """
    func = inspect.unwrap(func)
    args, kwargs = _bind_safe(func, args, kwargs)
    return pformat(PrettyCall(get_name(func), args, kwargs), **wl_kwargs)

pretty_duration

pretty_duration(
    seconds: float, *, prec: int = 2, **kwargs
) -> str

.

Examples:

>>> pretty_duration(0.1234)
'123. ms'
>>> pretty_duration(0.01234)
'12.3 ms'
Source code in src/liblaf/grapes/pretty/_duration.py
def pretty_duration(seconds: float, *, prec: int = 2, **kwargs) -> str:
    """.

    Examples:
        >>> pretty_duration(0.1234)
        '123. ms'
        >>> pretty_duration(0.01234)
        '12.3 ms'
    """
    return pretty_quantity(seconds, "s", prec=prec, **kwargs)

pretty_durations

pretty_durations(
    seconds: Iterable[float], *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents

.

Examples:

>>> pretty_durations([0.1234, 0.01234, 0.001234])
PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
Source code in src/liblaf/grapes/pretty/_duration.py
def pretty_durations(
    seconds: Iterable[float], *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents:
    """.

    Examples:
        >>> pretty_durations([0.1234, 0.01234, 0.001234])
        PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
    """
    return pretty_quantities(seconds, "s", prec=prec, **kwargs)

pretty_func

pretty_func(func: Callable) -> str
Source code in src/liblaf/grapes/pretty/_func.py
6
7
8
def pretty_func(func: Callable, /) -> str:
    name: str = get_name(func)
    return f"{name}()"

pretty_quantities

pretty_quantities(
    values: Iterable[float],
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> PrettyQuantitiesComponents

.

Examples:

>>> pretty_quantities([0.1234, 0.01234, 0.001234], "s")
PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantities(
    values: Iterable[float], unit: str | None = None, *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents:
    """.

    Examples:
        >>> pretty_quantities([0.1234, 0.01234, 0.001234], "s")
        PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
    """
    unit_or_sentinel: str = unit or _SENTINEL_UNIT
    components: PrettyQuantityComponents = pretty_quantity_components(
        max(values), unit_or_sentinel, prec=prec, **kwargs
    )
    spacer: str = _get_spacer(unit)

    def number_fmt(whole: str, frac: str, _units: str) -> str:
        if not frac.startswith("."):
            frac = f".{frac}"
        return f"{whole}{frac}"

    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
        show_units=False,
    ):
        mantissas: list[str] = [
            quantiphy.fixed(
                value,
                unit_or_sentinel,
                prec=len(components.frac) - 1,
                scale=components.units,
            )
            for value in values
        ]
    units: str = components.units
    if unit is None:
        units = units.removesuffix(_SENTINEL_UNIT)
    return PrettyQuantitiesComponents(mantissas, spacer, units)

pretty_quantity

pretty_quantity(
    value: float,
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> str

.

Examples:

>>> pretty_quantity(0.1234, "s")
'123. ms'
>>> pretty_quantity(0.01234, "s")
'12.3 ms'
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantity(
    value: float, unit: str | None = None, *, prec: int = 2, **kwargs
) -> str:
    """.

    Examples:
        >>> pretty_quantity(0.1234, "s")
        '123. ms'
        >>> pretty_quantity(0.01234, "s")
        '12.3 ms'
    """
    spacer: str = _get_spacer(unit)

    def number_fmt(whole: str, frac: str, units: str) -> str:
        if not frac.startswith("."):
            frac = f".{frac}"
        mantissa: str = f"{whole}{frac}"
        return f"{mantissa}{spacer}{units}"

    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
    ):
        q: Quantity = Quantity(value) if unit is None else Quantity(value, unit)
        return q.render(prec=prec, **kwargs)

pretty_quantity_components

pretty_quantity_components(
    value: float,
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> PrettyQuantityComponents
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantity_components(
    value: float, unit: str | None = None, *, prec: int = 2, **kwargs
) -> PrettyQuantityComponents:
    number_fmt = _NumberFmt()
    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
    ):
        quantiphy.render(value, unit or _SENTINEL_UNIT, prec=prec, **kwargs)
    whole: str = number_fmt.whole
    frac: str = number_fmt.frac
    units: str = number_fmt.units
    if not frac.startswith("."):
        frac = f".{frac}"
    if unit is None:
        units = units.removesuffix(_SENTINEL_UNIT)
    return PrettyQuantityComponents(whole, frac, units)

pretty_throughput

pretty_throughput(value: float, unit: str = '') -> str

.

Examples:

>>> pretty_throughput(1234, "it")
'1.2kit/s'
Source code in src/liblaf/grapes/pretty/_throughput.py
def pretty_throughput(value: float, unit: str = "") -> str:
    """.

    Examples:
        >>> pretty_throughput(1234, "it")
        '1.2kit/s'
    """
    throughput: about_time.HumanThroughput = about_time.HumanThroughput(value, unit)
    return throughput.as_human()

save

save(
    path: StrPath,
    obj: Any,
    /,
    *,
    enc_hook: EncHook | None = ...,
    force_ext: str | None = None,
    order: Literal["deterministic", "sorted"] | None = None,
    pydantic: PydanticDumpOptions | None = None,
) -> None
Source code in src/liblaf/grapes/serde/_save.py
def save(path: StrPath, obj: Any, /, force_ext: str | None = None, **kwargs) -> None:
    path = Path(path)
    ext: str = force_ext or path.suffix
    return writers[ext](path, obj, **kwargs)

timer

timer(
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_finish: Callback | None = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
) -> Timer
timer[C: Callable](
    callable: C,
    /,
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
    cb_finish: Callback | None = ...,
) -> C
timer[I: Iterable](
    iterable: I,
    /,
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
    cb_finish: Callback | None = ...,
) -> I
Source code in src/liblaf/grapes/timing/_main.py
def timer(func_or_iterable: Callable | Iterable | None = None, /, **kwargs) -> Any:
    timer = Timer(**kwargs)
    if func_or_iterable is None:
        return timer
    return timer(func_or_iterable)

todo

todo(
    message: str = "not yet implemented",
    assignee: str | None = None,
) -> Never
Source code in src/liblaf/grapes/errors/_misc.py
def todo(message: str = "not yet implemented", assignee: str | None = None) -> Never:
    raise TodoError(message=message, assignee=assignee)

track

track[T](
    sequence: Iterable[T],
    total: float | None = None,
    completed: int = 0,
    description: str = "Working...",
    *,
    progress: Progress | None = None,
) -> Iterable[T]
Source code in src/liblaf/grapes/rich/progress/_track.py
def track[T](
    sequence: Iterable[T],
    total: float | None = None,
    completed: int = 0,
    description: str = "Working...",
    *,
    progress: Progress | None = None,
) -> Iterable[T]:
    _logging_hide = True
    if progress is None:
        progress = Progress()
    with progress:
        yield from progress.track(
            sequence, total=total, completed=completed, description=description
        )

unreachable

unreachable(message: str | None = None) -> Never
Source code in src/liblaf/grapes/errors/_misc.py
def unreachable(message: str | None = None) -> Never:
    raise UnreachableError(message=message)

warn

warn(*args, **kwargs) -> None
Source code in src/liblaf/grapes/warnings/_warn.py
@wraps(warnings.warn)
def warn(*args, **kwargs) -> None:
    _warnings_hide = True
    stacklevel: int = kwargs.get("stacklevel", 1)
    _, stacklevel = magic.get_frame_with_stacklevel(
        stacklevel, magic.hidden_from_warnings
    )
    kwargs["stacklevel"] = stacklevel
    return warnings.warn(*args, **kwargs)

wraps

wraps[C: Callable](
    wrapped: C,
    assigned: Iterable[str] = WRAPPER_ASSIGNMENTS,
    updated: Iterable[str] = WRAPPER_UPDATES,
) -> Callable[[Any], C]
Source code in src/liblaf/grapes/functools/_wraps.py
def wraps[C: Callable](wrapped: C, *args, **kwargs) -> Callable[[Any], C]:
    return functools.wraps(wrapped, *args, **kwargs)  # pyright: ignore[reportReturnType]

wrapt_getattr

wrapt_getattr(obj: Any, name: str) -> Any
wrapt_getattr[T](
    obj: Any, name: str, default: T
) -> Any | T
Source code in src/liblaf/grapes/functools/_wrapt.py
def wrapt_getattr(obj: Any, name: str, default: Any = MISSING, /) -> Any:
    name = f"_self_{name}"
    try:
        return getattr(obj, name)
    except AttributeError:
        parent: Any = getattr(obj, "_self_parent", None)
        if parent is None:
            if default is MISSING:
                raise
            return default
        if hasattr(parent, name):
            return getattr(parent, name)
        if default is MISSING:
            raise
        return default

wrapt_setattr

wrapt_setattr(obj: Any, name: str, value: Any) -> None
Source code in src/liblaf/grapes/functools/_wrapt.py
6
7
8
def wrapt_setattr(obj: Any, name: str, value: Any, /) -> None:
    name = f"_self_{name}"
    setattr(obj, name, value)

attrs

Functions:

define

define(maybe_cls: type | None = None, **kwargs) -> Any
Source code in src/liblaf/grapes/attrs/_define.py
@wraps(attrs.define)
def define(maybe_cls: type | None = None, **kwargs) -> Any:
    if maybe_cls is None:
        return functools.partial(define, **kwargs)
    cls: type = _preprocess(maybe_cls, kwargs)
    return attrs.define(cls, **kwargs)

frozen

frozen(maybe_cls: type | None = None, **kwargs) -> Any
Source code in src/liblaf/grapes/attrs/_define.py
@wraps(attrs.frozen)
def frozen(maybe_cls: type | None = None, **kwargs) -> Any:
    if maybe_cls is None:
        return functools.partial(frozen, **kwargs)
    cls: type = _preprocess(maybe_cls, kwargs)
    return attrs.frozen(cls, **kwargs)

bench

Classes:

BenchResults

Parameters:

Methods:

Attributes:

outputs instance-attribute

outputs: dict[str, list[Any]]

sizes instance-attribute

sizes: list[float]

timings instance-attribute

timings: dict[str, list[float]]

plot

plot(
    *,
    relative_to: str | None = None,
    xlabel: str = "Size",
    ylabel: str = "Time (sec)",
    log_scale: bool = True,
) -> Figure
Source code in src/liblaf/grapes/bench/_results.py
def plot(
    self,
    *,
    relative_to: str | None = None,
    xlabel: str = "Size",
    ylabel: str = "Time (sec)",
    log_scale: bool = True,
) -> Figure:
    with deps.optional_deps("liblaf-grapes", "bench"):
        import matplotlib.pyplot as plt

    if relative_to is None:
        relative_to = min(self.timings.keys(), key=lambda k: self.timings[k][-1])

    fig: Figure
    ax0: Axes
    ax1: Axes
    fig, (ax0, ax1) = plt.subplots(1, 2, sharex="all", figsize=(12.8, 4.8))

    for label, timings in self.timings.items():
        ax0.plot(self.sizes, timings, label=label)
        base: list[float] = self.timings[relative_to]
        relative: list[float] = [t / b for t, b in zip(timings, base, strict=True)]
        ax1.plot(self.sizes, relative, label=label)

    ax0.grid(which="both", linestyle="--")
    ax0.legend()
    ax0.set_xlabel(xlabel)
    ax0.set_ylabel(ylabel)

    ax1.grid(which="both", linestyle="--")
    ax1.legend()
    ax1.set_xlabel(xlabel)
    ax1.set_ylabel(f"{ylabel} (relative to {relative_to})")

    if log_scale:
        ax0.set_xscale("log")
        ax0.set_yscale("log")
        ax1.set_xscale("log")

    fig.tight_layout()
    return fig

Bencher

Parameters:

  • min_time

    (float, default: 0.2 ) –
  • timeout

    (float, default: 10.0 ) –
  • warmup

    (int, default: 1 ) –

Methods:

Attributes:

min_time class-attribute instance-attribute

min_time: float = 0.2

timeout class-attribute instance-attribute

timeout: float = 10.0

warmup class-attribute instance-attribute

warmup: int = 1

bench

bench[C: Callable](
    func: C, /, *, label: str | None = None
) -> C
bench[C: Callable](
    *, label: str | None = None
) -> Callable[[C], C]
Source code in src/liblaf/grapes/bench/_bencher.py
def bench(
    self, func: Callable | None = None, *, label: str | None = None
) -> Callable:
    if func is None:
        return functools.partial(self.bench, label=label)
    if label is None:
        label = func.__name__
    self._registry[label] = func
    return func

run

run() -> BenchResults
Source code in src/liblaf/grapes/bench/_bencher.py
def run(self) -> BenchResults:
    inputs: Sequence[tuple[Sequence, Mapping]] = list(self._setup())
    sizes_and_inputs: list[tuple[float, tuple[Sequence, Mapping]]] = [
        (self._size_fn(*args, **kwargs), (args, kwargs)) for args, kwargs in inputs
    ]
    sizes_and_inputs.sort(key=lambda x: x[0])
    sizes: Sequence[float] = [size for size, _ in sizes_and_inputs]
    inputs = [(args, kwargs) for _, (args, kwargs) in sizes_and_inputs]
    outputs: dict[str, list[Any]] = {}
    timings: dict[str, list[float]] = {}
    for label, func in self._registry.items():
        outputs_name: list[Any] = []
        timings_name: list[float] = []
        for size, (args, kwargs) in zip(sizes, inputs, strict=True):
            output: Any
            elapsed: float
            output, elapsed = self._bench(func, args, kwargs)
            outputs_name.append(output)
            timings_name.append(elapsed)
            logger.debug("Bench %s(%g) took %g sec", label, size, elapsed)
            if elapsed > self.timeout:
                logger.warning("Bench %s(%g) timed out", label, size)
                break
        if len(timings_name) < len(sizes):
            n_remain: int = len(sizes) - len(timings_name)
            outputs_name.extend([None] * n_remain)
            timings_name.extend([math.inf] * n_remain)
        timings[label] = timings_name
        outputs[label] = outputs_name
    return BenchResults(outputs=outputs, sizes=list(sizes), timings=timings)

setup

setup[
    C: Callable[..., Iterable[tuple[Sequence, Mapping]]]
](func: C) -> C
Source code in src/liblaf/grapes/bench/_bencher.py
def setup[C: Callable[..., Iterable[tuple[Sequence, Mapping]]]](self, func: C) -> C:
    self._setup = func
    return func

size

size[C: Callable[..., float]](func: C) -> C
Source code in src/liblaf/grapes/bench/_bencher.py
def size[C: Callable[..., float]](self, func: C) -> C:
    self._size_fn = func
    return func

compat

Functions:

contains

contains[T](
    obj: Container[T],
    key: T,
    deprecated_keys: Iterable[T] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> bool

.

Examples:

>>> import pytest
>>> data = {"a": 1, "b": 2}
>>> contains(data, "a")
True
>>> contains(data, "missing")
False
>>> with pytest.deprecated_call():
...     contains(data, "c", deprecated_keys=["missing", "b"])
True
Source code in src/liblaf/grapes/compat/_operator.py
def contains[T](
    obj: Container[T],
    key: T,
    deprecated_keys: Iterable[T] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> bool:
    """.

    Examples:
        >>> import pytest
        >>> data = {"a": 1, "b": 2}
        >>> contains(data, "a")
        True
        >>> contains(data, "missing")
        False
        >>> with pytest.deprecated_call():
        ...     contains(data, "c", deprecated_keys=["missing", "b"])
        True
    """
    _warnings_hide = True
    if key in obj:
        return True
    for deprecated_key in deprecated_keys:
        if deprecated_key in obj:
            warnings.warn(
                msg.format_map({"deprecated_key": deprecated_key, "key": key}),
                DeprecationWarning,
            )
            return True
    return False

getitem

getitem[KT, VT](
    obj: SupportsGetItem[KT, VT],
    key: KT,
    deprecated_keys: Iterable[KT] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> VT

.

Examples:

>>> import pytest
>>> data = {"a": 1, "b": 2}
>>> getitem(data, "a")
1
>>> with pytest.raises(KeyError):
...     getitem(data, "missing")
>>> with pytest.deprecated_call():
...     getitem(data, "c", deprecated_keys=["missing", "b"])
2
Source code in src/liblaf/grapes/compat/_operator.py
def getitem[KT, VT](
    obj: SupportsGetItem[KT, VT],
    key: KT,
    deprecated_keys: Iterable[KT] = (),
    *,
    msg: str = _DEPRECATED_MESSAGE,
) -> VT:
    """.

    Examples:
        >>> import pytest
        >>> data = {"a": 1, "b": 2}
        >>> getitem(data, "a")
        1
        >>> with pytest.raises(KeyError):
        ...     getitem(data, "missing")
        >>> with pytest.deprecated_call():
        ...     getitem(data, "c", deprecated_keys=["missing", "b"])
        2
    """
    _warnings_hide = True
    try:
        return obj[key]
    except KeyError:
        pass
    for deprecated_key in deprecated_keys:
        try:
            value: VT = obj[deprecated_key]
        except KeyError:
            continue
        warnings.warn(
            msg.format_map({"deprecated_key": deprecated_key, "key": key}),
            DeprecationWarning,
        )
        return value
    raise KeyError(key)

conf

Classes:

Functions:

Attributes:

METADATA_KEY module-attribute

METADATA_KEY = 'liblaf.grapes.conf'

bool module-attribute

bool: FieldMethod[bool] = FieldMethod(bool)

decimal module-attribute

decimal: FieldMethod[Decimal] = FieldMethod(decimal)

float module-attribute

float: FieldMethod[float] = FieldMethod(float)

int module-attribute

int: FieldMethod[int] = FieldMethod(int)

list module-attribute

path module-attribute

path: FieldMethod[Path] = FieldMethod(path)

str module-attribute

str: FieldMethod[str] = FieldMethod(str)

BaseConfig

BaseConfig(name: str = '')

.

Examples:

>>> from liblaf.grapes import conf
>>> class Config(BaseConfig):
...     a: conf.Field[int] = conf.int(default=0)
>>> config = Config()
>>> config.get()
{'a': 0}
>>> config.a.get()
0
>>> with config.a.overrides(1):
...     config.get()
{'a': 1}
>>> config.get()
{'a': 0}
>>> with config.overrides(a=1):
...     config.get()
{'a': 1}
>>> config.get()
{'a': 0}

Methods:

Source code in src/liblaf/grapes/conf/_config.py
def __init__(self, name: str = "") -> None:
    kwargs: dict[str, Any] = {}
    cls: type[BaseConfig] = type(self)
    cls = attrs.resolve_types(cls)
    prefix: str = f"{name}." if name else ""
    for field in attrs.fields(type(self)):
        field: attrs.Attribute
        entry: Entry | None = field.metadata.get(METADATA_KEY, None)
        if entry is None:
            continue
        kwargs[field.name] = entry.make(field, prefix)
    self.__attrs_init__(**kwargs)  # pyright: ignore[reportAttributeAccessIssue]

__pdoc__

__pdoc__(**kwargs) -> AbstractDoc | None
Source code in src/liblaf/grapes/conf/_config.py
def __pdoc__(self, **kwargs) -> wl.AbstractDoc | None:
    from liblaf.grapes.wadler_lindig import pdoc_rich_repr

    return pdoc_rich_repr(self, **kwargs)

__repr__

__repr__() -> str
Source code in src/liblaf/grapes/conf/_config.py
def __repr__(self) -> str:
    from liblaf.grapes.wadler_lindig import pformat

    return pformat(self)

__rich_repr__

__rich_repr__() -> RichReprResult
Source code in src/liblaf/grapes/conf/_config.py
def __rich_repr__(self) -> RichReprResult:
    from liblaf.grapes.rich.repr import rich_repr_fieldz

    yield from rich_repr_fieldz(self)

get

get() -> dict[str, Any]
Source code in src/liblaf/grapes/conf/_config.py
def get(self) -> dict[str, Any]:
    result: dict[str, Any] = {}
    for f in attrs.fields(type(self)):
        f: attrs.Attribute
        value: Any = getattr(self, f.name)
        if isinstance(value, (BaseConfig, Field)):
            result[f.name] = value.get()
    return result

overrides

overrides(
    changes: Mapping[str, Any] = {}, /, **kwargs: Any
) -> Generator[Self]
Source code in src/liblaf/grapes/conf/_config.py
@contextlib.contextmanager
def overrides(
    self, changes: Mapping[str, Any] = {}, /, **kwargs: Any
) -> Generator[Self]:
    changes = tlz.merge(changes, kwargs)
    with contextlib.ExitStack() as stack:
        for key, value in changes.items():
            field: BaseConfig | Field = getattr(self, key)
            stack.enter_context(field.overrides(value))
        yield self

set

set(
    changes: Mapping[str, Any] = {}, /, **kwargs: Any
) -> None
Source code in src/liblaf/grapes/conf/_config.py
def set(self, changes: Mapping[str, Any] = {}, /, **kwargs: Any) -> None:
    changes = tlz.merge(changes, kwargs)
    for key, value in changes.items():
        field: BaseConfig | Field = getattr(self, key)
        field.set(value)

Entry

Bases: ABC


              flowchart TD
              liblaf.grapes.conf.Entry[Entry]

              

              click liblaf.grapes.conf.Entry href "" "liblaf.grapes.conf.Entry"
            

Methods:

make abstractmethod

make(field: Attribute, prefix: str) -> T
Source code in src/liblaf/grapes/conf/_entry.py
7
8
9
@abc.abstractmethod
def make(self, field: attrs.Attribute, prefix: str) -> T:
    raise NotImplementedError

Field

Field(
    name: str,
    *,
    default: T | MissingType = MISSING,
    env: str | None = None,
    factory: Callable[[], T] | None = None,
    getter: Callable[[str], T],
)

.

Examples:

>>> from environs import env
>>> a = Field("a", default=0, getter=env.int)
>>> a
Field(name='a', value=0)
>>> a.name
'a'
>>> a.get()
0
>>> with a.overrides(1):
...     a.get()
1
>>> a.get()
0
>>> a = Field("a", factory=lambda: 0, getter=env.int)
>>> a.get()
0

Methods:

Attributes:

Source code in src/liblaf/grapes/conf/_field.py
def __init__(
    self,
    name: str,
    *,
    default: T | MissingType = MISSING,
    env: str | None = None,
    factory: Callable[[], T] | None = None,
    getter: Callable[[str], T],
) -> None:
    value: T | MissingType = _get_value(
        name, default=default, env=env, factory=factory, getter=getter
    )
    var: contextvars.ContextVar[T]
    if value is MISSING:
        var = contextvars.ContextVar(name)
    else:
        value = cast("T", value)
        var = contextvars.ContextVar(name, default=value)
    self.__attrs_init__(var=var)  # pyright: ignore[reportAttributeAccessIssue]

name property

name: str

__pdoc__

__pdoc__(**kwargs) -> AbstractDoc | None
Source code in src/liblaf/grapes/conf/_field.py
def __pdoc__(self, **kwargs) -> wl.AbstractDoc | None:
    from liblaf.grapes.wadler_lindig import pdoc_rich_repr

    return pdoc_rich_repr(self, **kwargs)

__repr__

__repr__() -> str
Source code in src/liblaf/grapes/conf/_field.py
def __repr__(self) -> str:
    from liblaf.grapes.wadler_lindig import pformat

    return pformat(self)

__rich_repr__

__rich_repr__() -> RichReprResult
Source code in src/liblaf/grapes/conf/_field.py
def __rich_repr__(self) -> RichReprResult:
    yield "name", self.name
    yield "value", self.get()

get

get() -> T
Source code in src/liblaf/grapes/conf/_field.py
def get(self) -> T:
    return self._var.get()

overrides

overrides(value: T) -> Generator[T]
Source code in src/liblaf/grapes/conf/_field.py
@contextlib.contextmanager
def overrides(self, value: T, /) -> Generator[T]:
    token: contextvars.Token[T] = self._var.set(value)
    try:
        yield value
    finally:
        self._var.reset(token)

set

set(value: T) -> None
Source code in src/liblaf/grapes/conf/_field.py
def set(self, value: T, /) -> None:
    self._var.set(value)

FieldMethod

Parameters:

  • wrapped

    (FieldMethod[T]) –

Methods:

Attributes:

wrapped instance-attribute

wrapped: FieldMethod[T]

__call__

__call__(
    *,
    default: T,
    env: str | None = None,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[T]
__call__(
    *,
    default: None,
    env: str | None = None,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[T | None]
__call__(
    *,
    factory: Callable[[], T],
    env: str | None = None,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[T]
__call__(
    *,
    env: str | None = None,
    factory: None = None,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[T]

Parameters:

Source code in src/liblaf/grapes/conf/_field_method.py
def __call__(
    self,
    *,
    default: T | MissingType | None = MISSING,
    env: str | None = None,
    factory: Callable[[], T] | None = None,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[T] | Field[T | None]:
    return attrs.field(
        metadata={
            METADATA_KEY: VarEntry(
                getter=functools.partial(self.wrapped, **kwargs),
                default=default,
                factory=factory,
                env=env,
            )
        }
    )

GroupEntry

Bases: Entry[T]


              flowchart TD
              liblaf.grapes.conf.GroupEntry[GroupEntry]
              liblaf.grapes.conf._entry.Entry[Entry]

                              liblaf.grapes.conf._entry.Entry --> liblaf.grapes.conf.GroupEntry
                


              click liblaf.grapes.conf.GroupEntry href "" "liblaf.grapes.conf.GroupEntry"
              click liblaf.grapes.conf._entry.Entry href "" "liblaf.grapes.conf._entry.Entry"
            

Methods:

make

make(field: Attribute, prefix: str) -> T
Source code in src/liblaf/grapes/conf/_group.py
def make(self, field: attrs.Attribute, prefix: str) -> T:
    assert field.type is not None
    return field.type(f"{prefix}{field.name}")

ListFieldMethod

Parameters:

  • wrapped

    (ListFieldMethod) –

Methods:

Attributes:

wrapped instance-attribute

wrapped: ListFieldMethod

__call__

__call__(
    subcast: Subcast[T] | None = None,
    *,
    delimiter: str | None = None,
    env: str | None = None,
    factory: Callable[[], list[T]] | None = list,
    validate: Callable[[Any], Any]
    | Iterable[Callable[[Any], Any]]
    | None = ...,
) -> Field[list[T]]

Parameters:

Source code in src/liblaf/grapes/conf/_field_method.py
def __call__(
    self,
    subcast: environs.Subcast[T] | None = None,
    *,
    delimiter: str | None = None,
    env: str | None = None,
    factory: Callable[[], list[T]] | None = list,
    **kwargs: Unpack[BaseMethodKwargs],
) -> Field[list[T]]:
    return attrs.field(
        metadata={
            METADATA_KEY: VarEntry(
                getter=functools.partial(
                    self.wrapped, subcast=subcast, delimiter=delimiter, **kwargs
                ),
                factory=factory,
                env=env,
            )
        }
    )

VarEntry

Bases: Entry[Field[T]]


              flowchart TD
              liblaf.grapes.conf.VarEntry[VarEntry]
              liblaf.grapes.conf._entry.Entry[Entry]

                              liblaf.grapes.conf._entry.Entry --> liblaf.grapes.conf.VarEntry
                


              click liblaf.grapes.conf.VarEntry href "" "liblaf.grapes.conf.VarEntry"
              click liblaf.grapes.conf._entry.Entry href "" "liblaf.grapes.conf._entry.Entry"
            

Parameters:

Methods:

Attributes:

default class-attribute instance-attribute

default: T | MissingType = MISSING

env class-attribute instance-attribute

env: str | None = None

factory class-attribute instance-attribute

factory: Callable[[], T] | None = None

getter instance-attribute

getter: Callable[[str], T]

make

make(field: Attribute, prefix: str) -> Field[T]
Source code in src/liblaf/grapes/conf/_field_method.py
def make(self, field: attrs.Attribute, prefix: str) -> Field[T]:
    return Field(
        name=prefix + field.name,
        default=self.default,
        env=self.env,
        factory=self.factory,
        getter=self.getter,
    )

group

group() -> Any
Source code in src/liblaf/grapes/conf/_group.py
def group() -> Any:
    return attrs.field(metadata={METADATA_KEY: GroupEntry()})

deps

Functions:

optional_deps

optional_deps(
    package: str | None = None, extra: str | None = None
) -> Generator[None]
Source code in src/liblaf/grapes/deps/_optional.py
@contextlib.contextmanager
def optional_deps(
    package: str | None = None, extra: str | None = None
) -> Generator[None]:
    try:
        yield
    except ImportError as err:
        raise MissingOptionalDependencyError(
            err, package=package, extra=extra
        ) from None

errors

Classes:

Functions:

DispatchLookupError

DispatchLookupError(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
)

Bases: LookupError


              flowchart TD
              liblaf.grapes.errors.DispatchLookupError[DispatchLookupError]

              

              click liblaf.grapes.errors.DispatchLookupError href "" "liblaf.grapes.errors.DispatchLookupError"
            

Parameters:

Methods:

Attributes:

Source code in src/liblaf/grapes/errors/_dispatch.py
def __init__(
    self, func: Callable, args: Sequence[Any] = (), kwargs: Mapping[str, Any] = {}
) -> None:
    params = Params(args=args, kwargs=kwargs)
    self.__attrs_init__(func=func, params=params)  # pyright: ignore[reportAttributeAccessIssue]

func instance-attribute

func: Callable

params instance-attribute

params: Params

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_dispatch.py
def __str__(self) -> str:
    from liblaf.grapes import pretty

    pretty_call: str = pretty.pretty_call(
        self.func, self.params.args, self.params.kwargs
    )
    return f"`{pretty_call}` could not be resolved."

MatchError

Bases: ValueError


              flowchart TD
              liblaf.grapes.errors.MatchError[MatchError]

              

              click liblaf.grapes.errors.MatchError href "" "liblaf.grapes.errors.MatchError"
            

Parameters:

Methods:

Attributes:

typ class-attribute instance-attribute

typ: str | type = 'match'

value instance-attribute

value: Any

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_match.py
def __str__(self) -> str:
    cls: str = self.typ if isinstance(self.typ, str) else self.typ.__qualname__
    return f"{self.value!r} is not a valid {cls}."

TodoError

Bases: NotImplementedError


              flowchart TD
              liblaf.grapes.errors.TodoError[TodoError]

              

              click liblaf.grapes.errors.TodoError href "" "liblaf.grapes.errors.TodoError"
            

Parameters:

  • message

    (str, default: 'not yet implemented' ) –
  • assignee

    (str | None, default: None ) –

Methods:

Attributes:

assignee class-attribute instance-attribute

assignee: str | None = None

message class-attribute instance-attribute

message: str = 'not yet implemented'

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_misc.py
def __str__(self) -> str:
    msg: str = "TODO"
    if self.assignee:
        msg += f"({self.assignee})"
    msg += f": {self.message}"
    return msg

UnreachableError

Bases: AssertionError


              flowchart TD
              liblaf.grapes.errors.UnreachableError[UnreachableError]

              

              click liblaf.grapes.errors.UnreachableError href "" "liblaf.grapes.errors.UnreachableError"
            

Parameters:

  • message

    (str | None, default: None ) –

Methods:

Attributes:

message class-attribute instance-attribute

message: str | None = None

__str__

__str__() -> str
Source code in src/liblaf/grapes/errors/_misc.py
def __str__(self) -> str:
    msg: str = "internal error: entered unreachable code"
    if self.message:
        msg += f": {self.message}"
    return msg

todo

todo(
    message: str = "not yet implemented",
    assignee: str | None = None,
) -> Never
Source code in src/liblaf/grapes/errors/_misc.py
def todo(message: str = "not yet implemented", assignee: str | None = None) -> Never:
    raise TodoError(message=message, assignee=assignee)

unreachable

unreachable(message: str | None = None) -> Never
Source code in src/liblaf/grapes/errors/_misc.py
def unreachable(message: str | None = None) -> Never:
    raise UnreachableError(message=message)

fieldz

Functions:

has_fields

has_fields(obj: Any) -> bool
Source code in src/liblaf/grapes/fieldz/_has_fields.py
def has_fields(obj: Any) -> bool:
    try:
        fieldz.get_adapter(obj)
    except TypeError:
        return False
    else:
        return True

functools

Classes:

Functions:

MemorizedFunc

Bases: Protocol


              flowchart TD
              liblaf.grapes.functools.MemorizedFunc[MemorizedFunc]

              

              click liblaf.grapes.functools.MemorizedFunc href "" "liblaf.grapes.functools.MemorizedFunc"
            

Methods:

Attributes:

func property

func: Callable[P, T]

__call__

__call__(*args: P.args, **kwargs: P.kwargs) -> T
Source code in src/liblaf/grapes/functools/_memorize.py
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ...

memorize

memorize[**P, T](
    func: Callable[P, T],
    /,
    *,
    memory: Memory | None = ...,
    ignore: list[str] | None = ...,
    verbose: int | None = ...,
    mmap_mode: Literal["r+", "r", "w+", "c"] | None = ...,
    cache_validation_callback: Callable[[Metadata], bool]
    | None = ...,
    bytes_limit: int | str | None = ...,
    items_limit: int | None = ...,
    age_limit: timedelta | None = ...,
) -> MemorizedFunc[P, T]
memorize[**P, T](
    *,
    memory: Memory | None = None,
    ignore: list[str] | None = ...,
    verbose: int | None = ...,
    mmap_mode: Literal["r+", "r", "w+", "c"] | None = ...,
    cache_validation_callback: Callable[[Metadata], bool]
    | None = ...,
    bytes_limit: int | str | None = ...,
    items_limit: int | None = ...,
    age_limit: timedelta | None = ...,
) -> Callable[[Callable[P, T]], MemorizedFunc[P, T]]
Source code in src/liblaf/grapes/functools/_memorize.py
def memorize(func: Callable | None = None, /, **kwargs: Any) -> Any:
    if func is None:
        return functools.partial(memorize, **kwargs)
    memory: joblib.Memory | None = kwargs.pop("memory", None)
    if memory is None:
        memory = make_memory()
    cache_kwargs: dict[str, Any] = pick(
        {"ignore", "verbose", "mmap_mode", "cache_validation_callback"}, kwargs
    )
    reduce_size_kwargs: dict[str, Any] = pick(
        {"bytes_limit", "items_limit", "age_limit"}, kwargs
    )
    reduce_size_kwargs.setdefault("bytes_limit", config.joblib.memory.bytes_limit.get())

    @wrapt.decorator
    def wrapper[**P, T](
        wrapped: Callable[P, T],
        _instance: Any,
        args: tuple[Any, ...],
        kwargs: dict[str, Any],
    ) -> T:
        result: Any = wrapped(*args, **kwargs)
        memory.reduce_size(**reduce_size_kwargs)
        return result

    func = memory.cache(func, **cache_kwargs)
    func = wrapper(func)
    wrapt_setattr(func, "memory", memory)
    return func

wraps

wraps[C: Callable](
    wrapped: C,
    assigned: Iterable[str] = WRAPPER_ASSIGNMENTS,
    updated: Iterable[str] = WRAPPER_UPDATES,
) -> Callable[[Any], C]
Source code in src/liblaf/grapes/functools/_wraps.py
def wraps[C: Callable](wrapped: C, *args, **kwargs) -> Callable[[Any], C]:
    return functools.wraps(wrapped, *args, **kwargs)  # pyright: ignore[reportReturnType]

wrapt_getattr

wrapt_getattr(obj: Any, name: str) -> Any
wrapt_getattr[T](
    obj: Any, name: str, default: T
) -> Any | T
Source code in src/liblaf/grapes/functools/_wrapt.py
def wrapt_getattr(obj: Any, name: str, default: Any = MISSING, /) -> Any:
    name = f"_self_{name}"
    try:
        return getattr(obj, name)
    except AttributeError:
        parent: Any = getattr(obj, "_self_parent", None)
        if parent is None:
            if default is MISSING:
                raise
            return default
        if hasattr(parent, name):
            return getattr(parent, name)
        if default is MISSING:
            raise
        return default

wrapt_setattr

wrapt_setattr(obj: Any, name: str, value: Any) -> None
Source code in src/liblaf/grapes/functools/_wrapt.py
6
7
8
def wrapt_setattr(obj: Any, name: str, value: Any, /) -> None:
    name = f"_self_{name}"
    setattr(obj, name, value)

icecream

Classes:

Functions:

Attributes:

ICECREAM module-attribute

ICECREAM: int = 15

ICON module-attribute

ICON: str = '🍦'

ic module-attribute

IceCreamDebugger

Parameters:

  • enabled

    (bool, default: True ) –

Methods:

Attributes:

enabled class-attribute instance-attribute

enabled: bool = True

__call__

__call__(**kwargs) -> None
__call__[T](arg: T, **kwargs) -> T
__call__[T1, T2, *Ts](
    arg1: T1, arg2: T2, *args: *Ts, **kwargs
) -> tuple[T1, T2, *Ts]
Source code in src/liblaf/grapes/icecream/_icecream.py
def __call__(self, *args, **kwargs) -> Any:
    if self.enabled:
        frame: types.FrameType | None = magic.get_frame(depth=2)
        logger: logging.Logger = self._get_logger(frame)
        logger.log(ICECREAM, self._format(args, kwargs, frame), stacklevel=2)
    match len(args):
        case 0:
            return None
        case 1:
            return args[0]
        case _:
            return args

install

install() -> None
Source code in src/liblaf/grapes/icecream/_install.py
def install() -> None:
    from liblaf.grapes.logging import init

    init()
    builtins.ic = ic  # pyright: ignore[reportAttributeAccessIssue]

itertools

Functions:

  • areidentical

    Determine if sequences are identical element-wise. This lazily evaluates the sequences and stops as soon as the result is determined.

  • as_iterable

    .

  • as_sequence

    .

  • compact

    Filter an iterable on "truthy" values.

  • first_not_none

    Returns the first not None value in the args.

  • keyjoin

    Inner join two sequences of dictionaries on specified keys, merging matches with right value precedence.

  • len_or_none
  • omit

    Return a subset of the provided dictionary with keys not contained in the denylist.

  • pick

    Return a subset of the provided dictionary with keys contained in the allowlist.

areidentical

areidentical(*seqs: Iterable[Any]) -> bool

Determine if sequences are identical element-wise. This lazily evaluates the sequences and stops as soon as the result is determined.

Examples:

>>> areidentical([1, 2, 3], (1, 2, 3))
True
>>> areidentical([1, 2, 3], [1, 2])
False
Source code in src/liblaf/grapes/itertools/_toolz.py
def areidentical(*seqs: Iterable[Any]) -> bool:
    """Determine if sequences are identical element-wise. This lazily evaluates the sequences and stops as soon as the result is determined.

    Examples:
        >>> areidentical([1, 2, 3], (1, 2, 3))
        True

        >>> areidentical([1, 2, 3], [1, 2])
        False
    """
    return not any(tlz.diff(*seqs, default=object()))

as_iterable

as_iterable(
    obj: Any, base_type: ClassInfo | None = (str, bytes)
) -> Iterable

.

Examples:

If obj is iterable, return an iterator over its items:

>>> obj = (1, 2, 3)
>>> as_iterable(obj)
(1, 2, 3)

If obj is not iterable, return a one-item iterable containing obj:

>>> obj = 1
>>> as_iterable(obj)
(1,)

If obj is None, return an empty iterable:

>>> obj = None
>>> as_iterable(None)
()

By default, binary and text strings are not considered iterable:

>>> obj = "foo"
>>> as_iterable(obj)
('foo',)

If base_type is set, objects for which isinstance(obj, base_type) returns True won't be considered iterable.

>>> obj = {"a": 1}
>>> as_iterable(obj)
{'a': 1}
>>> as_iterable(obj, base_type=dict)  # Treat dicts as a unit
({'a': 1},)

Set base_type to None to avoid any special handling and treat objects Python considers iterable as iterable:

>>> obj = "foo"
>>> as_iterable(obj, base_type=None)
'foo'
References
  1. more_itertools.always_iterable
Source code in src/liblaf/grapes/itertools/_as_iterable.py
def as_iterable(obj: Any, base_type: ClassInfo | None = (str, bytes)) -> Iterable:
    """.

    Examples:
        If `obj` is iterable, return an iterator over its items:

        >>> obj = (1, 2, 3)
        >>> as_iterable(obj)
        (1, 2, 3)

        If `obj` is not iterable, return a one-item iterable containing `obj`:

        >>> obj = 1
        >>> as_iterable(obj)
        (1,)

        If `obj` is `None`, return an empty iterable:

        >>> obj = None
        >>> as_iterable(None)
        ()

        By default, binary and text strings are not considered iterable:

        >>> obj = "foo"
        >>> as_iterable(obj)
        ('foo',)

        If `base_type` is set, objects for which `isinstance(obj, base_type)` returns ``True`` won't be considered iterable.

        >>> obj = {"a": 1}
        >>> as_iterable(obj)
        {'a': 1}
        >>> as_iterable(obj, base_type=dict)  # Treat dicts as a unit
        ({'a': 1},)

        Set `base_type` to `None` to avoid any special handling and treat objects Python considers iterable as iterable:

        >>> obj = "foo"
        >>> as_iterable(obj, base_type=None)
        'foo'

    References:
        1. [`more_itertools.always_iterable`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable)
    """
    if obj is None:
        return ()
    if base_type is not None and isinstance(obj, base_type):
        return (obj,)
    if isinstance(obj, Iterable):
        return obj
    return (obj,)

as_sequence

as_sequence(
    obj: Any, base_type: ClassInfo | None = (str, bytes)
) -> Sequence

.

Examples:

If obj is iterable, return an iterator over its items:

>>> obj = (1, 2, 3)
>>> as_sequence(obj)
(1, 2, 3)

If obj is not iterable, return a one-item iterable containing obj:

>>> obj = 1
>>> as_sequence(obj)
(1,)

If obj is None, return an empty iterable:

>>> obj = None
>>> as_sequence(None)
()

By default, binary and text strings are not considered iterable:

>>> obj = "foo"
>>> as_sequence(obj)
('foo',)

If base_type is set, objects for which isinstance(obj, base_type) returns True won't be considered iterable.

>>> obj = {"a": 1}
>>> as_sequence(obj)
({'a': 1},)
>>> as_sequence(obj, base_type=dict)  # Treat dicts as a unit
({'a': 1},)

Set base_type to None to avoid any special handling and treat objects Python considers iterable as iterable:

>>> obj = "foo"
>>> as_sequence(obj, base_type=None)
'foo'
References
  1. more_itertools.always_iterable
Source code in src/liblaf/grapes/itertools/_as_sequence.py
def as_sequence(obj: Any, base_type: ClassInfo | None = (str, bytes)) -> Sequence:
    """.

    Examples:
        If `obj` is iterable, return an iterator over its items:

        >>> obj = (1, 2, 3)
        >>> as_sequence(obj)
        (1, 2, 3)

        If `obj` is not iterable, return a one-item iterable containing `obj`:

        >>> obj = 1
        >>> as_sequence(obj)
        (1,)

        If `obj` is `None`, return an empty iterable:

        >>> obj = None
        >>> as_sequence(None)
        ()

        By default, binary and text strings are not considered iterable:

        >>> obj = "foo"
        >>> as_sequence(obj)
        ('foo',)

        If `base_type` is set, objects for which `isinstance(obj, base_type)` returns ``True`` won't be considered iterable.

        >>> obj = {"a": 1}
        >>> as_sequence(obj)
        ({'a': 1},)
        >>> as_sequence(obj, base_type=dict)  # Treat dicts as a unit
        ({'a': 1},)

        Set `base_type` to `None` to avoid any special handling and treat objects Python considers iterable as iterable:

        >>> obj = "foo"
        >>> as_sequence(obj, base_type=None)
        'foo'

    References:
        1. [`more_itertools.always_iterable`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable)
    """
    if obj is None:
        return ()
    if base_type is not None and isinstance(obj, base_type):
        return (obj,)
    if isinstance(obj, Sequence):
        return obj
    return (obj,)

compact

compact[T](iterable: Iterable[T | None]) -> Iterator[T]

Filter an iterable on "truthy" values.

Examples:

>>> results = [0, 1, 2, None, 3, False]
>>> list(compact(results))
[1, 2, 3]
Source code in src/liblaf/grapes/itertools/_toolz.py
def compact[T](iterable: Iterable[T | None]) -> Iterator[T]:
    """Filter an iterable on "truthy" values.

    Examples:
        >>> results = [0, 1, 2, None, 3, False]
        >>> list(compact(results))
        [1, 2, 3]
    """
    return tlz.filter(None, iterable)

first_not_none

first_not_none[T](*args: T | None) -> T

Returns the first not None value in the args.

Examples:

>>> first_not_none(1, 2)
1
>>> first_not_none(None, 1)
1
References
  1. more_itertools.first_true
Source code in src/liblaf/grapes/itertools/_first_not_none.py
def first_not_none[T](*args: T | None) -> T:
    """Returns the first `not None` value in the `args`.

    Examples:
        >>> first_not_none(1, 2)
        1
        >>> first_not_none(None, 1)
        1

    References:
        1. [`more_itertools.first_true`](https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first_true)
    """
    return next(arg for arg in args if arg is not None)

keyjoin

keyjoin[KT, VT](
    leftkey: KT,
    leftseq: Iterable[Mapping[KT, VT]],
    rightkey: KT,
    rightseq: Iterable[Mapping[KT, VT]],
) -> Iterator[Mapping[KT, VT]]

Inner join two sequences of dictionaries on specified keys, merging matches with right value precedence.

Examples:

>>> people = [
...     {"id": 0, "name": "Anonymous Guy", "location": "Unknown"},
...     {"id": 1, "name": "Karan", "location": "San Francisco"},
...     {"id": 2, "name": "Matthew", "location": "Oakland"},
... ]
>>> hobbies = [
...     {"person_id": 1, "hobby": "Tennis"},
...     {"person_id": 1, "hobby": "Acting"},
...     {"person_id": 2, "hobby": "Biking"},
... ]
>>> list(keyjoin("id", people, "person_id", hobbies))
[{'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Tennis'}, {'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Acting'}, {'id': 2, 'name': 'Matthew', 'location': 'Oakland', 'person_id': 2, 'hobby': 'Biking'}]
Source code in src/liblaf/grapes/itertools/_toolz.py
def keyjoin[KT, VT](
    leftkey: KT,
    leftseq: Iterable[Mapping[KT, VT]],
    rightkey: KT,
    rightseq: Iterable[Mapping[KT, VT]],
) -> Iterator[Mapping[KT, VT]]:
    """Inner join two sequences of dictionaries on specified keys, merging matches with right value precedence.

    Examples:
        >>> people = [
        ...     {"id": 0, "name": "Anonymous Guy", "location": "Unknown"},
        ...     {"id": 1, "name": "Karan", "location": "San Francisco"},
        ...     {"id": 2, "name": "Matthew", "location": "Oakland"},
        ... ]
        >>> hobbies = [
        ...     {"person_id": 1, "hobby": "Tennis"},
        ...     {"person_id": 1, "hobby": "Acting"},
        ...     {"person_id": 2, "hobby": "Biking"},
        ... ]
        >>> list(keyjoin("id", people, "person_id", hobbies))
        [{'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Tennis'}, {'id': 1, 'name': 'Karan', 'location': 'San Francisco', 'person_id': 1, 'hobby': 'Acting'}, {'id': 2, 'name': 'Matthew', 'location': 'Oakland', 'person_id': 2, 'hobby': 'Biking'}]
    """
    return itertools.starmap(tlz.merge, tlz.join(leftkey, leftseq, rightkey, rightseq))

len_or_none

len_or_none(iterable: Iterable) -> int | None
Source code in src/liblaf/grapes/itertools/_len_or_none.py
4
5
6
7
8
def len_or_none(iterable: Iterable) -> int | None:
    try:
        return len(iterable)  # pyright: ignore[reportArgumentType]
    except TypeError:
        return None

omit

omit[KT, VT](
    denylist: Container[KT], dictionary: Mapping[KT, VT]
) -> dict[KT, VT]

Return a subset of the provided dictionary with keys not contained in the denylist.

Examples:

>>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
>>> omit(["a", "b"], alphabet)
{'c': 3, 'd': 4}
Source code in src/liblaf/grapes/itertools/_toolz.py
def omit[KT, VT](denylist: Container[KT], dictionary: Mapping[KT, VT]) -> dict[KT, VT]:
    """Return a subset of the provided dictionary with keys not contained in the denylist.

    Examples:
        >>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
        >>> omit(["a", "b"], alphabet)
        {'c': 3, 'd': 4}
    """
    return tlz.keyfilter(lambda k: k not in denylist, dictionary)

pick

pick[KT, VT](
    allowlist: Container[KT], dictionary: Mapping[KT, VT]
) -> dict[KT, VT]

Return a subset of the provided dictionary with keys contained in the allowlist.

Examples:

>>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
>>> pick(["a", "b"], alphabet)
{'a': 1, 'b': 2}
Source code in src/liblaf/grapes/itertools/_toolz.py
def pick[KT, VT](allowlist: Container[KT], dictionary: Mapping[KT, VT]) -> dict[KT, VT]:
    """Return a subset of the provided dictionary with keys contained in the allowlist.

    Examples:
        >>> alphabet = {"a": 1, "b": 2, "c": 3, "d": 4}
        >>> pick(["a", "b"], alphabet)
        {'a': 1, 'b': 2}
    """
    return tlz.keyfilter(lambda k: k in allowlist, dictionary)

logging

Modules:

Classes:

Functions:

Attributes:

autolog module-attribute

autolog: Logger = AutoLogger()

CleanLogger

CleanLogger(name: str, level: int | str = NOTSET)

Bases: Logger


              flowchart TD
              liblaf.grapes.logging.CleanLogger[CleanLogger]

              

              click liblaf.grapes.logging.CleanLogger href "" "liblaf.grapes.logging.CleanLogger"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_logger.py
def __init__(self, name: str, level: int | str = logging.NOTSET) -> None:
    _logging_hide = True
    super().__init__(name, level)
    if level != logging.NOTSET:
        return
    module: types.ModuleType | None = sys.modules.get(name)
    file: str | None = None
    if module is not None:
        file = getattr(module, "__file__", None)
    if file is None:
        frame: types.FrameType | None = magic.get_frame(
            hidden=magic.hidden_from_logging
        )
        if frame is not None:
            file = frame.f_code.co_filename
    if magic.is_dev_release(file, name):
        self.setLevel(self.dev_level)
    elif magic.is_pre_release(file, name):
        self.setLevel(self.pre_level)

dev_level class-attribute

dev_level: int | str = 1

pre_level class-attribute

pre_level: int | str = DEBUG

propagate property writable

propagate: bool

addHandler

addHandler(hdlr: Handler) -> None
Source code in src/liblaf/grapes/logging/helpers/_logger.py
@override
def addHandler(self, hdlr: logging.Handler) -> None:
    if self.name != "root" and isinstance(hdlr, logging.StreamHandler):
        return
    super().addHandler(hdlr)

LazyRepr

LazyRepr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs

__wrapped__ cached property

__wrapped__: str

args instance-attribute

args = args

func instance-attribute

func: Callable[P, str] = func

kwargs instance-attribute

kwargs = kwargs

__repr__

__repr__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __repr__(self) -> str:
    return self.__wrapped__

LazyStr

LazyStr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs

__wrapped__ cached property

__wrapped__: str

args instance-attribute

args = args

func instance-attribute

func: Callable[P, str] = func

kwargs instance-attribute

kwargs = kwargs

__str__

__str__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __str__(self) -> str:
    return self.__wrapped__

LimitsFilter

Parameters:

  • limiter

    (RateLimiter, default: <limits.strategies.FixedWindowRateLimiter object at 0x7f8a2e5730e0> ) –

Methods:

Attributes:

limiter class-attribute instance-attribute

limiter: RateLimiter = field(
    factory=lambda: FixedWindowRateLimiter(MemoryStorage())
)

filter

filter(record: LogRecord) -> bool
Source code in src/liblaf/grapes/logging/filters/_limits.py
def filter(self, record: logging.LogRecord) -> bool:
    args: Any = getattr(record, "limits", None)
    if args is None:
        return True
    hit_args: LimitsHitArgs = _parse_args_cache(args)
    if hit_args.item is None:
        return True
    identifiers: Sequence[str] = hit_args.make_identifiers(record)
    return self.limiter.hit(hit_args.item, *identifiers, cost=hit_args.cost)

LimitsHitArgs

Parameters:

  • item

    (RateLimitItem | None) –
  • namespace

    (Iterable[str] | None, default: None ) –
  • identifiers

    (Iterable[str], default: () ) –
  • cost

    (int, default: 1 ) –

Methods:

Attributes:

cost class-attribute instance-attribute

cost: int = 1

identifiers class-attribute instance-attribute

identifiers: Iterable[str] = field(default=())

item class-attribute instance-attribute

item: RateLimitItem | None = field(converter=_parse_item)

namespace class-attribute instance-attribute

namespace: Iterable[str] | None = field(default=None)

make_identifiers

make_identifiers(record: LogRecord) -> Sequence[str]
Source code in src/liblaf/grapes/logging/filters/_limits.py
def make_identifiers(self, record: logging.LogRecord) -> Sequence[str]:
    namespace: Iterable[str] = (
        self._default_namespace(record)
        if self.namespace is None
        else self.namespace
    )
    return (*namespace, *self.identifiers)

LoggerTree

LoggerTree(
    mapping: Mapping[str, Tree] | None = None,
    /,
    **kwargs: Tree,
)

Bases: UserDict[str, Tree]


              flowchart TD
              liblaf.grapes.logging.LoggerTree[LoggerTree]

              

              click liblaf.grapes.logging.LoggerTree href "" "liblaf.grapes.logging.LoggerTree"
            

Methods:

Source code in src/liblaf/grapes/logging/helpers/_tree.py
def __init__(
    self, mapping: Mapping[str, Tree] | None = None, /, **kwargs: Tree
) -> None:
    super().__init__(mapping, **kwargs)
    for logger in logging.root.manager.loggerDict.values():
        if isinstance(logger, logging.Logger):
            self.add_logger(logger)

__rich__

__rich__() -> Tree
Source code in src/liblaf/grapes/logging/helpers/_tree.py
def __rich__(self) -> Tree:
    return self["root"]

add_logger

add_logger(logger: Logger) -> Tree
Source code in src/liblaf/grapes/logging/helpers/_tree.py
def add_logger(self, logger: logging.Logger) -> Tree:
    if (tree := self.get(logger.name)) is not None:
        return tree
    tree = self._rich_logger(logger)
    self.data[logger.name] = tree
    if (parent := logger.parent) is not None:
        parent_tree: Tree = self.add_logger(parent)
        parent_tree.add(tree)
    return tree

RichFileHandler

RichFileHandler(
    filename: StrPath,
    mode: str = "w",
    *,
    encoding: str | None = None,
    errors: str | None = None,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = NOTSET,
)

Bases: RichHandler


              flowchart TD
              liblaf.grapes.logging.RichFileHandler[RichFileHandler]
              liblaf.grapes.rich.logging.handlers._handler.RichHandler[RichHandler]

                              liblaf.grapes.rich.logging.handlers._handler.RichHandler --> liblaf.grapes.logging.RichFileHandler
                


              click liblaf.grapes.logging.RichFileHandler href "" "liblaf.grapes.logging.RichFileHandler"
              click liblaf.grapes.rich.logging.handlers._handler.RichHandler href "" "liblaf.grapes.rich.logging.handlers._handler.RichHandler"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/handlers/_file.py
def __init__(
    self,
    filename: StrPath,
    mode: str = "w",
    *,
    encoding: str | None = None,
    errors: str | None = None,
    # RichHandler options
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = logging.NOTSET,
) -> None:
    filename = Path(filename)
    filename.parent.mkdir(parents=True, exist_ok=True)
    file: IO[str] = filename.open(mode=mode, encoding=encoding, errors=errors)
    console = Console(file=file)
    super().__init__(console, columns=columns, level=level)

columns instance-attribute

columns: list[RichHandlerColumn] = columns

console instance-attribute

console: Console = console

highlighter instance-attribute

highlighter: Highlighter = ReprHighlighter()

close

close() -> None
Source code in src/liblaf/grapes/logging/handlers/_file.py
@override
def close(self) -> None:
    super().close()
    self.console.file.close()

emit

emit(record: LogRecord) -> None
Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def emit(self, record: logging.LogRecord) -> None:
    self.console.print(
        *self._render(record),
        sep="",
        end="",
        overflow="ignore",
        no_wrap=True,
        highlight=False,
        crop=False,
        soft_wrap=False,
    )
    if (exception := self._render_exception(record)) is not None:
        self.console.print(exception)

init

init(
    *,
    file: StrPath | None = None,
    force: bool = False,
    time_relative: bool | None = None,
) -> None

.

Examples:

>>> init()
Source code in src/liblaf/grapes/logging/_init.py
def init(
    *,
    file: StrPath | None = None,
    force: bool = False,
    time_relative: bool | None = None,
) -> None:
    """.

    Examples:
        >>> init()
    """
    if file is None:
        file = config.logging.file.get()
    handlers: list[logging.Handler] = []
    if force or not logging.root.hasHandlers():
        handlers.append(RichHandler(time_relative=time_relative))
        if file is not None:
            handlers.append(RichFileHandler(file))
        for handler in handlers:
            handler.addFilter(LimitsFilter())
    init_levels()
    install_excepthook()
    install_unraisablehook()
    logging.basicConfig(handlers=handlers, force=force)
    logging.captureWarnings(True)  # noqa: FBT003
    logging.getLogger("IPKernelApp").setLevel(logging.WARNING)
    logging.getLogger("liblaf").setLevel(logging.DEBUG)
    logging.getLogger("nox").setLevel(logging.CRITICAL)
    remove_non_root_stream_handlers()
    set_default_logger_level_by_release_type()

init_levels

init_levels(
    levels: Mapping[int, str] | None = None,
) -> None
Source code in src/liblaf/grapes/logging/helpers/_level.py
def init_levels(levels: Mapping[int, str] | None = None) -> None:
    if levels is None:
        levels = _DEFAULT_LEVELS
    for level, name in levels.items():
        logging.addLevelName(level, name)

install_excepthook

install_excepthook(level: int = CRITICAL) -> None
Source code in src/liblaf/grapes/logging/helpers/_excepthook.py
def install_excepthook(level: int = logging.CRITICAL) -> None:
    def excepthook(
        exc_type: type[BaseException],
        exc_value: BaseException,
        exc_traceback: types.TracebackType | None,
    ) -> None:
        logger.log(level, exc_value, exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = excepthook

install_unraisablehook

install_unraisablehook(level: int = ERROR) -> None
Source code in src/liblaf/grapes/logging/helpers/_unraisablehook.py
def install_unraisablehook(level: int = logging.ERROR) -> None:
    def unraisablehook(args: sys.UnraisableHookArgs, /) -> None:
        if args.exc_value is None:
            return
        logger.log(
            level,
            "%s: %r",
            args.err_msg,
            args.object,
            exc_info=(args.exc_type, args.exc_value, args.exc_traceback),
        )

    sys.unraisablehook = unraisablehook

remove_non_root_stream_handlers

remove_non_root_stream_handlers() -> None
Source code in src/liblaf/grapes/logging/helpers/_remove_handlers.py
def remove_non_root_stream_handlers() -> None:
    # loggerDict is not documented, but it's widely used.
    for logger in logging.root.manager.loggerDict.values():
        if not isinstance(logger, logging.Logger):
            continue
        if logger.name == "root":
            continue
        for handler in logger.handlers[:]:  # slice to freeze the list during iteration
            if isinstance(handler, logging.StreamHandler) and (
                handler.stream is sys.stdout or handler.stream is sys.stderr
            ):
                logger.removeHandler(handler)

set_default_logger_level_by_release_type

set_default_logger_level_by_release_type(
    dev_level: int | str | None = None,
    pre_level: int | str | None = None,
) -> None
Source code in src/liblaf/grapes/logging/helpers/_logger.py
def set_default_logger_level_by_release_type(
    dev_level: int | str | None = None, pre_level: int | str | None = None
) -> None:
    if dev_level is not None:
        CleanLogger.dev_level = dev_level
    if pre_level is not None:
        CleanLogger.pre_level = pre_level
    logging.setLoggerClass(CleanLogger)

filters

Classes:

LimitsFilter

Parameters:

  • limiter
    (RateLimiter, default: <limits.strategies.FixedWindowRateLimiter object at 0x7f8a2e5730e0> ) –

Methods:

Attributes:

limiter class-attribute instance-attribute
limiter: RateLimiter = field(
    factory=lambda: FixedWindowRateLimiter(MemoryStorage())
)
filter
filter(record: LogRecord) -> bool
Source code in src/liblaf/grapes/logging/filters/_limits.py
def filter(self, record: logging.LogRecord) -> bool:
    args: Any = getattr(record, "limits", None)
    if args is None:
        return True
    hit_args: LimitsHitArgs = _parse_args_cache(args)
    if hit_args.item is None:
        return True
    identifiers: Sequence[str] = hit_args.make_identifiers(record)
    return self.limiter.hit(hit_args.item, *identifiers, cost=hit_args.cost)

LimitsHitArgs

Parameters:

  • item
    (RateLimitItem | None) –
  • namespace
    (Iterable[str] | None, default: None ) –
  • identifiers
    (Iterable[str], default: () ) –
  • cost
    (int, default: 1 ) –

Methods:

Attributes:

cost class-attribute instance-attribute
cost: int = 1
identifiers class-attribute instance-attribute
identifiers: Iterable[str] = field(default=())
item class-attribute instance-attribute
item: RateLimitItem | None = field(converter=_parse_item)
namespace class-attribute instance-attribute
namespace: Iterable[str] | None = field(default=None)
make_identifiers
make_identifiers(record: LogRecord) -> Sequence[str]
Source code in src/liblaf/grapes/logging/filters/_limits.py
def make_identifiers(self, record: logging.LogRecord) -> Sequence[str]:
    namespace: Iterable[str] = (
        self._default_namespace(record)
        if self.namespace is None
        else self.namespace
    )
    return (*namespace, *self.identifiers)

OnceFilter

Methods:

__call__
__call__(record: LogRecord) -> bool
Source code in src/liblaf/grapes/logging/filters/_once.py
def __call__(self, record: logging.LogRecord) -> bool:
    if not getattr(record, "once", False):
        return True
    record_hash: Hashable = self._hash_record(record)
    if record_hash in self._history:
        return False
    self._history.add(record_hash)
    return True

handlers

Classes:

RichFileHandler

RichFileHandler(
    filename: StrPath,
    mode: str = "w",
    *,
    encoding: str | None = None,
    errors: str | None = None,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = NOTSET,
)

Bases: RichHandler


              flowchart TD
              liblaf.grapes.logging.handlers.RichFileHandler[RichFileHandler]
              liblaf.grapes.rich.logging.handlers._handler.RichHandler[RichHandler]

                              liblaf.grapes.rich.logging.handlers._handler.RichHandler --> liblaf.grapes.logging.handlers.RichFileHandler
                


              click liblaf.grapes.logging.handlers.RichFileHandler href "" "liblaf.grapes.logging.handlers.RichFileHandler"
              click liblaf.grapes.rich.logging.handlers._handler.RichHandler href "" "liblaf.grapes.rich.logging.handlers._handler.RichHandler"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/handlers/_file.py
def __init__(
    self,
    filename: StrPath,
    mode: str = "w",
    *,
    encoding: str | None = None,
    errors: str | None = None,
    # RichHandler options
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = logging.NOTSET,
) -> None:
    filename = Path(filename)
    filename.parent.mkdir(parents=True, exist_ok=True)
    file: IO[str] = filename.open(mode=mode, encoding=encoding, errors=errors)
    console = Console(file=file)
    super().__init__(console, columns=columns, level=level)
columns instance-attribute
columns: list[RichHandlerColumn] = columns
console instance-attribute
console: Console = console
highlighter instance-attribute
highlighter: Highlighter = ReprHighlighter()
close
close() -> None
Source code in src/liblaf/grapes/logging/handlers/_file.py
@override
def close(self) -> None:
    super().close()
    self.console.file.close()
emit
emit(record: LogRecord) -> None
Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def emit(self, record: logging.LogRecord) -> None:
    self.console.print(
        *self._render(record),
        sep="",
        end="",
        overflow="ignore",
        no_wrap=True,
        highlight=False,
        crop=False,
        soft_wrap=False,
    )
    if (exception := self._render_exception(record)) is not None:
        self.console.print(exception)

helpers

Classes:

Functions:

Attributes:

autolog module-attribute

autolog: Logger = AutoLogger()

CleanLogger

CleanLogger(name: str, level: int | str = NOTSET)

Bases: Logger


              flowchart TD
              liblaf.grapes.logging.helpers.CleanLogger[CleanLogger]

              

              click liblaf.grapes.logging.helpers.CleanLogger href "" "liblaf.grapes.logging.helpers.CleanLogger"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_logger.py
def __init__(self, name: str, level: int | str = logging.NOTSET) -> None:
    _logging_hide = True
    super().__init__(name, level)
    if level != logging.NOTSET:
        return
    module: types.ModuleType | None = sys.modules.get(name)
    file: str | None = None
    if module is not None:
        file = getattr(module, "__file__", None)
    if file is None:
        frame: types.FrameType | None = magic.get_frame(
            hidden=magic.hidden_from_logging
        )
        if frame is not None:
            file = frame.f_code.co_filename
    if magic.is_dev_release(file, name):
        self.setLevel(self.dev_level)
    elif magic.is_pre_release(file, name):
        self.setLevel(self.pre_level)
dev_level class-attribute
dev_level: int | str = 1
pre_level class-attribute
pre_level: int | str = DEBUG
propagate property writable
propagate: bool
addHandler
addHandler(hdlr: Handler) -> None
Source code in src/liblaf/grapes/logging/helpers/_logger.py
@override
def addHandler(self, hdlr: logging.Handler) -> None:
    if self.name != "root" and isinstance(hdlr, logging.StreamHandler):
        return
    super().addHandler(hdlr)

LazyRepr

LazyRepr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs
__wrapped__ cached property
__wrapped__: str
args instance-attribute
args = args
func instance-attribute
func: Callable[P, str] = func
kwargs instance-attribute
kwargs = kwargs
__repr__
__repr__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __repr__(self) -> str:
    return self.__wrapped__

LazyStr

LazyStr(
    func: Callable[P, str],
    /,
    *args: P.args,
    **kwargs: P.kwargs,
)

Methods:

Attributes:

Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __init__(
    self, func: Callable[P, str], /, *args: P.args, **kwargs: P.kwargs
) -> None:
    self.func = func
    self.args = args
    self.kwargs = kwargs
__wrapped__ cached property
__wrapped__: str
args instance-attribute
args = args
func instance-attribute
func: Callable[P, str] = func
kwargs instance-attribute
kwargs = kwargs
__str__
__str__() -> str
Source code in src/liblaf/grapes/logging/helpers/_lazy.py
def __str__(self) -> str:
    return self.__wrapped__

LoggerTree

LoggerTree(
    mapping: Mapping[str, Tree] | None = None,
    /,
    **kwargs: Tree,
)

Bases: UserDict[str, Tree]


              flowchart TD
              liblaf.grapes.logging.helpers.LoggerTree[LoggerTree]

              

              click liblaf.grapes.logging.helpers.LoggerTree href "" "liblaf.grapes.logging.helpers.LoggerTree"
            

Methods:

Source code in src/liblaf/grapes/logging/helpers/_tree.py
def __init__(
    self, mapping: Mapping[str, Tree] | None = None, /, **kwargs: Tree
) -> None:
    super().__init__(mapping, **kwargs)
    for logger in logging.root.manager.loggerDict.values():
        if isinstance(logger, logging.Logger):
            self.add_logger(logger)
__rich__
__rich__() -> Tree
Source code in src/liblaf/grapes/logging/helpers/_tree.py
def __rich__(self) -> Tree:
    return self["root"]
add_logger
add_logger(logger: Logger) -> Tree
Source code in src/liblaf/grapes/logging/helpers/_tree.py
def add_logger(self, logger: logging.Logger) -> Tree:
    if (tree := self.get(logger.name)) is not None:
        return tree
    tree = self._rich_logger(logger)
    self.data[logger.name] = tree
    if (parent := logger.parent) is not None:
        parent_tree: Tree = self.add_logger(parent)
        parent_tree.add(tree)
    return tree

init_levels

init_levels(
    levels: Mapping[int, str] | None = None,
) -> None
Source code in src/liblaf/grapes/logging/helpers/_level.py
def init_levels(levels: Mapping[int, str] | None = None) -> None:
    if levels is None:
        levels = _DEFAULT_LEVELS
    for level, name in levels.items():
        logging.addLevelName(level, name)

install_excepthook

install_excepthook(level: int = CRITICAL) -> None
Source code in src/liblaf/grapes/logging/helpers/_excepthook.py
def install_excepthook(level: int = logging.CRITICAL) -> None:
    def excepthook(
        exc_type: type[BaseException],
        exc_value: BaseException,
        exc_traceback: types.TracebackType | None,
    ) -> None:
        logger.log(level, exc_value, exc_info=(exc_type, exc_value, exc_traceback))

    sys.excepthook = excepthook

install_unraisablehook

install_unraisablehook(level: int = ERROR) -> None
Source code in src/liblaf/grapes/logging/helpers/_unraisablehook.py
def install_unraisablehook(level: int = logging.ERROR) -> None:
    def unraisablehook(args: sys.UnraisableHookArgs, /) -> None:
        if args.exc_value is None:
            return
        logger.log(
            level,
            "%s: %r",
            args.err_msg,
            args.object,
            exc_info=(args.exc_type, args.exc_value, args.exc_traceback),
        )

    sys.unraisablehook = unraisablehook

remove_non_root_stream_handlers

remove_non_root_stream_handlers() -> None
Source code in src/liblaf/grapes/logging/helpers/_remove_handlers.py
def remove_non_root_stream_handlers() -> None:
    # loggerDict is not documented, but it's widely used.
    for logger in logging.root.manager.loggerDict.values():
        if not isinstance(logger, logging.Logger):
            continue
        if logger.name == "root":
            continue
        for handler in logger.handlers[:]:  # slice to freeze the list during iteration
            if isinstance(handler, logging.StreamHandler) and (
                handler.stream is sys.stdout or handler.stream is sys.stderr
            ):
                logger.removeHandler(handler)

set_default_logger_level_by_release_type

set_default_logger_level_by_release_type(
    dev_level: int | str | None = None,
    pre_level: int | str | None = None,
) -> None
Source code in src/liblaf/grapes/logging/helpers/_logger.py
def set_default_logger_level_by_release_type(
    dev_level: int | str | None = None, pre_level: int | str | None = None
) -> None:
    if dev_level is not None:
        CleanLogger.dev_level = dev_level
    if pre_level is not None:
        CleanLogger.pre_level = pre_level
    logging.setLoggerClass(CleanLogger)

magic

Functions:

abbr_path

abbr_path(
    path: StrPath, truncation_symbol: str = "\U000f01d8/"
) -> str
Source code in src/liblaf/grapes/magic/_abbr_path.py
def abbr_path(path: StrPath, truncation_symbol: str = "󰇘/") -> str:
    path = Path(path)
    for prefix in sys.path:
        if path.is_relative_to(prefix):
            return f"{truncation_symbol}{path.relative_to(prefix)}"
    return str(path)

entrypoint

entrypoint() -> Path
Source code in src/liblaf/grapes/magic/_entrypoint.py
def entrypoint() -> Path:
    return Path(sys.argv[0])

get_frame

get_frame(
    depth: int = 1,
    hidden: Callable[[FrameType], bool] | None = None,
) -> FrameType | None
Source code in src/liblaf/grapes/magic/_frame.py
def get_frame(
    depth: int = 1, hidden: Callable[[types.FrameType], bool] | None = None
) -> types.FrameType | None:
    frame: types.FrameType | None = inspect.currentframe()
    while frame is not None and depth > 0:
        frame = frame.f_back
        depth -= 1
        if hidden is not None:
            while frame is not None and hidden(frame):
                frame = frame.f_back
    return frame

get_frame_with_stacklevel

get_frame_with_stacklevel(
    depth: int = 1,
    hidden: Callable[[FrameType], bool] | None = None,
) -> tuple[FrameType | None, int]
Source code in src/liblaf/grapes/magic/_frame.py
def get_frame_with_stacklevel(
    depth: int = 1, hidden: Callable[[types.FrameType], bool] | None = None
) -> tuple[types.FrameType | None, int]:
    frame: types.FrameType | None = inspect.currentframe()
    stacklevel: int = 0
    while frame is not None and depth > 0:
        frame = frame.f_back
        depth -= 1
        stacklevel += 1
        if hidden is not None:
            while frame is not None and hidden(frame):
                frame = frame.f_back
                stacklevel += 1
    return frame, stacklevel

hidden_from_logging

hidden_from_logging(frame: FrameType | None) -> bool
Source code in src/liblaf/grapes/magic/_frame.py
def hidden_from_logging(frame: types.FrameType | None) -> bool:
    if frame is None:
        return False
    # `__logging_hide` does not work as expected in some cases due to name mangling
    # `__logging_hide__` will violate Ruff F841
    # so we use `_logging_hide` here
    if _coalesce(frame.f_locals, ("_logging_hide", "__tracebackhide__")):
        return True
    name: str = frame.f_globals.get("__name__", "")
    return f"{name}.".startswith(tuple(config.logging.hide_frame.get()))

hidden_from_traceback

hidden_from_traceback(
    frame: FrameType | None,
    *,
    hide_stable_release: bool | None = None,
) -> bool
Source code in src/liblaf/grapes/magic/_frame.py
def hidden_from_traceback(
    frame: types.FrameType | None, *, hide_stable_release: bool | None = None
) -> bool:
    if frame is None:
        return False
    if _coalesce(frame.f_locals, ("__tracebackhide__",)):
        return True
    if hide_stable_release is None:
        hide_stable_release = config.traceback.hide_stable_release.get()
    if hide_stable_release:
        name: str | None = frame.f_globals.get("__name__")
        if not is_pre_release(frame.f_code.co_filename, name):
            return True
    return False

hidden_from_warnings

hidden_from_warnings(
    frame: FrameType | None,
    *,
    hide_stable_release: bool | None = None,
) -> bool
Source code in src/liblaf/grapes/magic/_frame.py
def hidden_from_warnings(
    frame: types.FrameType | None, *, hide_stable_release: bool | None = None
) -> bool:
    if frame is None:
        return False
    if _coalesce(frame.f_locals, ("_warnings_hide", "__tracebackhide__")):
        return True
    if hide_stable_release is None:
        hide_stable_release = config.traceback.hide_stable_release.get()
    if hide_stable_release:
        name: str | None = frame.f_globals.get("__name__")
        if not is_pre_release(frame.f_code.co_filename, name):
            return True
    return False

in_ci

in_ci() -> bool
Source code in src/liblaf/grapes/magic/_ci.py
def in_ci() -> bool:
    return env.bool("CI", False)

is_dev_release

is_dev_release(
    file: StrPath | None = None, name: str | None = None
) -> bool
Source code in src/liblaf/grapes/magic/_release_type.py
def is_dev_release(file: StrPath | None = None, name: str | None = None) -> bool:
    return _release_type_index.is_dev(file, name)

is_pre_release

is_pre_release(
    file: StrPath | None = None, name: str | None = None
) -> bool | None
Source code in src/liblaf/grapes/magic/_release_type.py
def is_pre_release(file: StrPath | None = None, name: str | None = None) -> bool | None:
    return _release_type_index.is_pre(file, name)

pretty

Classes:

Functions:

PrettyQuantitiesComponents

Bases: NamedTuple


              flowchart TD
              liblaf.grapes.pretty.PrettyQuantitiesComponents[PrettyQuantitiesComponents]

              

              click liblaf.grapes.pretty.PrettyQuantitiesComponents href "" "liblaf.grapes.pretty.PrettyQuantitiesComponents"
            

PrettyQuantitiesComponents(mantissas, spacer, units)

Parameters:

  • mantissas

    (list[str], default: None ) –
  • spacer

    (str, default: None ) –
  • units

    (str, default: None ) –

Attributes:

mantissas instance-attribute

mantissas: list[str]

spacer instance-attribute

spacer: str

units instance-attribute

units: str

PrettyQuantityComponents

Bases: NamedTuple


              flowchart TD
              liblaf.grapes.pretty.PrettyQuantityComponents[PrettyQuantityComponents]

              

              click liblaf.grapes.pretty.PrettyQuantityComponents href "" "liblaf.grapes.pretty.PrettyQuantityComponents"
            

PrettyQuantityComponents(whole, frac, units)

Parameters:

  • whole

    (str, default: None ) –
  • frac

    (str, default: None ) –
  • units

    (str, default: None ) –

Attributes:

frac instance-attribute

frac: str

units instance-attribute

units: str

whole instance-attribute

whole: str

get_name

get_name(obj: Any) -> str
Source code in src/liblaf/grapes/pretty/_utils.py
5
6
7
def get_name(obj: Any) -> str:
    obj = inspect.unwrap(obj)
    return getattr(obj, "__qualname__", None) or getattr(obj, "__name__", "<unknown>")

has_ansi

has_ansi(s: str) -> bool

.

Examples:

>>> has_ansi("\x1b[31m red text \x1b[0m")
True
>>> has_ansi("plain text")
False
Source code in src/liblaf/grapes/pretty/_ansi.py
def has_ansi(s: str, /) -> bool:
    r""".

    Examples:
        >>> has_ansi("\x1b[31m red text \x1b[0m")
        True
        >>> has_ansi("plain text")
        False
    """
    return "\x1b" in s

pretty_call

pretty_call(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
    **wl_kwargs,
) -> str

.

Examples:

>>> def foo(a: int, b: int, c: int = 3): ...
>>> print(pretty_call(foo, (1, 2), {"c": 4}))
foo(1, 2, 4)
Source code in src/liblaf/grapes/pretty/_call.py
def pretty_call(
    func: Callable,
    args: Sequence[Any] = (),
    kwargs: Mapping[str, Any] = {},
    **wl_kwargs,
) -> str:
    """.

    Examples:
        >>> def foo(a: int, b: int, c: int = 3): ...
        >>> print(pretty_call(foo, (1, 2), {"c": 4}))
        foo(1, 2, 4)
    """
    func = inspect.unwrap(func)
    args, kwargs = _bind_safe(func, args, kwargs)
    return pformat(PrettyCall(get_name(func), args, kwargs), **wl_kwargs)

pretty_duration

pretty_duration(
    seconds: float, *, prec: int = 2, **kwargs
) -> str

.

Examples:

>>> pretty_duration(0.1234)
'123. ms'
>>> pretty_duration(0.01234)
'12.3 ms'
Source code in src/liblaf/grapes/pretty/_duration.py
def pretty_duration(seconds: float, *, prec: int = 2, **kwargs) -> str:
    """.

    Examples:
        >>> pretty_duration(0.1234)
        '123. ms'
        >>> pretty_duration(0.01234)
        '12.3 ms'
    """
    return pretty_quantity(seconds, "s", prec=prec, **kwargs)

pretty_durations

pretty_durations(
    seconds: Iterable[float], *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents

.

Examples:

>>> pretty_durations([0.1234, 0.01234, 0.001234])
PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
Source code in src/liblaf/grapes/pretty/_duration.py
def pretty_durations(
    seconds: Iterable[float], *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents:
    """.

    Examples:
        >>> pretty_durations([0.1234, 0.01234, 0.001234])
        PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
    """
    return pretty_quantities(seconds, "s", prec=prec, **kwargs)

pretty_func

pretty_func(func: Callable) -> str
Source code in src/liblaf/grapes/pretty/_func.py
6
7
8
def pretty_func(func: Callable, /) -> str:
    name: str = get_name(func)
    return f"{name}()"

pretty_quantities

pretty_quantities(
    values: Iterable[float],
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> PrettyQuantitiesComponents

.

Examples:

>>> pretty_quantities([0.1234, 0.01234, 0.001234], "s")
PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantities(
    values: Iterable[float], unit: str | None = None, *, prec: int = 2, **kwargs
) -> PrettyQuantitiesComponents:
    """.

    Examples:
        >>> pretty_quantities([0.1234, 0.01234, 0.001234], "s")
        PrettyQuantitiesComponents(mantissas=['123.', '12.', '1.'], spacer=' ', units='ms')
    """
    unit_or_sentinel: str = unit or _SENTINEL_UNIT
    components: PrettyQuantityComponents = pretty_quantity_components(
        max(values), unit_or_sentinel, prec=prec, **kwargs
    )
    spacer: str = _get_spacer(unit)

    def number_fmt(whole: str, frac: str, _units: str) -> str:
        if not frac.startswith("."):
            frac = f".{frac}"
        return f"{whole}{frac}"

    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
        show_units=False,
    ):
        mantissas: list[str] = [
            quantiphy.fixed(
                value,
                unit_or_sentinel,
                prec=len(components.frac) - 1,
                scale=components.units,
            )
            for value in values
        ]
    units: str = components.units
    if unit is None:
        units = units.removesuffix(_SENTINEL_UNIT)
    return PrettyQuantitiesComponents(mantissas, spacer, units)

pretty_quantity

pretty_quantity(
    value: float,
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> str

.

Examples:

>>> pretty_quantity(0.1234, "s")
'123. ms'
>>> pretty_quantity(0.01234, "s")
'12.3 ms'
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantity(
    value: float, unit: str | None = None, *, prec: int = 2, **kwargs
) -> str:
    """.

    Examples:
        >>> pretty_quantity(0.1234, "s")
        '123. ms'
        >>> pretty_quantity(0.01234, "s")
        '12.3 ms'
    """
    spacer: str = _get_spacer(unit)

    def number_fmt(whole: str, frac: str, units: str) -> str:
        if not frac.startswith("."):
            frac = f".{frac}"
        mantissa: str = f"{whole}{frac}"
        return f"{mantissa}{spacer}{units}"

    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
    ):
        q: Quantity = Quantity(value) if unit is None else Quantity(value, unit)
        return q.render(prec=prec, **kwargs)

pretty_quantity_components

pretty_quantity_components(
    value: float,
    unit: str | None = None,
    *,
    prec: int = 2,
    **kwargs,
) -> PrettyQuantityComponents
Source code in src/liblaf/grapes/pretty/_quantiphy.py
def pretty_quantity_components(
    value: float, unit: str | None = None, *, prec: int = 2, **kwargs
) -> PrettyQuantityComponents:
    number_fmt = _NumberFmt()
    with Quantity.prefs(
        map_sf=Quantity.map_sf_to_greek,
        number_fmt=number_fmt,
        strip_radix=False,
        strip_zeros=False,
    ):
        quantiphy.render(value, unit or _SENTINEL_UNIT, prec=prec, **kwargs)
    whole: str = number_fmt.whole
    frac: str = number_fmt.frac
    units: str = number_fmt.units
    if not frac.startswith("."):
        frac = f".{frac}"
    if unit is None:
        units = units.removesuffix(_SENTINEL_UNIT)
    return PrettyQuantityComponents(whole, frac, units)

pretty_throughput

pretty_throughput(value: float, unit: str = '') -> str

.

Examples:

>>> pretty_throughput(1234, "it")
'1.2kit/s'
Source code in src/liblaf/grapes/pretty/_throughput.py
def pretty_throughput(value: float, unit: str = "") -> str:
    """.

    Examples:
        >>> pretty_throughput(1234, "it")
        '1.2kit/s'
    """
    throughput: about_time.HumanThroughput = about_time.HumanThroughput(value, unit)
    return throughput.as_human()

rich

Modules:

Functions:

get_console cached

get_console(**kwargs) -> Console
Source code in src/liblaf/grapes/rich/_get_console.py
@wraps(Console)
@functools.cache
def get_console(**kwargs) -> Console:
    if kwargs.get("theme") is None:
        kwargs["theme"] = default_theme()
    file: IO[str] | None = kwargs.get("file")
    stderr: bool = file is None and kwargs.get("stderr", False)
    stdout: bool = file is None and not stderr
    if "force_terminal" not in kwargs and (stdout or stderr) and magic.in_ci():
        kwargs["force_terminal"] = True
    if "width" not in kwargs and (
        (stdout and not sys.stdout.isatty())
        or (stderr and not sys.stderr.isatty())
        or (file is not None and not os.isatty(file.fileno()))
    ):
        kwargs["width"] = 128
    if stdout:
        rich.reconfigure(**kwargs)
        return rich.get_console()
    return Console(**kwargs)

logging

Modules:

Classes:

RichHandler

RichHandler(
    console: Console | None = None,
    *,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = NOTSET,
    time_relative: bool | None = None,
)

Bases: Handler


              flowchart TD
              liblaf.grapes.rich.logging.RichHandler[RichHandler]

              

              click liblaf.grapes.rich.logging.RichHandler href "" "liblaf.grapes.rich.logging.RichHandler"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def __init__(
    self,
    console: Console | None = None,
    *,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = logging.NOTSET,
    time_relative: bool | None = None,
) -> None:
    super().__init__(level=level)
    columns = (
        _default_columns(time_relative=time_relative)
        if columns is None
        else list(columns)
    )
    if console is None:
        console = get_console(stderr=True)
    self.columns = columns
    self.console = console
    self.highlighter = ReprHighlighter()
columns instance-attribute
columns: list[RichHandlerColumn] = columns
console instance-attribute
console: Console = console
highlighter instance-attribute
highlighter: Highlighter = ReprHighlighter()
emit
emit(record: LogRecord) -> None
Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def emit(self, record: logging.LogRecord) -> None:
    self.console.print(
        *self._render(record),
        sep="",
        end="",
        overflow="ignore",
        no_wrap=True,
        highlight=False,
        crop=False,
        soft_wrap=False,
    )
    if (exception := self._render_exception(record)) is not None:
        self.console.print(exception)

handlers

Modules:

Classes:

RichHandler
RichHandler(
    console: Console | None = None,
    *,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = NOTSET,
    time_relative: bool | None = None,
)

Bases: Handler


              flowchart TD
              liblaf.grapes.rich.logging.handlers.RichHandler[RichHandler]

              

              click liblaf.grapes.rich.logging.handlers.RichHandler href "" "liblaf.grapes.rich.logging.handlers.RichHandler"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def __init__(
    self,
    console: Console | None = None,
    *,
    columns: Iterable[RichHandlerColumn] | None = None,
    level: int = logging.NOTSET,
    time_relative: bool | None = None,
) -> None:
    super().__init__(level=level)
    columns = (
        _default_columns(time_relative=time_relative)
        if columns is None
        else list(columns)
    )
    if console is None:
        console = get_console(stderr=True)
    self.columns = columns
    self.console = console
    self.highlighter = ReprHighlighter()
columns instance-attribute
columns: list[RichHandlerColumn] = columns
console instance-attribute
console: Console = console
highlighter instance-attribute
highlighter: Highlighter = ReprHighlighter()
emit
emit(record: LogRecord) -> None
Source code in src/liblaf/grapes/rich/logging/handlers/_handler.py
def emit(self, record: logging.LogRecord) -> None:
    self.console.print(
        *self._render(record),
        sep="",
        end="",
        overflow="ignore",
        no_wrap=True,
        highlight=False,
        crop=False,
        soft_wrap=False,
    )
    if (exception := self._render_exception(record)) is not None:
        self.console.print(exception)
RichHandlerColumn

Bases: ABC


              flowchart TD
              liblaf.grapes.rich.logging.handlers.RichHandlerColumn[RichHandlerColumn]

              

              click liblaf.grapes.rich.logging.handlers.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.RichHandlerColumn"
            

Methods:

render abstractmethod
render(record: LogRecord) -> Text | None
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_abc.py
@abc.abstractmethod
def render(self, record: logging.LogRecord, /) -> Text | None: ...
RichHandlerColumnLevel

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.RichHandlerColumnLevel[RichHandlerColumnLevel]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.RichHandlerColumnLevel
                


              click liblaf.grapes.rich.logging.handlers.RichHandlerColumnLevel href "" "liblaf.grapes.rich.logging.handlers.RichHandlerColumnLevel"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Parameters:

  • align
    (Literal[left, center, right], default: 'right' ) –
  • width
    (int, default: 3 ) –

Methods:

Attributes:

align class-attribute instance-attribute
align: AlignMethod = 'right'
width class-attribute instance-attribute
width: int = 3
render
render(record: LogRecord) -> Text
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_level.py
@override
def render(self, record: logging.LogRecord) -> Text:
    level: str = self._get_abbr(record)
    text = Text(level, f"logging.level.{record.levelname.lower()}")
    text.align(self.align, self.width)
    return text
RichHandlerColumnLocation

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.RichHandlerColumnLocation[RichHandlerColumnLocation]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.RichHandlerColumnLocation
                


              click liblaf.grapes.rich.logging.handlers.RichHandlerColumnLocation href "" "liblaf.grapes.rich.logging.handlers.RichHandlerColumnLocation"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Methods:

render
render(record: LogRecord) -> Text | None
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_location.py
@override
def render(self, record: LogRecord) -> Text | None:
    if record.name == "py.warnings":
        return Text(record.name, "log.path")
    plain: str = f"{record.name}:{record.funcName}:{record.lineno}"
    return Text(plain, "log.path")
RichHandlerColumnTime

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.RichHandlerColumnTime[RichHandlerColumnTime]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.RichHandlerColumnTime
                


              click liblaf.grapes.rich.logging.handlers.RichHandlerColumnTime href "" "liblaf.grapes.rich.logging.handlers.RichHandlerColumnTime"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Parameters:

  • fmt
    (str, default: 'YYYY-MM-DD HH:mm:ss.SSS' ) –
  • relative
    (bool, default: True ) –

Methods:

Attributes:

fmt class-attribute instance-attribute
fmt: str = field(factory=get)
relative class-attribute instance-attribute
relative: bool = field(factory=get)
render
render(record: LogRecord) -> Text
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_time.py
@override
def render(self, record: LogRecord) -> Text:
    plain: str = (
        self._render_relative(record)
        if self.relative
        else self._render_absolute(record)
    )
    return Text(plain, "log.time")
columns

Classes:

RichHandlerColumn

Bases: ABC


              flowchart TD
              liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumn[RichHandlerColumn]

              

              click liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumn"
            

Methods:

render abstractmethod
render(record: LogRecord) -> Text | None
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_abc.py
@abc.abstractmethod
def render(self, record: logging.LogRecord, /) -> Text | None: ...
RichHandlerColumnLevel

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLevel[RichHandlerColumnLevel]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLevel
                


              click liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLevel href "" "liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLevel"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Parameters:

  • align (Literal[left, center, right], default: 'right' ) –
  • width (int, default: 3 ) –

Methods:

Attributes:

align class-attribute instance-attribute
align: AlignMethod = 'right'
width class-attribute instance-attribute
width: int = 3
render
render(record: LogRecord) -> Text
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_level.py
@override
def render(self, record: logging.LogRecord) -> Text:
    level: str = self._get_abbr(record)
    text = Text(level, f"logging.level.{record.levelname.lower()}")
    text.align(self.align, self.width)
    return text
RichHandlerColumnLocation

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLocation[RichHandlerColumnLocation]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLocation
                


              click liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLocation href "" "liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnLocation"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Methods:

render
render(record: LogRecord) -> Text | None
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_location.py
@override
def render(self, record: LogRecord) -> Text | None:
    if record.name == "py.warnings":
        return Text(record.name, "log.path")
    plain: str = f"{record.name}:{record.funcName}:{record.lineno}"
    return Text(plain, "log.path")
RichHandlerColumnTime

Bases: RichHandlerColumn


              flowchart TD
              liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnTime[RichHandlerColumnTime]
              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn[RichHandlerColumn]

                              liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn --> liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnTime
                


              click liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnTime href "" "liblaf.grapes.rich.logging.handlers.columns.RichHandlerColumnTime"
              click liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn href "" "liblaf.grapes.rich.logging.handlers.columns._abc.RichHandlerColumn"
            

Parameters:

  • fmt (str, default: 'YYYY-MM-DD HH:mm:ss.SSS' ) –
  • relative (bool, default: True ) –

Methods:

Attributes:

fmt class-attribute instance-attribute
fmt: str = field(factory=get)
relative class-attribute instance-attribute
relative: bool = field(factory=get)
render
render(record: LogRecord) -> Text
Source code in src/liblaf/grapes/rich/logging/handlers/columns/_time.py
@override
def render(self, record: LogRecord) -> Text:
    plain: str = (
        self._render_relative(record)
        if self.relative
        else self._render_absolute(record)
    )
    return Text(plain, "log.time")

progress

Classes:

Functions:

Progress

Progress(
    *columns: str | ProgressColumn,
    limit: str | RateLimitItem | None = None,
    limiter: RateLimiter | None = None,
    logger: Logger | None = None,
    speed_estimate_period: float = 30.0,
    get_time: GetTimeCallable | None = None,
    disable: bool = False,
    expand: bool = False,
)

Bases: Progress


              flowchart TD
              liblaf.grapes.rich.progress.Progress[Progress]

              

              click liblaf.grapes.rich.progress.Progress href "" "liblaf.grapes.rich.progress.Progress"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/rich/progress/_progress.py
def __init__(
    self,
    *columns: str | ProgressColumn,
    limit: str | limits.RateLimitItem | None = None,
    limiter: limits.strategies.RateLimiter | None = None,
    logger: logging.Logger | None = None,
    # RichProgress options
    speed_estimate_period: float = 30.0,
    get_time: GetTimeCallable | None = None,
    disable: bool = False,
    expand: bool = False,
) -> None:
    super().__init__(
        *columns,
        console=Console(quiet=True),
        auto_refresh=False,
        speed_estimate_period=speed_estimate_period,
        get_time=get_time,
        disable=disable,
        expand=expand,
    )
    if limit is None:
        limit = limits.RateLimitItemPerSecond(1)
    elif isinstance(limit, str):
        limit = limits.parse(limit)
    self.limit = limit
    if limiter is None:
        limiter = limits.strategies.SlidingWindowCounterRateLimiter(
            limits.storage.MemoryStorage()
        )
    self.limiter = limiter
    if logger is None:
        logger = autolog
    self.logger = logger
limit instance-attribute
limit: RateLimitItem = limit
limiter instance-attribute
limiter: RateLimiter = limiter
logger instance-attribute
logger: Logger = logger
stale class-attribute instance-attribute
stale: bool = False
advance
advance(task_id: TaskID, advance: float = 1) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def advance(self, task_id: TaskID, advance: float = 1) -> None:
    _logging_hide = True
    self.stale = True
    super().advance(task_id, advance)
    self.refresh()
get_default_columns classmethod
get_default_columns() -> tuple[str | ProgressColumn, ...]
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
@classmethod
def get_default_columns(cls) -> tuple[str | ProgressColumn, ...]:  # pyright: ignore[reportIncompatibleMethodOverride]
    return (
        # SpinnerColumn(),
        TextColumn("{task.description}", style="progress.description"),
        BarColumn(),
        TaskProgressColumn(),
        MofNCompleteColumn(),
        "[",
        TimeElapsedColumn(),
        "<",
        TimeRemainingColumn(),
        ",",
        RateColumn(),
        "]",
    )
refresh
refresh(*, force: bool = False) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def refresh(self, *, force: bool = False) -> None:
    _logging_hide = True
    if self.stale and (self.limiter.hit(self.limit) or force):
        self.stale = False
        self.logger.info(self.get_renderable())
reset
reset(
    task_id: TaskID,
    *,
    start: bool = True,
    total: float | None = None,
    completed: int = 0,
    visible: bool | None = None,
    description: str | None = None,
    **fields: Any,
) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def reset(
    self,
    task_id: TaskID,
    *,
    start: bool = True,
    total: float | None = None,
    completed: int = 0,
    visible: bool | None = None,
    description: str | None = None,
    **fields: Any,
) -> None:
    _logging_hide = True
    self.stale = True
    super().reset(
        task_id,
        start=start,
        total=total,
        completed=completed,
        visible=visible,
        description=description,
        **fields,
    )
start
start() -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def start(self) -> None:
    pass
stop
stop() -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def stop(self) -> None:
    _logging_hide = True
    self.refresh(force=True)
update
update(
    task_id: TaskID,
    *,
    total: float | None = None,
    completed: float | None = None,
    advance: float | None = None,
    description: str | None = None,
    visible: bool | None = None,
    refresh: bool = False,
    **fields: Any,
) -> None
Source code in src/liblaf/grapes/rich/progress/_progress.py
@override
def update(
    self,
    task_id: TaskID,
    *,
    total: float | None = None,
    completed: float | None = None,
    advance: float | None = None,
    description: str | None = None,
    visible: bool | None = None,
    refresh: bool = False,
    **fields: Any,
) -> None:
    _logging_hide = True
    self.stale = True
    super().update(
        task_id,
        total=total,
        completed=completed,
        advance=advance,
        description=description,
        visible=visible,
        refresh=refresh,
        **fields,
    )

RateColumn

RateColumn(
    unit: str = "it", table_column: Column | None = None
)

Bases: ProgressColumn


              flowchart TD
              liblaf.grapes.rich.progress.RateColumn[RateColumn]

              

              click liblaf.grapes.rich.progress.RateColumn href "" "liblaf.grapes.rich.progress.RateColumn"
            

Methods:

Attributes:

Source code in src/liblaf/grapes/rich/progress/_rate_column.py
def __init__(self, unit: str = "it", table_column: Column | None = None) -> None:
    super().__init__(table_column)
    self.unit = unit
unit class-attribute instance-attribute
unit: str = unit
render
render(task: Task) -> RenderableType
Source code in src/liblaf/grapes/rich/progress/_rate_column.py
def render(self, task: Task) -> RenderableType:
    if not task.speed:
        return Text(f"?{self.unit}/s", style="progress.data.speed")
    throughput: str = pretty.pretty_throughput(task.speed, self.unit)
    return Text(throughput, style="progress.data.speed")

track

track[T](
    sequence: Iterable[T],
    total: float | None = None,
    completed: int = 0,
    description: str = "Working...",
    *,
    progress: Progress | None = None,
) -> Iterable[T]
Source code in src/liblaf/grapes/rich/progress/_track.py
def track[T](
    sequence: Iterable[T],
    total: float | None = None,
    completed: int = 0,
    description: str = "Working...",
    *,
    progress: Progress | None = None,
) -> Iterable[T]:
    _logging_hide = True
    if progress is None:
        progress = Progress()
    with progress:
        yield from progress.track(
            sequence, total=total, completed=completed, description=description
        )

repr

Functions:

auto_rich_repr

auto_rich_repr[T: type](
    cls: T, *, rich_repr: bool | None = None
) -> T
auto_rich_repr[T: type](
    *, rich_repr: bool | None = None
) -> Callable[[T], T]
Source code in src/liblaf/grapes/rich/repr/_auto.py
def auto_rich_repr(cls: type | None = None, *, rich_repr: bool | None = None) -> Any:
    if cls is None:
        return functools.partial(auto_rich_repr, rich_repr=rich_repr)
    if rich_repr is None:
        rich_repr = not hasattr(cls, "__rich_repr__")
    if rich_repr and has_fields(cls):
        cls.__rich_repr__ = rich_repr_fieldz
    return cls

rich_repr_fieldz

rich_repr_fieldz(obj: object) -> RichReprResult
Source code in src/liblaf/grapes/rich/repr/_fieldz.py
def rich_repr_fieldz(obj: object) -> RichReprResult:
    for field in fieldz.fields(obj):
        if not field.repr:
            continue
        value: Any = getattr(obj, field.name, MISSING)
        # rich.repr uses `if default == value:` but does not protect against
        # exceptions. Some types (e.g. NumPy arrays) raise on equality/truth
        # checks (ambiguous truth value). Do the comparison here inside a
        # try/except so we can catch and handle those errors safely.
        try:
            if value == field.default:
                yield field.name, value, field.default
            else:
                yield field.name, value
        except Exception:  # noqa: BLE001
            yield field.name, value

traceback

Classes:

Functions:

RichExceptionSummary

Parameters:

Attributes:

  • highlighter (Highlighter) –

    Highlights the text typically produced from __repr__ methods.

Methods:

cause cached property
cause: Self | None
context cached property
context: Self | None
exc_type instance-attribute
exc_type: type[BaseException]
exc_type_str cached property
exc_type_str: str
exc_value instance-attribute
exc_value: BaseException
exceptions cached property
exceptions: list[Self]
highlighter class-attribute instance-attribute
highlighter: Highlighter = field(
    repr=False, init=False, factory=ReprHighlighter
)
stack cached property
traceback instance-attribute
traceback: TracebackType | None
__attrs_post_init__
__attrs_post_init__() -> None
Source code in src/liblaf/grapes/rich/traceback/_exception.py
def __attrs_post_init__(self) -> None:
    self._seen.add(id(self.exc_value))
__rich_console__
__rich_console__(
    console: Console, options: ConsoleOptions
) -> RenderResult
Source code in src/liblaf/grapes/rich/traceback/_exception.py
def __rich_console__(
    self, console: Console, options: ConsoleOptions
) -> RenderResult:
    yield from self.render()
render
render(
    options: RichTracebackOptions | None = None,
) -> Generator[RenderableType]
Source code in src/liblaf/grapes/rich/traceback/_exception.py
def render(
    self, options: RichTracebackOptions | None = None
) -> Generator[RenderableType]:
    if options is None:
        options = RichTracebackOptions()
    if self.cause is not None:
        yield from self.cause.render(options)
        yield Text(
            "\nThe above exception was the direct cause of the following exception:\n",
            style="italic",
        )
    if self.context is not None:
        yield from self.context.render(options)
        yield Text(
            "\nDuring handling of the above exception, another exception occurred:\n",
            style="italic",
        )
    yield from self.stack.render(options)
    yield from self._render_exception_only(options)
    if self.exceptions:
        yield from self._render_subexceptions(options)

RichFrameSummary

Parameters:

Methods:

Attributes:

end_column property
end_column: int | None
end_line property
end_line: int | None
filename cached property
filename: str
frame instance-attribute
frame: FrameType
hidden cached property
hidden: bool
lasti instance-attribute
lasti: int
lineno instance-attribute
lineno: int
locals cached property
locals: dict[str, Any]
name cached property
name: str
position cached property
position: tuple[
    int | None, int | None, int | None, int | None
]
qualname cached property
qualname: str
start_column property
start_column: int | None
start_line property
start_line: int | None
__rich_console__
__rich_console__(
    console: Console, options: ConsoleOptions
) -> RenderResult
Source code in src/liblaf/grapes/rich/traceback/_frame.py
def __rich_console__(
    self, console: Console, options: ConsoleOptions
) -> RenderResult:
    yield from self.render()
render
render(
    options: RichTracebackOptions | None = None,
) -> Generator[RenderableType]
Source code in src/liblaf/grapes/rich/traceback/_frame.py
def render(
    self, options: RichTracebackOptions | None = None
) -> Generator[RenderableType]:
    if options is None:
        options = RichTracebackOptions()
    yield from self._render_location(options)
    if not self.hidden:
        yield from self._render_syntax(options)
        if options.show_locals:
            yield from self._render_locals(options)

RichStackSummary

Parameters:

Methods:

Attributes:

frames cached property
traceback instance-attribute
traceback: TracebackType | None
__rich_console__
__rich_console__(
    console: Console, options: ConsoleOptions
) -> RenderResult
Source code in src/liblaf/grapes/rich/traceback/_stack.py
def __rich_console__(
    self, console: Console, options: ConsoleOptions
) -> RenderResult:
    yield from self.render()
render
render(
    options: RichTracebackOptions | None = None,
) -> Generator[RenderableType]
Source code in src/liblaf/grapes/rich/traceback/_stack.py
def render(
    self, options: RichTracebackOptions | None = None
) -> Generator[RenderableType]:
    if options is None:
        options = RichTracebackOptions()
    if not self.frames:
        return
    panel = Panel(
        self._render_frames(options),
        title=Text.assemble(
            "Traceback ",
            ("(most recent call last)", "dim"),
            style="traceback.title",
        ),
        expand=False,
        style=options.theme.get_background_style(),
        border_style="traceback.border",
    )
    yield panel

install

install(*, console: Console | None = None) -> None
Source code in src/liblaf/grapes/rich/traceback/_install.py
def install(*, console: Console | None = None) -> None:
    if console is None:
        console = get_console(stderr=True)

    def excepthook(
        exc_type: type[BaseException],
        exc_value: BaseException,
        traceback: types.TracebackType | None,
    ) -> None:
        exc = RichExceptionSummary(exc_type, exc_value, traceback)
        console.print(exc)

    sys.excepthook = excepthook

sentinel

Type Aliases:

Attributes:

MISSING module-attribute

MISSING: Final[MissingType] = MISSING

MissingType

MissingType = Literal[MISSING]

serde

This module provides functions for serialization and deserialization of various data formats, including JSON, TOML, YAML, and Pydantic models. It also includes registries for mapping file extensions to their respective serialization and deserialization functions.

Type Aliases:

Classes:

Functions:

Attributes:

json module-attribute

json = Serde(decoder=decode, encoder=encode)

toml module-attribute

toml = Serde(decoder=decode, encoder=encode)

yaml module-attribute

yaml = Serde(decoder=decode, encoder=encode)

DecHook

DecHook = Callable[[type, Any], Any]

EncHook

EncHook = Callable[[Any], Any]

PydanticDumpOptions typed-dict

PydanticDumpOptions(
    *,
    mode: Literal["json", "python"] = ...,
    include: IncEx | None = ...,
    exclude: IncEx | None = ...,
    context: Any | None = ...,
    by_alias: bool | None = ...,
    exclude_unset: bool = ...,
    exclude_defaults: bool = ...,
    exclude_none: bool = ...,
    round_trip: bool = ...,
    warnings: bool | Literal["none", "warn", "error"] = ...,
    fallback: Callable[[Any], Any] | None = ...,
    serialize_as_any: bool = ...,
)

Bases: TypedDict


              flowchart TD
              liblaf.grapes.serde.PydanticDumpOptions[PydanticDumpOptions]

              

              click liblaf.grapes.serde.PydanticDumpOptions href "" "liblaf.grapes.serde.PydanticDumpOptions"
            

Parameters:

  • mode

    (ForwardRef) –
  • include

    (ForwardRef) –
  • exclude

    (ForwardRef) –
  • context

    (ForwardRef) –
  • by_alias

    (ForwardRef) –
  • exclude_unset

    (ForwardRef) –
  • exclude_defaults

    (ForwardRef) –
  • exclude_none

    (ForwardRef) –
  • round_trip

    (ForwardRef) –
  • warnings

    (ForwardRef) –
  • fallback

    (ForwardRef) –
  • serialize_as_any

    (ForwardRef) –

Parameters:

  • mode

    (Literal['json', 'python'], default: ... ) –
  • include

    (IncEx | None, default: ... ) –
  • exclude

    (IncEx | None, default: ... ) –
  • context

    (Any | None, default: ... ) –
  • by_alias

    (bool | None, default: ... ) –
  • exclude_unset

    (bool, default: ... ) –
  • exclude_defaults

    (bool, default: ... ) –
  • exclude_none

    (bool, default: ... ) –
  • round_trip

    (bool, default: ... ) –
  • warnings

    (bool | Literal['none', 'warn', 'error'], default: ... ) –
  • fallback

    (Callable[[Any], Any] | None, default: ... ) –
  • serialize_as_any

    (bool, default: ... ) –

PydanticValidateOptions typed-dict

PydanticValidateOptions(
    *,
    strict: bool | None = ...,
    from_attributes: bool | None = ...,
    context: Any | None = ...,
    by_alias: bool | None = ...,
    by_name: bool | None = ...,
)

Bases: TypedDict


              flowchart TD
              liblaf.grapes.serde.PydanticValidateOptions[PydanticValidateOptions]

              

              click liblaf.grapes.serde.PydanticValidateOptions href "" "liblaf.grapes.serde.PydanticValidateOptions"
            

Parameters:

  • strict

    (bool | None) –

    Whether to enforce types strictly.

  • from_attributes

    (bool | None) –

    Whether to extract data from object attributes.

  • context

    (Any | None) –

    Additional context to pass to the validator.

  • by_alias

    (bool | None) –

    Whether to use the field's alias when validating against the provided input data.

  • by_name

    (bool | None) –

    Whether to use the field's name when validating against the provided input data.

Parameters:

  • strict

    (bool | None, default: ... ) –

    Whether to enforce types strictly.

  • from_attributes

    (bool | None, default: ... ) –

    Whether to extract data from object attributes.

  • context

    (Any | None, default: ... ) –

    Additional context to pass to the validator.

  • by_alias

    (bool | None, default: ... ) –

    Whether to use the field's alias when validating against the provided input data.

  • by_name

    (bool | None, default: ... ) –

    Whether to use the field's name when validating against the provided input data.

Serde

Parameters:

  • decoder

    (Decoder) –
  • encoder

    (Encoder) –

Methods:

Attributes:

decoder instance-attribute

decoder: Decoder

encoder instance-attribute

encoder: Encoder

decode

decode(
    buf: Buffer | str,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
) -> Any
decode[T](
    buf: Buffer | str,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: type[T],
) -> T
decode[T](
    buf: Buffer | str,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: Any,
) -> Any
Source code in src/liblaf/grapes/serde/_serde.py
def decode(self, buf: Buffer | str, /, **kwargs) -> Any:
    if "dec_hook" not in kwargs:
        kwargs["dec_hook"] = functools.partial(
            dec_hook, pydantic_options=kwargs.pop("pydantic", None)
        )
    return self.decoder(buf, **kwargs)

encode

encode(
    obj: Any,
    /,
    *,
    enc_hook: EncHook | None = ...,
    order: Literal["deterministic", "sorted"] | None = None,
    pydantic: PydanticDumpOptions | None = None,
) -> bytes
Source code in src/liblaf/grapes/serde/_serde.py
def encode(self, obj: Any, /, **kwargs) -> bytes:
    if "enc_hook" not in kwargs:
        kwargs["enc_hook"] = functools.partial(
            enc_hook, pydantic_options=kwargs.pop("pydantic", None)
        )
    return self.encoder(obj, **kwargs)

load

load(
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
) -> Any
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: type[T],
) -> T
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: Any,
) -> Any
Source code in src/liblaf/grapes/serde/_serde.py
def load(self, path: StrPath, /, **kwargs) -> Any:
    path = Path(path)
    return self.decode(path.read_bytes(), **kwargs)

save

save(
    path: StrPath,
    obj: Any,
    /,
    *,
    enc_hook: EncHook | None = ...,
    order: Literal["deterministic", "sorted"] | None = None,
    pydantic: PydanticDumpOptions | None = None,
) -> None
Source code in src/liblaf/grapes/serde/_serde.py
def save(self, path: StrPath, obj: Any, /, **kwargs) -> None:
    path = Path(path)
    path.write_bytes(self.encode(obj, **kwargs))

dec_hook

dec_hook(
    typ: type,
    obj: Any,
    /,
    *,
    pydantic_options: PydanticValidateOptions | None = None,
) -> Any
Source code in src/liblaf/grapes/serde/_decode.py
def dec_hook(
    typ: type, obj: Any, /, *, pydantic_options: PydanticValidateOptions | None = None
) -> Any:
    if issubclass(typ, pydantic.BaseModel):
        pydantic_options = pydantic_options or {}
        return typ.model_validate(obj, **pydantic_options)
    return typ(obj)

enc_hook

enc_hook(obj: Any, /, **_kwargs) -> Any
Source code in src/liblaf/grapes/serde/_encode.py
@functools.singledispatch
def enc_hook(obj: Any, /, **_kwargs) -> Any:
    msg: str = f"Objects of type {type(obj)} are not supported"
    raise NotImplementedError(msg)

load

load(
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
) -> Any
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: type[T],
) -> T
load[T](
    path: StrPath,
    /,
    *,
    dec_hook: DecHook | None = ...,
    force_ext: str | None = None,
    pydantic: PydanticValidateOptions | None = None,
    strict: bool = True,
    type: Any,
) -> Any
Source code in src/liblaf/grapes/serde/_load.py
def load(path: StrPath, /, *, force_ext: str | None = None, **kwargs) -> Any:
    path = Path(path)
    ext: str = force_ext or path.suffix
    return readers[ext](path, **kwargs)

save

save(
    path: StrPath,
    obj: Any,
    /,
    *,
    enc_hook: EncHook | None = ...,
    force_ext: str | None = None,
    order: Literal["deterministic", "sorted"] | None = None,
    pydantic: PydanticDumpOptions | None = None,
) -> None
Source code in src/liblaf/grapes/serde/_save.py
def save(path: StrPath, obj: Any, /, force_ext: str | None = None, **kwargs) -> None:
    path = Path(path)
    ext: str = force_ext or path.suffix
    return writers[ext](path, obj, **kwargs)

timing

Modules:

Type Aliases:

Classes:

Functions:

Attributes:

CLOCK_REGISTRY module-attribute

CLOCK_REGISTRY = Registry()

ClockName

ClockName = Literal[
    "monotonic",
    "perf",
    "process",
    "thread",
    "time",
    "children-system",
    "children-user",
    "elapsed",
    "system",
    "user",
]

BaseTimer

Bases: Timings


              flowchart TD
              liblaf.grapes.timing.BaseTimer[BaseTimer]
              liblaf.grapes.timing._timings.Timings[Timings]

                              liblaf.grapes.timing._timings.Timings --> liblaf.grapes.timing.BaseTimer
                


              click liblaf.grapes.timing.BaseTimer href "" "liblaf.grapes.timing.BaseTimer"
              click liblaf.grapes.timing._timings.Timings href "" "liblaf.grapes.timing._timings.Timings"
            

Parameters:

  • label

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • clocks

    (Sequence[ClockName], default: ('perf',) ) –
  • cb_start

    (Callback | None, default: None ) –
  • cb_stop

    (Callback | None, default: <function log_record at 0x7f8a6ee77320> ) –
  • cb_finish

    (Callback | None, default: <function log_summary at 0x7f8a6ee77740> ) –

Attributes:

Methods:

cb_finish class-attribute instance-attribute

cb_finish: Callback | None = log_summary

cb_start class-attribute instance-attribute

cb_start: Callback | None = None

cb_stop class-attribute instance-attribute

cb_stop: Callback | None = log_record

clocks class-attribute instance-attribute

clocks: Sequence[ClockName] = field(default=DEFAULT_CLOCKS)

default_clock property

default_clock: ClockName

label class-attribute instance-attribute

label: str | None = field(default=None)

name class-attribute instance-attribute

name: str | None = field(default=None)

timings class-attribute instance-attribute

timings: dict[ClockName, list[float]] = field(
    factory=lambda: defaultdict(list), init=False
)

__attrs_post_init__

__attrs_post_init__() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def __attrs_post_init__(self) -> None:
    _warnings_hide = True
    if self.label is None and self.name is not None:
        warnings.warn(
            "'name' parameter is deprecated. Please use 'label' instead.",
            DeprecationWarning,
        )
        self.label = self.name

__bool__

__bool__() -> bool
Source code in src/liblaf/grapes/timing/_base.py
def __bool__(self) -> bool:
    return True

__len__

__len__() -> int
Source code in src/liblaf/grapes/timing/_timings.py
def __len__(self) -> int:
    return len(self.timings[self.default_clock])

clear

clear() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def clear(self) -> None:
    self.timings.clear()
    self._start_time.clear()
    self._stop_time.clear()

elapsed

elapsed(clock_name: ClockName | None = None) -> float
Source code in src/liblaf/grapes/timing/_timings.py
def elapsed(self, clock_name: ClockName | None = None) -> float:
    clock_name = clock_name or self.default_clock
    stop_time: float
    if clock_name in self._stop_time:
        stop_time = self._stop_time[clock_name]
    else:
        stop_time = clock(clock_name)
    return stop_time - self._start_time[clock_name]

finish

finish() -> None
Source code in src/liblaf/grapes/timing/_base.py
def finish(self) -> None:
    _logging_hide = True
    if self.cb_finish is not None:
        self.cb_finish(self)

log_record

log_record(
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | RateLimitItem | None = "1/second",
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_record(
    self,
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | limits.RateLimitItem | None = "1/second",
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_record(index=index)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            )
        },
    )

log_summary

log_summary(
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | RateLimitItem | None = None,
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_summary(
    self,
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | limits.RateLimitItem | None = None,
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_summary(stats=stats)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            ),
            "markup": lambda: self.pretty_summary(stats=stats, rich_markup=True),
        },
    )

pretty_record

pretty_record(index: int = -1) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_record(self, index: int = -1) -> str:
    name: str = self.label or "Timer"
    items: list[str] = [
        f"{clock_name}: {pretty.pretty_duration(self.timings[clock_name][index])}"
        for clock_name in self.clocks
    ]
    items_str: str = ", ".join(items)
    return f"{name} > {items_str}"

pretty_summary

pretty_summary(
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_summary(
    self,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str:
    name: str = self.label or "Timer"
    header: str = f"{name} (count: {len(self)})"
    if len(self) == 0:
        return header
    lines: list[str] = []
    for clock_name in self.clocks:
        stats_str: list[str] = []
        for stat in stats:
            stat_name: str
            value: str
            stat_name, value = pretty_statistic(
                self.timings[clock_name], stat, rich_markup=rich_markup
            )
            stats_str.append(f"{stat_name}: {value}")
        line: str = f"{clock_name} > {', '.join(stats_str)}"
        lines.append(line)
    if len(self.clocks) == 1:
        return f"{header} {lines[0]}"
    return f"{header}\n" + "\n".join(lines)

start

start() -> None
Source code in src/liblaf/grapes/timing/_base.py
def start(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        self._start_time[clock_name] = clock(clock_name)
    self._stop_time.clear()
    if self.cb_start is not None:
        self.cb_start(self)

stop

stop() -> None
Source code in src/liblaf/grapes/timing/_base.py
def stop(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        stop_time: float = clock(clock_name)
        self._stop_time[clock_name] = stop_time
        self.timings[clock_name].append(stop_time - self._start_time[clock_name])
    if self.cb_stop is not None:
        self.cb_stop(self)

Timer

Bases: BaseTimer, AbstractContextManager


              flowchart TD
              liblaf.grapes.timing.Timer[Timer]
              liblaf.grapes.timing._base.BaseTimer[BaseTimer]
              liblaf.grapes.timing._timings.Timings[Timings]

                              liblaf.grapes.timing._base.BaseTimer --> liblaf.grapes.timing.Timer
                                liblaf.grapes.timing._timings.Timings --> liblaf.grapes.timing._base.BaseTimer
                



              click liblaf.grapes.timing.Timer href "" "liblaf.grapes.timing.Timer"
              click liblaf.grapes.timing._base.BaseTimer href "" "liblaf.grapes.timing._base.BaseTimer"
              click liblaf.grapes.timing._timings.Timings href "" "liblaf.grapes.timing._timings.Timings"
            

Parameters:

  • label

    (str | None, default: None ) –
  • name

    (str | None, default: None ) –
  • clocks

    (Sequence[ClockName], default: ('perf',) ) –
  • cb_start

    (Callback | None, default: None ) –
  • cb_stop

    (Callback | None, default: <function log_record at 0x7f8a6ee77320> ) –
  • cb_finish

    (Callback | None, default: <function log_summary at 0x7f8a6ee77740> ) –

Attributes:

Methods:

cb_finish class-attribute instance-attribute

cb_finish: Callback | None = log_summary

cb_start class-attribute instance-attribute

cb_start: Callback | None = None

cb_stop class-attribute instance-attribute

cb_stop: Callback | None = log_record

clocks class-attribute instance-attribute

clocks: Sequence[ClockName] = field(default=DEFAULT_CLOCKS)

default_clock property

default_clock: ClockName

label class-attribute instance-attribute

label: str | None = field(default=None)

name class-attribute instance-attribute

name: str | None = field(default=None)

timings class-attribute instance-attribute

timings: dict[ClockName, list[float]] = field(
    factory=lambda: defaultdict(list), init=False
)

__attrs_post_init__

__attrs_post_init__() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def __attrs_post_init__(self) -> None:
    _warnings_hide = True
    if self.label is None and self.name is not None:
        warnings.warn(
            "'name' parameter is deprecated. Please use 'label' instead.",
            DeprecationWarning,
        )
        self.label = self.name

__bool__

__bool__() -> bool
Source code in src/liblaf/grapes/timing/_base.py
def __bool__(self) -> bool:
    return True

__call__

__call__[C: Callable](func: C) -> C
__call__[I: Iterable](iterable: I) -> I
Source code in src/liblaf/grapes/timing/_timer.py
def __call__(self, func_or_iterable: Callable | Iterable, /) -> Any:
    if callable(func_or_iterable):
        return timed_callable(func_or_iterable, self)
    return TimedIterable(func_or_iterable, self)

__enter__

__enter__() -> Self
Source code in src/liblaf/grapes/timing/_timer.py
@override  # contextlib.AbstractContextManager
def __enter__(self) -> Self:
    _logging_hide = True
    self.start()
    return self

__exit__

__exit__(
    exc_type: type[BaseException] | None,
    exc_value: BaseException | None,
    traceback: TracebackType | None,
) -> None
Source code in src/liblaf/grapes/timing/_timer.py
@override  # contextlib.AbstractContextManager
def __exit__(
    self,
    exc_type: type[BaseException] | None,
    exc_value: BaseException | None,
    traceback: types.TracebackType | None,
    /,
) -> None:
    _logging_hide = True
    self.stop()

__len__

__len__() -> int
Source code in src/liblaf/grapes/timing/_timings.py
def __len__(self) -> int:
    return len(self.timings[self.default_clock])

clear

clear() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def clear(self) -> None:
    self.timings.clear()
    self._start_time.clear()
    self._stop_time.clear()

elapsed

elapsed(clock_name: ClockName | None = None) -> float
Source code in src/liblaf/grapes/timing/_timings.py
def elapsed(self, clock_name: ClockName | None = None) -> float:
    clock_name = clock_name or self.default_clock
    stop_time: float
    if clock_name in self._stop_time:
        stop_time = self._stop_time[clock_name]
    else:
        stop_time = clock(clock_name)
    return stop_time - self._start_time[clock_name]

finish

finish() -> None
Source code in src/liblaf/grapes/timing/_base.py
def finish(self) -> None:
    _logging_hide = True
    if self.cb_finish is not None:
        self.cb_finish(self)

log_record

log_record(
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | RateLimitItem | None = "1/second",
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_record(
    self,
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | limits.RateLimitItem | None = "1/second",
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_record(index=index)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            )
        },
    )

log_summary

log_summary(
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | RateLimitItem | None = None,
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_summary(
    self,
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | limits.RateLimitItem | None = None,
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_summary(stats=stats)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            ),
            "markup": lambda: self.pretty_summary(stats=stats, rich_markup=True),
        },
    )

pretty_record

pretty_record(index: int = -1) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_record(self, index: int = -1) -> str:
    name: str = self.label or "Timer"
    items: list[str] = [
        f"{clock_name}: {pretty.pretty_duration(self.timings[clock_name][index])}"
        for clock_name in self.clocks
    ]
    items_str: str = ", ".join(items)
    return f"{name} > {items_str}"

pretty_summary

pretty_summary(
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_summary(
    self,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str:
    name: str = self.label or "Timer"
    header: str = f"{name} (count: {len(self)})"
    if len(self) == 0:
        return header
    lines: list[str] = []
    for clock_name in self.clocks:
        stats_str: list[str] = []
        for stat in stats:
            stat_name: str
            value: str
            stat_name, value = pretty_statistic(
                self.timings[clock_name], stat, rich_markup=rich_markup
            )
            stats_str.append(f"{stat_name}: {value}")
        line: str = f"{clock_name} > {', '.join(stats_str)}"
        lines.append(line)
    if len(self.clocks) == 1:
        return f"{header} {lines[0]}"
    return f"{header}\n" + "\n".join(lines)

start

start() -> None
Source code in src/liblaf/grapes/timing/_base.py
def start(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        self._start_time[clock_name] = clock(clock_name)
    self._stop_time.clear()
    if self.cb_start is not None:
        self.cb_start(self)

stop

stop() -> None
Source code in src/liblaf/grapes/timing/_base.py
def stop(self) -> None:
    _logging_hide = True
    for clock_name in self.clocks:
        stop_time: float = clock(clock_name)
        self._stop_time[clock_name] = stop_time
        self.timings[clock_name].append(stop_time - self._start_time[clock_name])
    if self.cb_stop is not None:
        self.cb_stop(self)

Timings

Parameters:

Attributes:

Methods:

clocks class-attribute instance-attribute

clocks: Sequence[ClockName] = field(default=DEFAULT_CLOCKS)

default_clock property

default_clock: ClockName

label class-attribute instance-attribute

label: str | None = field(default=None)

name class-attribute instance-attribute

name: str | None = field(default=None)

timings class-attribute instance-attribute

timings: dict[ClockName, list[float]] = field(
    factory=lambda: defaultdict(list), init=False
)

__attrs_post_init__

__attrs_post_init__() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def __attrs_post_init__(self) -> None:
    _warnings_hide = True
    if self.label is None and self.name is not None:
        warnings.warn(
            "'name' parameter is deprecated. Please use 'label' instead.",
            DeprecationWarning,
        )
        self.label = self.name

__len__

__len__() -> int
Source code in src/liblaf/grapes/timing/_timings.py
def __len__(self) -> int:
    return len(self.timings[self.default_clock])

clear

clear() -> None
Source code in src/liblaf/grapes/timing/_timings.py
def clear(self) -> None:
    self.timings.clear()
    self._start_time.clear()
    self._stop_time.clear()

elapsed

elapsed(clock_name: ClockName | None = None) -> float
Source code in src/liblaf/grapes/timing/_timings.py
def elapsed(self, clock_name: ClockName | None = None) -> float:
    clock_name = clock_name or self.default_clock
    stop_time: float
    if clock_name in self._stop_time:
        stop_time = self._stop_time[clock_name]
    else:
        stop_time = clock(clock_name)
    return stop_time - self._start_time[clock_name]

log_record

log_record(
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | RateLimitItem | None = "1/second",
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_record(
    self,
    *,
    index: int = -1,
    level: int = LOG_RECORD_DEFAULT_LEVEL,
    limits: str | limits.RateLimitItem | None = "1/second",
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_record(index=index)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            )
        },
    )

log_summary

log_summary(
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | RateLimitItem | None = None,
) -> None
Source code in src/liblaf/grapes/timing/_timings.py
def log_summary(
    self,
    *,
    level: int = LOG_SUMMARY_DEFAULT_LEVEL,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    limits: str | limits.RateLimitItem | None = None,
) -> None:
    _logging_hide = True
    autolog.log(
        level,
        "%s",
        LazyStr(lambda: self.pretty_summary(stats=stats)),
        extra={
            "limits": LimitsHitArgs(
                item=limits, identifiers=(self.label or "Timer",)
            ),
            "markup": lambda: self.pretty_summary(stats=stats, rich_markup=True),
        },
    )

pretty_record

pretty_record(index: int = -1) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_record(self, index: int = -1) -> str:
    name: str = self.label or "Timer"
    items: list[str] = [
        f"{clock_name}: {pretty.pretty_duration(self.timings[clock_name][index])}"
        for clock_name in self.clocks
    ]
    items_str: str = ", ".join(items)
    return f"{name} > {items_str}"

pretty_summary

pretty_summary(
    stats: Iterable[
        StatisticName
    ] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str
Source code in src/liblaf/grapes/timing/_timings.py
def pretty_summary(
    self,
    stats: Iterable[StatisticName] = LOG_SUMMARY_DEFAULT_STATISTICS,
    *,
    rich_markup: bool = False,
) -> str:
    name: str = self.label or "Timer"
    header: str = f"{name} (count: {len(self)})"
    if len(self) == 0:
        return header
    lines: list[str] = []
    for clock_name in self.clocks:
        stats_str: list[str] = []
        for stat in stats:
            stat_name: str
            value: str
            stat_name, value = pretty_statistic(
                self.timings[clock_name], stat, rich_markup=rich_markup
            )
            stats_str.append(f"{stat_name}: {value}")
        line: str = f"{clock_name} > {', '.join(stats_str)}"
        lines.append(line)
    if len(self.clocks) == 1:
        return f"{header} {lines[0]}"
    return f"{header}\n" + "\n".join(lines)

clock

clock(name: ClockName = 'perf') -> float
Source code in src/liblaf/grapes/timing/_clock.py
def clock(name: ClockName = "perf") -> float:
    return CLOCK_REGISTRY[name]()

get_timer

get_timer(wrapper: Any) -> BaseTimer
get_timer[T](wrapper: Any, default: T) -> BaseTimer | T
Source code in src/liblaf/grapes/timing/_utils.py
def get_timer(wrapper: Any, default: Any = MISSING) -> Any:
    if default is MISSING:
        return ft.wrapt_getattr(wrapper, "timer")
    return ft.wrapt_getattr(wrapper, "timer", default)

log_record

log_record(
    timer: Timings,
    /,
    *,
    index: int = ...,
    level: int | str = ...,
    limits: str | RateLimitItem | None = ...,
) -> Any
log_record(
    *,
    index: int = ...,
    level: int | str = ...,
    limits: str | RateLimitItem | None = ...,
) -> Callback
Source code in src/liblaf/grapes/timing/callback.py
def log_record(timer: Timings | None = None, /, **kwargs) -> Any:
    _logging_hide = True
    if timer is None:
        return functools.partial(log_record, **kwargs)
    return timer.log_record(**kwargs)

log_summary

log_summary(
    timer: Timings,
    /,
    *,
    level: int | str = ...,
    stats: Iterable[StatisticName] = ...,
    limits: str | RateLimitItem | None = ...,
) -> None
log_summary(
    *,
    level: int | str = ...,
    stats: Iterable[StatisticName] = ...,
    limits: str | RateLimitItem | None = ...,
) -> Callback
Source code in src/liblaf/grapes/timing/callback.py
def log_summary(timer: Timings | None = None, /, **kwargs) -> Any:
    _logging_hide = True
    if timer is None:
        return functools.partial(log_summary, **kwargs)
    return timer.log_summary(**kwargs)

timer

timer(
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_finish: Callback | None = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
) -> Timer
timer[C: Callable](
    callable: C,
    /,
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
    cb_finish: Callback | None = ...,
) -> C
timer[I: Iterable](
    iterable: I,
    /,
    *,
    label: str | None = ...,
    clocks: Sequence[ClockName] = ...,
    cb_start: Callback | None = ...,
    cb_stop: Callback | None = ...,
    cb_finish: Callback | None = ...,
) -> I
Source code in src/liblaf/grapes/timing/_main.py
def timer(func_or_iterable: Callable | Iterable | None = None, /, **kwargs) -> Any:
    timer = Timer(**kwargs)
    if func_or_iterable is None:
        return timer
    return timer(func_or_iterable)

callback

Functions:

log_record

log_record(
    timer: Timings,
    /,
    *,
    index: int = ...,
    level: int | str = ...,
    limits: str | RateLimitItem | None = ...,
) -> Any
log_record(
    *,
    index: int = ...,
    level: int | str = ...,
    limits: str | RateLimitItem | None = ...,
) -> Callback
Source code in src/liblaf/grapes/timing/callback.py
def log_record(timer: Timings | None = None, /, **kwargs) -> Any:
    _logging_hide = True
    if timer is None:
        return functools.partial(log_record, **kwargs)
    return timer.log_record(**kwargs)

log_summary

log_summary(
    timer: Timings,
    /,
    *,
    level: int | str = ...,
    stats: Iterable[StatisticName] = ...,
    limits: str | RateLimitItem | None = ...,
) -> None
log_summary(
    *,
    level: int | str = ...,
    stats: Iterable[StatisticName] = ...,
    limits: str | RateLimitItem | None = ...,
) -> Callback
Source code in src/liblaf/grapes/timing/callback.py
def log_summary(timer: Timings | None = None, /, **kwargs) -> Any:
    _logging_hide = True
    if timer is None:
        return functools.partial(log_summary, **kwargs)
    return timer.log_summary(**kwargs)

defaults

Attributes:

DEFAULT_CLOCKS module-attribute

DEFAULT_CLOCKS: Sequence[ClockName] = ('perf',)

LOG_RECORD_DEFAULT_LEVEL module-attribute

LOG_RECORD_DEFAULT_LEVEL: int = DEBUG

LOG_SUMMARY_DEFAULT_LEVEL module-attribute

LOG_SUMMARY_DEFAULT_LEVEL: int = INFO

LOG_SUMMARY_DEFAULT_STATISTICS module-attribute

LOG_SUMMARY_DEFAULT_STATISTICS: Iterable[StatisticName] = (
    "total",
    "mean+stdev",
    "range",
)

typing

Functions:

array_kind

array_kind(obj: Any) -> str | None
Source code in src/liblaf/grapes/typing/_array.py
def array_kind(obj: Any) -> str | None:
    # ref: <https://github.com/arogozhnikov/einops/blob/43a12ee010a844f3ad57bf404d27e4ee2d151131/einops/_backends.py>
    # ref: <https://github.com/patrick-kidger/wadler_lindig/blob/03ed125c04766008fb3f2eaa611fd3627b09de3d/wadler_lindig/_definitions.py#L254-L265>
    for module_name, type_name in _ARRAY_KINDS:
        module: types.ModuleType | None = sys.modules.get(module_name)
        if module is None:
            continue
        if isinstance(obj, getattr(module, type_name)):
            return module_name
    return None

clone_param_spec

clone_param_spec[**P, T](
    _func: Callable[P, T],
) -> Callable[[Any], Callable[P, T]]
Source code in src/liblaf/grapes/typing/_utils.py
def clone_param_spec[**P, T](
    _func: Callable[P, T], /
) -> Callable[[Any], Callable[P, T]]:
    def wrapper(wrapped: Any, /) -> Callable[P, T]:
        return wrapped

    return wrapper

clone_signature

clone_signature[C](_source: C) -> Callable[[Any], C]
Source code in src/liblaf/grapes/typing/_utils.py
def clone_signature[C](_source: C, /) -> Callable[[Any], C]:
    def wrapper(obj: Any) -> C:
        return obj

    return wrapper

is_array

is_array(obj: Any) -> bool
Source code in src/liblaf/grapes/typing/_array.py
def is_array(obj: Any) -> bool:
    return array_kind(obj) is not None

wadler_lindig

Modules:

Type Aliases:

Classes:

Functions:

Attributes:

pdoc_custom module-attribute

CustomCallable

CustomCallable = Callable[[Any], AbstractDoc | None]

PdocCustomDispatcher

PdocCustomDispatcher()

Methods:

Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def __init__(self) -> None:
    @functools.singledispatch
    def dispatcher(
        obj: Any, **kwargs: Unpack[WadlerLindigOptions]
    ) -> wl.AbstractDoc | None:
        return self._fallback(obj, **kwargs)

    self._dispatcher = dispatcher
    self._registry = []
    self.register(datetime.date, pdoc_datetime)
    self.register(enum.Enum, pdoc_enum)
    self.register(Mapping, pdoc_mapping)
    self.register(pydantic.RootModel, pdoc_pydantic_root_model)
    self.register(pdoc_array)
    self.register(pdoc_fieldz)
    self.register(pdoc_rich_repr)

__call__

__call__(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def __call__(
    self, obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    respect_pdoc: bool = kwargs.get("respect_pdoc", True)
    if respect_pdoc and hasattr(obj, "__pdoc__"):
        return None
    return self._dispatcher(obj, **kwargs)

register

register[C: Callable](cls: _RegType) -> Callable[[C], C]
register[C: Callable](cls: _RegType, /, func: C) -> C
register[C: Callable](func: C) -> C
Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def register(
    self, cls_or_func: _RegType | Callable, /, func: Callable | None = None
) -> Callable:
    if isinstance(cls_or_func, (type, types.UnionType)):
        return self._dispatcher.register(cls_or_func, func)
    self._registry.append(cls_or_func)
    return cls_or_func

WadlerLindigOptions typed-dict

WadlerLindigOptions(
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
)

Bases: TypedDict


              flowchart TD
              liblaf.grapes.wadler_lindig.WadlerLindigOptions[WadlerLindigOptions]

              

              click liblaf.grapes.wadler_lindig.WadlerLindigOptions href "" "liblaf.grapes.wadler_lindig.WadlerLindigOptions"
            

Parameters:

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –

auto_pdoc

auto_pdoc[T: type](
    cls: T,
    *,
    pdoc: bool | None = None,
    repr: bool | None = None,
) -> T
auto_pdoc[T: type](
    *, pdoc: bool | None = None, repr: bool | None = None
) -> Callable[[T], T]
Source code in src/liblaf/grapes/wadler_lindig/_auto.py
def auto_pdoc(
    cls: type | None = None,
    *,
    pdoc: bool | None = None,
    repr: bool | None = None,  # noqa: A002
) -> Any:
    if cls is None:
        return functools.partial(auto_pdoc, pdoc=pdoc, repr=repr)
    if pdoc is None:
        pdoc = not hasattr(cls, "__pdoc__")
    if repr is None:
        repr = cls.__repr__ is object.__repr__  # noqa: A001
    if pdoc:
        if hasattr(cls, "__rich_repr__"):
            cls.__pdoc__ = pdoc_rich_repr
        elif has_fields(cls):
            cls.__pdoc__ = pdoc_fieldz
    if repr:
        cls.__repr__ = pformat  # pyright: ignore[reportAttributeAccessIssue]
    return cls

chain_custom

chain_custom(
    *custom: Callable[..., AbstractDoc | None] | None,
) -> Callable[[Any], AbstractDoc | None]
Source code in src/liblaf/grapes/wadler_lindig/custom/_chain.py
def chain_custom(
    *custom: Callable[..., wl.AbstractDoc | None] | None,
) -> Callable[[Any], wl.AbstractDoc | None]:
    custom = tuple(func for func in custom if func is not None)
    if not custom:
        return _no_doc
    if len(custom) == 1:
        return custom[0]

    def wrapper(*args, **kwargs) -> wl.AbstractDoc | None:
        for func in custom:
            doc: wl.AbstractDoc | None = func(*args, **kwargs)
            if doc is not None:
                return doc
        return None

    return wrapper

make_kwargs

make_kwargs(
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> WadlerLindigOptions

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_options.py
def make_kwargs(**kwargs: Unpack[WadlerLindigOptions]) -> WadlerLindigOptions:
    kwargs: dict[str, Any] = tlz.merge(config.pretty.get(), kwargs)
    prelude_custom = _PreludeCustom(kwargs)
    kwargs["custom"] = chain_custom(kwargs.get("custom"), prelude_custom)
    return cast("WadlerLindigOptions", kwargs)

pdoc

pdoc(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pdoc.py
@wraps(wl.pdoc)
def pdoc(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> wl.AbstractDoc:
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pdoc(obj, **kwargs)

pdoc_array

pdoc_array(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_array.py
def pdoc_array(
    obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    size: int | None = _array_size(obj)
    if size is None:
        return None
    if kwargs.get("short_arrays") is None:
        with contextlib.suppress(TypeError):
            kwargs["short_arrays"] = size > kwargs.get("short_arrays_threshold", 100)
    kwargs.pop("custom", None)  # avoid infinite recursion
    return wl.pdoc(obj, **kwargs)

pdoc_datetime

pdoc_datetime(obj: date, **_kwargs) -> AbstractDoc
Source code in src/liblaf/grapes/wadler_lindig/custom/_datetime.py
def pdoc_datetime(obj: datetime.date, **_kwargs) -> wl.AbstractDoc:
    return wl.TextDoc(obj.isoformat())

pdoc_enum

pdoc_enum(
    obj: Enum,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_enum.py
def pdoc_enum(obj: enum.Enum, **kwargs: Unpack[WadlerLindigOptions]) -> wl.AbstractDoc:
    return pdoc_type(type(obj), dataclass=True, **kwargs) + wl.TextDoc(f".{obj.name}")

pdoc_fieldz

pdoc_fieldz(
    obj: object,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_fieldz.py
def pdoc_fieldz(
    obj: object, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    try:
        fields: tuple[fieldz.Field, ...] = fieldz.fields(obj)
    except TypeError:
        return None
    cls: type = type(obj)
    pairs: list[tuple[str, Any]] = []
    for field in fields:
        if not field.repr:
            continue
        value: Any = getattr(obj, field.name, MISSING)
        if kwargs.get("hide_defaults", True) and value is field.default:
            continue
        pairs.append((field.name, value))
    return wl.bracketed(
        begin=pdoc_type(cls, dataclass=True, **kwargs) + wl.TextDoc("("),
        docs=wl.named_objs(pairs, **kwargs),
        sep=wl.comma,
        end=wl.TextDoc(")"),
        indent=kwargs.get("indent", 2),
    )

pdoc_mapping

pdoc_mapping(
    obj: Mapping[Any, Any],
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_mapping.py
def pdoc_mapping(
    obj: Mapping[Any, Any], **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    if type(obj) is dict:
        begin: wl.AbstractDoc = wl.TextDoc("{")
    else:
        begin: wl.AbstractDoc = pdoc_type(
            type(obj), dataclass=True, **kwargs
        ) + wl.TextDoc("{")
    return wl.bracketed(
        begin=begin,
        docs=[
            wl.pdoc(key, **kwargs) + wl.TextDoc(": ") + wl.pdoc(value, **kwargs)
            for key, value in obj.items()
        ],
        sep=wl.comma,
        end=wl.TextDoc("}"),
        indent=kwargs.get("indent", 2),
    )

pdoc_pydantic_root_model

pdoc_pydantic_root_model(
    obj: RootModel,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_pydantic.py
def pdoc_pydantic_root_model(
    obj: pydantic.RootModel, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    return pdoc_type(type(obj), dataclass=True, **kwargs) + wl.pdoc(obj.root, **kwargs)

pdoc_rich_repr

pdoc_rich_repr(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_rich_repr.py
def pdoc_rich_repr(
    obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    if not hasattr(obj, "__rich_repr__"):
        return None
    repr_result: RichReprResult | None = obj.__rich_repr__()
    if repr_result is None:
        return None
    cls: type = type(obj)
    args: list[Any] = []
    pairs: list[tuple[str, Any]] = []
    for field in repr_result:
        name: str
        value: Any
        default: Any
        if isinstance(field, tuple):
            if len(field) == 2:
                name, value = field
                pairs.append((name, value))
            elif len(field) == 3:
                name, value, default = field
                if kwargs.get("hide_defaults", True) and value is default:
                    continue
                pairs.append((name, value))
        else:
            value = field
            args.append(value)
    return wl.bracketed(
        begin=pdoc_type(cls, dataclass=True, **kwargs) + wl.TextDoc("("),
        docs=[wl.pdoc(arg, **kwargs) for arg in args] + wl.named_objs(pairs, **kwargs),
        sep=wl.comma,
        end=wl.TextDoc(")"),
        indent=kwargs.get("indent", 2),
    )

pdoc_type

pdoc_type(
    obj: type,
    *,
    dataclass: bool = False,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_type.py
def pdoc_type(
    obj: type, *, dataclass: bool = False, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    if dataclass:
        kwargs["show_type_module"] = kwargs.get("show_dataclass_module", False)
    return _pformat_type(obj, **kwargs)

pformat

pformat(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> str

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pformat.py
@wraps(wl.pformat)
def pformat(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> str:
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pformat(obj, **kwargs)

pprint

pprint(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> None

Pretty-prints an object to stdout.

Examples:

array:

>>> import numpy as np
>>> pprint(np.zeros((2, 3)))
array([[0., 0., 0.],
       [0., 0., 0.]])
>>> pprint(np.zeros((20, 30)))
f64[20,30](numpy)

datetime:

>>> import datetime
>>> pprint(datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC))
1970-01-01T00:00:00+00:00

dataclass:

>>> import dataclasses
>>> import numpy as np
>>> @dataclasses.dataclass
... class MyDataclass:
...     x: list[str]
...     y: np.ndarray
>>> obj = MyDataclass(["lorem", "ipsum", "dolor sit amet"], np.zeros((2, 3)))
>>> pprint(obj, width=30, indent=4)
MyDataclass(
    x=[
        'lorem',
        'ipsum',
        'dolor sit amet'
    ],
    y=array([[0., 0., 0.],
             [0., 0., 0.]])
)

dict:

>>> pprint({"jack": 4098, "sjoerd": 4127})
{'jack': 4098, 'sjoerd': 4127}

pydantic:

>>> import pydantic
>>> class MyModel(pydantic.RootModel[list[str]]): ...
>>> obj = MyModel(["lorem", "ipsum", "dolor sit amet"])
>>> pprint(obj)
MyModel['lorem', 'ipsum', 'dolor sit amet']

rich.repr:

>>> import rich
>>> class Bird:
...     def __rich_repr__(self):
...         yield "penguin"
...         yield "eats", ["fish"]
...         yield "fly", False, True
...         yield "extinct", False, False
>>> pprint(Bird())
Bird('penguin', eats=['fish'], fly=False)

Parameters:

  • custom

    (CustomCallable, default: ... ) –
  • hide_defaults

    (bool, default: ... ) –
  • indent

    (int, default: ... ) –
  • respect_pdoc

    (bool, default: ... ) –
  • short_arrays

    (bool, default: ... ) –
  • show_dataclass_module

    (bool, default: ... ) –
  • show_type_module

    (bool, default: ... ) –
  • width

    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/_pprint.py
def pprint(obj: Any, **kwargs: Unpack[WadlerLindigOptions]) -> None:
    """Pretty-prints an object to stdout.

    Examples:
        array:

        >>> import numpy as np
        >>> pprint(np.zeros((2, 3)))
        array([[0., 0., 0.],
               [0., 0., 0.]])
        >>> pprint(np.zeros((20, 30)))
        f64[20,30](numpy)

        datetime:

        >>> import datetime
        >>> pprint(datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC))
        1970-01-01T00:00:00+00:00

        dataclass:

        >>> import dataclasses
        >>> import numpy as np
        >>> @dataclasses.dataclass
        ... class MyDataclass:
        ...     x: list[str]
        ...     y: np.ndarray
        >>> obj = MyDataclass(["lorem", "ipsum", "dolor sit amet"], np.zeros((2, 3)))
        >>> pprint(obj, width=30, indent=4)
        MyDataclass(
            x=[
                'lorem',
                'ipsum',
                'dolor sit amet'
            ],
            y=array([[0., 0., 0.],
                     [0., 0., 0.]])
        )

        dict:

        >>> pprint({"jack": 4098, "sjoerd": 4127})
        {'jack': 4098, 'sjoerd': 4127}

        pydantic:

        >>> import pydantic
        >>> class MyModel(pydantic.RootModel[list[str]]): ...
        >>> obj = MyModel(["lorem", "ipsum", "dolor sit amet"])
        >>> pprint(obj)
        MyModel['lorem', 'ipsum', 'dolor sit amet']

        rich.repr:

        >>> import rich
        >>> class Bird:
        ...     def __rich_repr__(self):
        ...         yield "penguin"
        ...         yield "eats", ["fish"]
        ...         yield "fly", False, True
        ...         yield "extinct", False, False
        >>> pprint(Bird())
        Bird('penguin', eats=['fish'], fly=False)
    """
    kwargs: WadlerLindigOptions = make_kwargs(**kwargs)
    return wl.pprint(obj, **kwargs)

custom

Classes:

Functions:

Attributes:

pdoc_custom module-attribute

PdocCustomDispatcher

PdocCustomDispatcher()

Methods:

Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def __init__(self) -> None:
    @functools.singledispatch
    def dispatcher(
        obj: Any, **kwargs: Unpack[WadlerLindigOptions]
    ) -> wl.AbstractDoc | None:
        return self._fallback(obj, **kwargs)

    self._dispatcher = dispatcher
    self._registry = []
    self.register(datetime.date, pdoc_datetime)
    self.register(enum.Enum, pdoc_enum)
    self.register(Mapping, pdoc_mapping)
    self.register(pydantic.RootModel, pdoc_pydantic_root_model)
    self.register(pdoc_array)
    self.register(pdoc_fieldz)
    self.register(pdoc_rich_repr)
__call__
__call__(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def __call__(
    self, obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    respect_pdoc: bool = kwargs.get("respect_pdoc", True)
    if respect_pdoc and hasattr(obj, "__pdoc__"):
        return None
    return self._dispatcher(obj, **kwargs)
register
register[C: Callable](cls: _RegType) -> Callable[[C], C]
register[C: Callable](cls: _RegType, /, func: C) -> C
register[C: Callable](func: C) -> C
Source code in src/liblaf/grapes/wadler_lindig/custom/_dispatch.py
def register(
    self, cls_or_func: _RegType | Callable, /, func: Callable | None = None
) -> Callable:
    if isinstance(cls_or_func, (type, types.UnionType)):
        return self._dispatcher.register(cls_or_func, func)
    self._registry.append(cls_or_func)
    return cls_or_func

chain_custom

chain_custom(
    *custom: Callable[..., AbstractDoc | None] | None,
) -> Callable[[Any], AbstractDoc | None]
Source code in src/liblaf/grapes/wadler_lindig/custom/_chain.py
def chain_custom(
    *custom: Callable[..., wl.AbstractDoc | None] | None,
) -> Callable[[Any], wl.AbstractDoc | None]:
    custom = tuple(func for func in custom if func is not None)
    if not custom:
        return _no_doc
    if len(custom) == 1:
        return custom[0]

    def wrapper(*args, **kwargs) -> wl.AbstractDoc | None:
        for func in custom:
            doc: wl.AbstractDoc | None = func(*args, **kwargs)
            if doc is not None:
                return doc
        return None

    return wrapper

pdoc_array

pdoc_array(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_array.py
def pdoc_array(
    obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    size: int | None = _array_size(obj)
    if size is None:
        return None
    if kwargs.get("short_arrays") is None:
        with contextlib.suppress(TypeError):
            kwargs["short_arrays"] = size > kwargs.get("short_arrays_threshold", 100)
    kwargs.pop("custom", None)  # avoid infinite recursion
    return wl.pdoc(obj, **kwargs)

pdoc_datetime

pdoc_datetime(obj: date, **_kwargs) -> AbstractDoc
Source code in src/liblaf/grapes/wadler_lindig/custom/_datetime.py
def pdoc_datetime(obj: datetime.date, **_kwargs) -> wl.AbstractDoc:
    return wl.TextDoc(obj.isoformat())

pdoc_enum

pdoc_enum(
    obj: Enum,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_enum.py
def pdoc_enum(obj: enum.Enum, **kwargs: Unpack[WadlerLindigOptions]) -> wl.AbstractDoc:
    return pdoc_type(type(obj), dataclass=True, **kwargs) + wl.TextDoc(f".{obj.name}")

pdoc_fieldz

pdoc_fieldz(
    obj: object,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_fieldz.py
def pdoc_fieldz(
    obj: object, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    try:
        fields: tuple[fieldz.Field, ...] = fieldz.fields(obj)
    except TypeError:
        return None
    cls: type = type(obj)
    pairs: list[tuple[str, Any]] = []
    for field in fields:
        if not field.repr:
            continue
        value: Any = getattr(obj, field.name, MISSING)
        if kwargs.get("hide_defaults", True) and value is field.default:
            continue
        pairs.append((field.name, value))
    return wl.bracketed(
        begin=pdoc_type(cls, dataclass=True, **kwargs) + wl.TextDoc("("),
        docs=wl.named_objs(pairs, **kwargs),
        sep=wl.comma,
        end=wl.TextDoc(")"),
        indent=kwargs.get("indent", 2),
    )

pdoc_mapping

pdoc_mapping(
    obj: Mapping[Any, Any],
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_mapping.py
def pdoc_mapping(
    obj: Mapping[Any, Any], **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    if type(obj) is dict:
        begin: wl.AbstractDoc = wl.TextDoc("{")
    else:
        begin: wl.AbstractDoc = pdoc_type(
            type(obj), dataclass=True, **kwargs
        ) + wl.TextDoc("{")
    return wl.bracketed(
        begin=begin,
        docs=[
            wl.pdoc(key, **kwargs) + wl.TextDoc(": ") + wl.pdoc(value, **kwargs)
            for key, value in obj.items()
        ],
        sep=wl.comma,
        end=wl.TextDoc("}"),
        indent=kwargs.get("indent", 2),
    )

pdoc_pydantic_root_model

pdoc_pydantic_root_model(
    obj: RootModel,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_pydantic.py
def pdoc_pydantic_root_model(
    obj: pydantic.RootModel, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    return pdoc_type(type(obj), dataclass=True, **kwargs) + wl.pdoc(obj.root, **kwargs)

pdoc_rich_repr

pdoc_rich_repr(
    obj: Any,
    *,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc | None

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_rich_repr.py
def pdoc_rich_repr(
    obj: Any, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc | None:
    if not hasattr(obj, "__rich_repr__"):
        return None
    repr_result: RichReprResult | None = obj.__rich_repr__()
    if repr_result is None:
        return None
    cls: type = type(obj)
    args: list[Any] = []
    pairs: list[tuple[str, Any]] = []
    for field in repr_result:
        name: str
        value: Any
        default: Any
        if isinstance(field, tuple):
            if len(field) == 2:
                name, value = field
                pairs.append((name, value))
            elif len(field) == 3:
                name, value, default = field
                if kwargs.get("hide_defaults", True) and value is default:
                    continue
                pairs.append((name, value))
        else:
            value = field
            args.append(value)
    return wl.bracketed(
        begin=pdoc_type(cls, dataclass=True, **kwargs) + wl.TextDoc("("),
        docs=[wl.pdoc(arg, **kwargs) for arg in args] + wl.named_objs(pairs, **kwargs),
        sep=wl.comma,
        end=wl.TextDoc(")"),
        indent=kwargs.get("indent", 2),
    )

pdoc_type

pdoc_type(
    obj: type,
    *,
    dataclass: bool = False,
    custom: CustomCallable = ...,
    hide_defaults: bool = ...,
    indent: int = ...,
    respect_pdoc: bool = ...,
    short_arrays: bool = ...,
    show_dataclass_module: bool = ...,
    show_type_module: bool = ...,
    width: int = ...,
) -> AbstractDoc

Parameters:

  • custom
    (CustomCallable, default: ... ) –
  • hide_defaults
    (bool, default: ... ) –
  • indent
    (int, default: ... ) –
  • respect_pdoc
    (bool, default: ... ) –
  • short_arrays
    (bool, default: ... ) –
  • show_dataclass_module
    (bool, default: ... ) –
  • show_type_module
    (bool, default: ... ) –
  • width
    (int, default: ... ) –
Source code in src/liblaf/grapes/wadler_lindig/custom/_type.py
def pdoc_type(
    obj: type, *, dataclass: bool = False, **kwargs: Unpack[WadlerLindigOptions]
) -> wl.AbstractDoc:
    if dataclass:
        kwargs["show_type_module"] = kwargs.get("show_dataclass_module", False)
    return _pformat_type(obj, **kwargs)

warnings

Functions:

warn

warn(*args, **kwargs) -> None
Source code in src/liblaf/grapes/warnings/_warn.py
@wraps(warnings.warn)
def warn(*args, **kwargs) -> None:
    _warnings_hide = True
    stacklevel: int = kwargs.get("stacklevel", 1)
    _, stacklevel = magic.get_frame_with_stacklevel(
        stacklevel, magic.hidden_from_warnings
    )
    kwargs["stacklevel"] = stacklevel
    return warnings.warn(*args, **kwargs)