Coverage for src/extratools_core/printtools.py: 0%
35 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-07 08:10 -0700
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-07 08:10 -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 local_key(prev) > local_key(curr):
26 raise ValueError
28 if first:
29 s.write(repr(prev))
30 first = False
32 s.write(" == " if local_key(prev) == local_key(curr) else " < ")
33 s.write(repr(curr))
35 return s.getvalue()
38def alignment_to_str[T](
39 *seqs: Iterable[T | None],
40 default: str = "",
41 separator: str = " | ",
42) -> str:
43 strs: list[StringIO] = []
45 for i, col in enumerate(zip_longest(*seqs, fillvalue=default)):
46 if i == 0:
47 strs = [StringIO() for _ in col]
48 else:
49 for s in strs:
50 s.write(separator)
52 vals: list[str] = [
53 default if v is None else repr(v)
54 for v in col
55 ]
56 max_len: int = max(
57 len(val)
58 for val in vals
59 )
60 pads: list[str] = [
61 (max_len - len(val)) * ' '
62 for val in vals
63 ]
65 for s, pad, val in zip(strs, pads, vals, strict=True):
66 s.write(val)
67 s.write(pad)
69 return '\n'.join([s.getvalue() for s in strs])