Coverage for src/extratools_core/printtools.py: 0%
33 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-05 19:38 -0700
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-05 19:38 -0700
1from collections.abc import Callable, Iterable
2from io import StringIO
3from itertools import zip_longest
4from typing import cast
6from toolz import sliding_window
8from .typing import Comparable
11def sorted_to_str[T](
12 seq: Iterable[T],
13 *,
14 key: Callable[[T], Comparable] | None = None,
15) -> str:
16 def default_key(v: T) -> Comparable:
17 return cast("Comparable", v)
19 local_key: Callable[[T], Comparable] = default_key if key is None else key
21 s = StringIO()
23 first: bool = True
24 for prev, curr in sliding_window(2, seq):
25 if first:
26 s.write(repr(prev))
27 first = False
29 s.write(" == " if local_key(prev) == local_key(curr) else " < ")
30 s.write(repr(curr))
32 return s.getvalue()
35def alignment_to_str[T](
36 *seqs: Iterable[T | None],
37 default: str = "",
38 separator: str = " | ",
39) -> str:
40 strs: list[StringIO] = []
42 for i, col in enumerate(zip_longest(*seqs, fillvalue=default)):
43 if i == 0:
44 strs = [StringIO() for _ in col]
45 else:
46 for s in strs:
47 s.write(separator)
49 vals: list[str] = [
50 default if v is None else repr(v)
51 for v in col
52 ]
53 max_len: int = max(
54 len(val)
55 for val in vals
56 )
57 pads: list[str] = [
58 (max_len - len(val)) * ' '
59 for val in vals
60 ]
62 for s, pad, val in zip(strs, pads, vals, strict=True):
63 s.write(val)
64 s.write(pad)
66 return '\n'.join([s.getvalue() for s in strs])