nbcat 0.9.4__py3-none-any.whl → 0.9.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
nbcat/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.4"
1
+ __version__ = "0.9.6"
nbcat/enums.py CHANGED
@@ -14,3 +14,10 @@ class OutputType(str, Enum):
14
14
  EXECUTE_RESULT = "execute_result"
15
15
  ERROR = "error"
16
16
  PYOUT = "pyout"
17
+
18
+
19
+ class OutputCellType(str, Enum):
20
+ PLAIN = "plain"
21
+ HTML = "html"
22
+ IMAGE = "image"
23
+ JSON = "json"
nbcat/main.py CHANGED
@@ -9,19 +9,20 @@ from argcomplete.completers import FilesCompleter
9
9
  from pydantic import ValidationError
10
10
  from rich import box
11
11
  from rich.console import Console, RenderableType
12
- from rich.markdown import Markdown
13
12
  from rich.panel import Panel
13
+ from rich.pretty import Pretty
14
14
  from rich.syntax import Syntax
15
15
  from rich.table import Table
16
16
  from rich.text import Text
17
17
 
18
18
  from . import __version__
19
- from .enums import CellType
19
+ from .enums import CellType, OutputCellType
20
20
  from .exceptions import (
21
21
  InvalidNotebookFormatError,
22
22
  NotebookNotFoundError,
23
23
  UnsupportedNotebookTypeError,
24
24
  )
25
+ from .markdown import Markdown
25
26
  from .schemas import Cell, Notebook
26
27
 
27
28
  console = Console()
@@ -92,18 +93,28 @@ def render_cell(cell: Cell) -> list[tuple[Union[str, None], RenderableType]]:
92
93
  def _render_raw(input: str) -> Text:
93
94
  return Text(input)
94
95
 
96
+ def _render_image(input: str) -> None:
97
+ return None
98
+
99
+ def _render_json(input: str) -> Pretty:
100
+ return Pretty(input)
101
+
95
102
  RENDERERS = {
96
103
  CellType.MARKDOWN: _render_markdown,
97
104
  CellType.CODE: _render_code,
98
105
  CellType.RAW: _render_raw,
99
106
  CellType.HEADING: _render_markdown,
107
+ OutputCellType.PLAIN: _render_raw,
108
+ OutputCellType.HTML: _render_markdown,
109
+ OutputCellType.IMAGE: _render_image,
110
+ OutputCellType.JSON: _render_json,
100
111
  }
101
112
 
102
113
  rows: list[tuple[Union[str, None], RenderableType]] = []
103
114
  renderer = RENDERERS.get(cell.cell_type)
104
115
  source = renderer(cell.input) if renderer else None
105
116
  if source:
