Coverage for databooks/tui.py: 88%
52 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-10-03 12:27 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-10-03 12:27 +0000
1"""Terminal user interface (TUI) helper functions and components."""
2from contextlib import AbstractContextManager, nullcontext
3from dataclasses import asdict
4from enum import Enum
5from pathlib import Path
6from typing import Any, Dict, List, Optional, Union, overload
8from rich.columns import Columns
9from rich.console import Console
10from rich.rule import Rule
11from rich.theme import Theme
13from databooks.data_models.notebook import JupyterNotebook, NotebookMetadata
14from databooks.git_utils import DiffContents
16DATABOOKS_TUI = Theme({"in_count": "blue", "out_count": "orange3", "kernel": "bold"})
18ImgFmt = Enum("ImgFmt", {"html": "HTML", "svg": "SVG", "text": "TXT"})
21def nb2rich(
22 path: Path,
23 console: Console = Console(),
24) -> None:
25 """Show rich representation of notebook in terminal."""
26 notebook = JupyterNotebook.parse_file(path)
27 console.print(Rule(path.resolve().name), notebook)
30@overload
31def nbs2rich(
32 paths: List[Path],
33 *,
34 context: ImgFmt,
35 **kwargs: Any,
36) -> str:
37 ...
40@overload
41def nbs2rich(
42 paths: List[Path],
43 *,
44 context: bool,
45 **kwargs: Any,
46) -> None:
47 ...
50def nbs2rich(
51 paths: List[Path],
52 *,
53 context: Union[ImgFmt, bool] = False,
54 export_kwargs: Optional[Dict[str, Any]] = None,
55 **console_kwargs: Any,
56) -> Optional[str]:
57 """
58 Show rich representation of notebooks in terminal.
60 :param paths: notebook paths to print
61 :param context: specify context - `ImgFmt` to export outputs, `True` for `pager`
62 :param export_kwargs: keyword arguments for exporting prints (as a dictionary)
63 :param console_kwargs: keyword arguments to be passed to `Console`
64 :return: console output if `context` is `ImgFmt`, else `None`
65 """
66 if "record" in console_kwargs:
67 raise ValueError(
68 "Specify `record` parameter of console via `context` argument."
69 )
70 theme = console_kwargs.pop("theme", DATABOOKS_TUI)
71 console = Console(record=isinstance(context, ImgFmt), theme=theme, **console_kwargs)
72 ctx_map: Dict[Union[ImgFmt, bool], AbstractContextManager] = {
73 True: console.pager(styles=True),
74 False: nullcontext(),
75 }
76 with ctx_map.get(context, console.capture()):
77 for path in paths:
78 nb2rich(path, console=console)
79 if isinstance(context, ImgFmt):
80 return getattr(console, f"export_{context.name}")(**(export_kwargs or {}))
83def diff2rich(
84 diff: DiffContents,
85 *,
86 console: Console = Console(),
87) -> None:
88 """Show rich representation of notebook diff in terminal."""
89 a_nb, b_nb = (
90 JupyterNotebook.parse_raw(c)
91 if c is not None
92 else JupyterNotebook(
93 nbformat=0, nbformat_minor=0, metadata=NotebookMetadata(), cells=[]
94 )
95 for c in (diff.a.contents, diff.b.contents)
96 )
97 cols = Columns(
98 [
99 Rule(
100 f"{ab}/{c['path'].resolve().name if c['path'] is not None else 'null'}"
101 )
102 for ab, c in asdict(diff).items()
103 if ab in ("a", "b")
104 ],
105 width=console.width // 2,
106 padding=(0, 0),
107 )
108 console.print(cols, a_nb - b_nb)
111@overload
112def diffs2rich(
113 diffs: List[DiffContents],
114 *,
115 context: ImgFmt,
116 **kwargs: Any,
117) -> str:
118 ...
121@overload
122def diffs2rich(
123 diffs: List[DiffContents],
124 *,
125 context: bool,
126 **kwargs: Any,
127) -> None:
128 ...
131def diffs2rich(
132 diffs: List[DiffContents],
133 *,
134 context: Union[ImgFmt, bool] = False,
135 export_kwargs: Optional[Dict[str, Any]] = None,
136 **console_kwargs: Any,
137) -> Optional[str]:
138 """
139 Show rich representation of notebook diff in terminal.
141 :param diffs: `databooks.git_utils.DiffContents` for rendering
142 :param context: specify context - `ImgFmt` to export outputs, `True` for `pager`
143 :param export_kwargs: keyword arguments for exporting prints (as a dictionary)
144 :param console_kwargs: keyword arguments to be passed to `Console`
145 :return: console output if `context` is `ImgFmt`, else `None`
146 """
147 theme = console_kwargs.pop("theme", DATABOOKS_TUI)
148 console = Console(record=isinstance(context, ImgFmt), theme=theme, **console_kwargs)
149 ctx_map: Dict[Union[ImgFmt, bool], AbstractContextManager] = {
150 True: console.pager(styles=True),
151 False: nullcontext(),
152 }
153 with ctx_map.get(context, console.capture()):
154 for diff in diffs:
155 diff2rich(diff, console=console)
156 if isinstance(context, ImgFmt):
157 return getattr(console, f"export_{context.name}")(**(export_kwargs or {}))