Coverage for src/evutils/transforms/functional/_common.py: 100%

15 statements  

« prev     ^ index     » next       coverage.py v7.15.1, created at 2026-07-18 05:24 +0000

1"""Shared helpers for the functional transforms. 

2 

3Every functional follows the same shape: validate arguments, then unwrap the 

4events into the constituent ``(t, x, y, p)`` arrays, run a Numba-compiled 

5kernel, and repack the result into the caller's original container. The 

6:func:`apply_kernel` helper centralises the unwrap/kernel/repack dance so each 

7functional only has to express its argument handling and pick a kernel. 

8""" 

9from __future__ import annotations 

10 

11from typing import Callable 

12 

13import numpy as np 

14 

15def apply_kernel(events: "EventArray", kernel: Callable[..., "EventArray"], *args: object) -> "EventArray": 

16 """Unwrap ``events``, run ``kernel(t, x, y, p, *args)``, repack the result. 

17 

18 Empty inputs are returned untouched so kernels never see zero-length arrays 

19 (several derive a sensor extent from ``x.max()`` / ``y.max()``). 

20 """ 

21 from evutils.transforms.compose import repack_events, unwrap_events 

22 

23 if len(events) == 0: 

24 return events 

25 

26 t, x, y, p = unwrap_events(events) 

27 t, x, y, p = kernel(t, x, y, p, *args) 

28 return repack_events(events, t, x, y, p) 

29 

30def sample_range(value: "tuple[float, float] | list[float] | float") -> float: 

31 """Return ``value``, or a uniform sample in ``[lo, hi)`` if it is a 2-tuple. 

32 

33 Mirrors the range-sampling convention used across the tonic transforms, 

34 where a scalar is used verbatim and a ``(lo, hi)`` pair is sampled per call. 

35 """ 

36 if isinstance(value, (tuple, list)): 

37 lo, hi = value 

38 return (hi - lo) * np.random.random_sample() + lo 

39 return float(value)