106
- label = f"[green][{cell.execution_count}][/]:" if cell.execution_count else None
117
+ label = f"[green][{cell.execution_count}][/]" if cell.execution_count else None
107
118
  rows.append(
108
119
  (
109
120
  label,
@@ -113,13 +124,16 @@ def render_cell(cell: Cell) -> list[tuple[Union[str, None], RenderableType]]:
113
124
 
114
125
  for o in cell.outputs:
115
126
  if o.output:
116
- label = f"[blue][{o.execution_count}][/]:" if o.execution_count else None
117
- rows.append(
118
- (
119
- label,
120
- o.output,
127
+ renderer = RENDERERS.get(o.output.output_type)
128
+ output = renderer(o.output.text) if renderer else None
129
+ if output:
130
+ label = f"[blue][{o.execution_count}][/]" if o.execution_count else None
131
+ rows.append(
132
+ (
133
+ label,
134
+ output,
135
+ )
121
136
  )
122
- )
123
137
  return rows
124
138
 
125
139
 
nbcat/markdown.py ADDED
@@ -0,0 +1,51 @@
1
+ # In an ideal world, this code shouldn't exist. However, for reasons unknown to me,
2
+ # `rich` decided to format markdown headers in a way that makes them unusable
3
+ # in the terminal: they are centered and wrapped in a Panel, which causes them to
4
+ # blend in with the rest of the content. It takes me time to understand what I'm
5
+ # looking at.
6
+ #
7
+ # Instead, I override the default implementation by adding colors and preserving
8
+ # the original formatting, so that the headers remain recognizable even on
9
+ # black-and-white screens.
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import ClassVar
14
+
15
+ from rich import markdown as md
16
+ from rich.console import Console, ConsoleOptions, RenderResult
17
+ from rich.text import Text
18
+
19
+
20
+ class Heading(md.Heading):
21
+ """A heading."""
22
+
23
+ def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
24
+ styles = {
25
+ "h1": "bold cyan",
26
+ "h2": "bold magenta",
27
+ "h3": "bold yellow",
28
+ }
29
+ indent = int(self.tag.strip("h"))
30
+ yield Text(f"{'#' * indent} {self.text}", style=styles.get(self.tag, "dim white"))
31
+
32
+
33
+ class Markdown(md.Markdown):
34
+ elements: ClassVar[dict[str, type[md.MarkdownElement]]] = {
35
+ "paragraph_open": md.Paragraph,
36
+ "heading_open": Heading,
37
+ "fence": md.CodeBlock,
38
+ "code_block": md.CodeBlock,
39
+ "blockquote_open": md.BlockQuote,
40
+ "hr": md.HorizontalRule,
41
+ "bullet_list_open": md.ListElement,
42
+ "ordered_list_open": md.ListElement,
43
+ "list_item_open": md.ListItem,
44
+ "image": md.ImageItem,
45
+ "table_open": md.TableElement,
46
+ "tbody_open": md.TableBodyElement,
47
+ "thead_open": md.TableHeaderElement,
48
+ "tr_open": md.TableRowElement,
49
+ "td_open": md.TableDataElement,
50
+ "th_open": md.TableDataElement,
51
+ }
nbcat/schemas.py CHANGED
@@ -2,7 +2,7 @@ from typing import Any, Union
2
2
 
3
3
  from pydantic import BaseModel, computed_field, model_validator
4
4
 
5
- from .enums import CellType, OutputType
5
+ from .enums import CellType, OutputCellType, OutputType
6
6
  from .exceptions import InvalidNotebookFormatError
7
7
 
8
8
 
@@ -11,15 +11,19 @@ class BaseOutput(BaseModel):
11
11
  execution_count: Union[int, None] = None
12
12
 
13
13
 
14
+ class CellOutput(BaseModel):
15
+ output_type: OutputCellType
16
+ text: str
17
+
18
+
14
19
  class StreamOutput(BaseOutput):
15
20
  text: Union[list[str], str]
16
21
 
17
22
  @computed_field
18
23
  @property
19
- def output(self) -> str:
20
- if isinstance(self.text, list):
21
- return "".join(self.text)
22
- return self.text
24
+ def output(self) -> CellOutput:
25
+ text = "".join(self.text) if isinstance(self.text, list) else self.text
26
+ return CellOutput(output_type=OutputCellType.PLAIN, text=text)
23
27
 
24
28
 
25
29
  class DisplayDataOutput(BaseOutput):
@@ -27,9 +31,18 @@ class DisplayDataOutput(BaseOutput):
27
31
 
28
32
  @computed_field
29
33
  @property
30
- def output(self) -> str:
31
- # TODO: add support for rich display outputs
32
- return ""
34
+ def output(self) -> Union[CellOutput, None]:
35
+ data_type_map = {
36
+ "text/html": OutputCellType.HTML,
37
+ "text/png": OutputCellType.IMAGE,
38
+ "text/plain": OutputCellType.PLAIN,
39
+ "application/vnd.raw.v1+json": OutputCellType.JSON,
40
+ }
41
+ for data_type, output_type in data_type_map.items():
42
+ data = self.data.get(data_type)
43
+ if data:
44
+ text = "".join(data) if isinstance(data, list) else str(data)
45
+ return CellOutput(output_type=output_type, text=text)
33
46
 
34
47
 
35
48
  class ErrorOutput(BaseOutput):
@@ -39,8 +52,8 @@ class ErrorOutput(BaseOutput):
39
52
 
40
53
  @computed_field
41
54
  @property
42
- def output(self) -> str:
43
- return "\n".join(self.traceback)
55
+ def output(self) -> CellOutput:
56
+ return CellOutput(output_type=OutputCellType.PLAIN, text="\n".join(self.traceback))
44
57
 
45
58
 
46
59
  class PyoutDataOutput(BaseOutput):
@@ -48,8 +61,8 @@ class PyoutDataOutput(BaseOutput):
48
61
 
49
62
  @computed_field
50
63
  @property
51
- def output(self) -> str:
52
- return "\n".join(self.text)
64
+ def output(self) -> CellOutput:
65
+ return CellOutput(output_type=OutputCellType.PLAIN, text="\n".join(self.text))
53
66
 
54
67
 
55
68
  class Cell(BaseModel):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbcat
3
- Version: 0.9.4
3
+ Version: 0.9.6
4
4
  Summary: cat for jupyter notebooks
5
5
  Project-URL: Homepage, https://github.com/akopdev/nbcat
6
6
  Project-URL: Repository, https://github.com/akopdev/nbcat
@@ -41,17 +41,31 @@ Requires-Dist: pytest-responses; extra == 'dev'
41
41
  Requires-Dist: ruff; extra == 'dev'
42
42
  Description-Content-Type: text/markdown
43
43
 
44
- # 📦 nbcat
44
+ # nbcat
45
45
 
46
- `nbcat` lets you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
46
+ `nbcat` let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
47
47
 
48
- ## 🚀 Features
48
+ <p align="center">
49
+ <a href="docs/screenshot.png" target="blank"><img src="docs/screenshot.png" width="400" /></a>
50
+ </p>
49
51
 
50
- - Fast and lightweight with minimal external dependencies
52
+ ## Features
53
+
54
+ - Very fast and lightweight with minimal dependencies
51
55
  - Preview remote notebooks without downloading them
52
- - Supports for all Jupyter notebook versions - including legacy formats
56
+ - Supports for all Jupyter notebook versions, including old legacy formats
57
+
58
+ ## Motivation
59
+
60
+ The idea of previewing notebooks in a terminal is not new - there have been many previous attempts to achieve it.
61
+ However, most are either slow and overengineered with a ton of half-working features, or they're outdated and incompatible with modern Python.
62
+
63
+ I was looking for a simple tool that let me quickly render Jupyter notebooks without switching context from my terminal window or installing a ton of dependencies.
64
+
65
+ Please note, that `nbcat` doesn't aim to replace JupyterLab. If you need a full-featured terminal experience, I recommend checking out [euporie](https://euporie.readthedocs.io/) instead.
66
+
53
67
 
54
- ## 📦 Installation
68
+ ## Installation
55
69
 
56
70
  From the command line using pip:
57
71
 
@@ -59,7 +73,7 @@ From the command line using pip:
59
73
  pip install nbcat
60
74
  ```
61
75
 
62
- ## 🛠️ Quickstart
76
+ ## Quickstart
63
77
 
64
78
  ```bash
65
79
  $ nbcat notebook.ipynb
@@ -77,7 +91,7 @@ Example use case with `fzf` command that lists all `.ipynb` files and uses `nbca
77
91
  find . -type f -name "*.ipynb" | fzf --preview 'nbcat {}'
78
92
  ```
79
93
 
80
- ## 🧪 Testing & Development
94
+ ## Testing & Development
81
95
 
82
96
  Run the tests:
83
97
 
@@ -91,15 +105,15 @@ Check code quality:
91
105
  make format lint
92
106
  ```
93
107
 
94
- ## 🙌 Contributing
108
+ ## Contributing
95
109
 
96
110
  Contributions are welcome! Please open an issue or [pull request](https://github.com/akopdev/nbcat/pulls).
97
111
 
98
- ## 📄 License
112
+ ## License
99
113
 
100
114
  Distributed under the MIT License. See [`LICENSE`](./LICENSE) for more information.
101
115
 
102
- ## 🔗 Useful Links
116
+ ## Useful Links
103
117
 
104
118
  - 📘 Documentation: _coming soon_
105
119
  - 🐛 Issues: [GitHub Issues](https://github.com/akopdev/nbcat/issues)
@@ -0,0 +1,12 @@
1
+ nbcat/__init__.py,sha256=IgVHjr-TeioZYLJSkvpT80LLGi6U3ONzR1cfYfd5XNQ,22
2
+ nbcat/enums.py,sha256=Fn8PIcLl_uY4nQIs1EUvmKTwfhNUIZgmhRFiCSJk9wk,411
3
+ nbcat/exceptions.py,sha256=Ho7LQz9K70VtIMDNtAwuAtGmb-lFKxGxSj7MN3-EpDA,321
4
+ nbcat/main.py,sha256=7RYjHvWmKWoD9LFI1dopKvp_wvqWa2Rk9AYZ_RsrIaw,5805
5
+ nbcat/markdown.py,sha256=K6yL9rY3uTxMPsRIJnxqNHmCX2Qc-f3my8eiHxTLfic,1835
6
+ nbcat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ nbcat/schemas.py,sha256=fjSbdXa4pHKRV1Z-vUESkYZywkojanCvSu8s7rc9Xkw,3134
8
+ nbcat-0.9.6.dist-info/METADATA,sha256=v-8f9HAlHG2t-Mw36CZAIGcMRTeCWiyt0BzZMlS164w,4082
9
+ nbcat-0.9.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
+ nbcat-0.9.6.dist-info/entry_points.txt,sha256=io_GRDsecAkYuCZALsjyea3VBq91VCoSznqlZEAJshY,42
11
+ nbcat-0.9.6.dist-info/licenses/LICENSE,sha256=7GjUnahXdd5opdvlpJdb1BisLbiXt2iOFhzIUduhdkE,1072
12
+ nbcat-0.9.6.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- nbcat/__init__.py,sha256=e56AvHfJCtG2ZwwINqsxINVbehWdKxMYgIDbjd7P-II,22
2
- nbcat/enums.py,sha256=ZsuOwYLF0D4PVwSkS74LwoXY0y0DkeBToLBWnmiS97Y,300
3
- nbcat/exceptions.py,sha256=Ho7LQz9K70VtIMDNtAwuAtGmb-lFKxGxSj7MN3-EpDA,321
4
- nbcat/main.py,sha256=02qOCh4I4kXpoIgZCRYztiY5QPDw7FkAbC4smjl1Sxc,5273
5
- nbcat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- nbcat/schemas.py,sha256=miVL0GDHIqXaFxz_cd9qn7cSZvIjZYK8TTY9YsfkuXs,2407
7
- nbcat-0.9.4.dist-info/METADATA,sha256=VkAsyObzS8n5gT7qzA7Gxertoz863ZWENfqgaz3EGu0,3375
8
- nbcat-0.9.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
- nbcat-0.9.4.dist-info/entry_points.txt,sha256=io_GRDsecAkYuCZALsjyea3VBq91VCoSznqlZEAJshY,42
10
- nbcat-0.9.4.dist-info/licenses/LICENSE,sha256=7GjUnahXdd5opdvlpJdb1BisLbiXt2iOFhzIUduhdkE,1072
11
- nbcat-0.9.4.dist-info/RECORD,,
File without changes