nbcat 0.9.3__py3-none-any.whl → 0.9.5__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 +1 -1
- nbcat/enums.py +7 -0
- nbcat/main.py +25 -10
- nbcat/schemas.py +32 -19
- {nbcat-0.9.3.dist-info → nbcat-0.9.5.dist-info}/METADATA +21 -11
- nbcat-0.9.5.dist-info/RECORD +11 -0
- nbcat-0.9.3.dist-info/RECORD +0 -11
- {nbcat-0.9.3.dist-info → nbcat-0.9.5.dist-info}/WHEEL +0 -0
- {nbcat-0.9.3.dist-info → nbcat-0.9.5.dist-info}/entry_points.txt +0 -0
- {nbcat-0.9.3.dist-info → nbcat-0.9.5.dist-info}/licenses/LICENSE +0 -0
nbcat/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.9.
|
1
|
+
__version__ = "0.9.5"
|
nbcat/enums.py
CHANGED
nbcat/main.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import argparse
|
2
2
|
import sys
|
3
3
|
from pathlib import Path
|
4
|
+
from typing import Union
|
4
5
|
|
5
6
|
import argcomplete
|
6
7
|
import requests
|
@@ -10,12 +11,13 @@ from rich import box
|
|
10
11
|
from rich.console import Console, RenderableType
|
11
12
|
from rich.markdown import Markdown
|
12
13
|
from rich.panel import Panel
|
14
|
+
from rich.pretty import Pretty
|
13
15
|
from rich.syntax import Syntax
|
14
16
|
from rich.table import Table
|
15
17
|
from rich.text import Text
|
16
18
|
|
17
19
|
from . import __version__
|
18
|
-
from .enums import CellType
|
20
|
+
from .enums import CellType, OutputCellType
|
19
21
|
from .exceptions import (
|
20
22
|
InvalidNotebookFormatError,
|
21
23
|
NotebookNotFoundError,
|
@@ -66,7 +68,7 @@ def read_notebook(fp: str, debug: bool = False) -> Notebook:
|
|
66
68
|
raise InvalidNotebookFormatError(f"Invalid notebook: {e}")
|
67
69
|
|
68
70
|
|
69
|
-
def render_cell(cell: Cell) -> list[tuple[str
|
71
|
+
def render_cell(cell: Cell) -> list[tuple[Union[str, None], RenderableType]]:
|
70
72
|
"""
|
71
73
|
Render the content of a notebook cell for display.
|
72
74
|
|
@@ -91,18 +93,28 @@ def render_cell(cell: Cell) -> list[tuple[str | None, RenderableType]]:
|
|
91
93
|
def _render_raw(input: str) -> Text:
|
92
94
|
return Text(input)
|
93
95
|
|
96
|
+
def _render_image(input: str) -> None:
|
97
|
+
return None
|
98
|
+
|
99
|
+
def _render_json(input: str) -> Pretty:
|
100
|
+
return Pretty(input)
|
101
|
+
|
94
102
|
RENDERERS = {
|
95
103
|
CellType.MARKDOWN: _render_markdown,
|
96
104
|
CellType.CODE: _render_code,
|
97
105
|
CellType.RAW: _render_raw,
|
98
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,
|
99
111
|
}
|
100
112
|
|
101
|
-
rows: list[tuple[str
|
113
|
+
rows: list[tuple[Union[str, None], RenderableType]] = []
|
102
114
|
renderer = RENDERERS.get(cell.cell_type)
|
103
115
|
source = renderer(cell.input) if renderer else None
|
104
116
|
if source:
|
105
|
-
label = f"[green][{cell.execution_count}][/]
|
117
|
+
label = f"[green][{cell.execution_count}][/]" if cell.execution_count else None
|
106
118
|
rows.append(
|
107
119
|
(
|
108
120
|
label,
|
@@ -112,13 +124,16 @@ def render_cell(cell: Cell) -> list[tuple[str | None, RenderableType]]:
|
|
112
124
|
|
113
125
|
for o in cell.outputs:
|
114
126
|
if o.output:
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
+
)
|
120
136
|
)
|
121
|
-
)
|
122
137
|
return rows
|
123
138
|
|
124
139
|
|
nbcat/schemas.py
CHANGED
@@ -1,25 +1,29 @@
|
|
1
|
-
from typing import Any
|
1
|
+
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
|
|
9
9
|
class BaseOutput(BaseModel):
|
10
10
|
output_type: OutputType
|
11
|
-
execution_count: int
|
11
|
+
execution_count: Union[int, None] = None
|
12
|
+
|
13
|
+
|
14
|
+
class CellOutput(BaseModel):
|
15
|
+
output_type: OutputCellType
|
16
|
+
text: str
|
12
17
|
|
13
18
|
|
14
19
|
class StreamOutput(BaseOutput):
|
15
|
-
text: list[str]
|
20
|
+
text: Union[list[str], str]
|
16
21
|
|
17
22
|
@computed_field
|
18
23
|
@property
|
19
|
-
def output(self) ->
|
20
|
-
if isinstance(self.text, list)
|
21
|
-
|
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) ->
|
31
|
-
|
32
|
-
|
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) ->
|
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,16 +61,16 @@ class PyoutDataOutput(BaseOutput):
|
|
48
61
|
|
49
62
|
@computed_field
|
50
63
|
@property
|
51
|
-
def output(self) ->
|
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):
|
56
69
|
cell_type: CellType
|
57
|
-
source: list[str]
|
58
|
-
level: int
|
59
|
-
execution_count: int
|
60
|
-
outputs: list[StreamOutput
|
70
|
+
source: Union[list[str], str]
|
71
|
+
level: Union[int, None] = None
|
72
|
+
execution_count: Union[int, None] = None
|
73
|
+
outputs: list[Union[StreamOutput, DisplayDataOutput, ErrorOutput, PyoutDataOutput]] = []
|
61
74
|
|
62
75
|
@model_validator(mode="before")
|
63
76
|
@classmethod
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nbcat
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.5
|
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
|
@@ -28,7 +28,7 @@ License: MIT License
|
|
28
28
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
29
29
|
SOFTWARE.
|
30
30
|
License-File: LICENSE
|
31
|
-
Requires-Python: >=3.
|
31
|
+
Requires-Python: >=3.9
|
32
32
|
Requires-Dist: argcomplete
|
33
33
|
Requires-Dist: pydantic
|
34
34
|
Requires-Dist: requests
|
@@ -43,15 +43,25 @@ Description-Content-Type: text/markdown
|
|
43
43
|
|
44
44
|
# 📦 nbcat
|
45
45
|
|
46
|
-
`nbcat`
|
46
|
+
`nbcat` let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
|
47
47
|
|
48
|
-
##
|
48
|
+
## Features
|
49
49
|
|
50
|
-
-
|
50
|
+
- Very fast and lightweight with minimal dependencies
|
51
51
|
- Preview remote notebooks without downloading them
|
52
|
-
- Supports for all Jupyter notebook versions
|
52
|
+
- Supports for all Jupyter notebook versions, including old legacy formats
|
53
53
|
|
54
|
-
##
|
54
|
+
## Motivation
|
55
|
+
|
56
|
+
The idea of previewing notebooks in a terminal is not new - there have been many previous attempts to achieve it.
|
57
|
+
However, most are either slow and overengineered with a ton of half-working features, or they're outdated and incompatible with modern Python.
|
58
|
+
|
59
|
+
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.
|
60
|
+
|
61
|
+
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.
|
62
|
+
|
63
|
+
|
64
|
+
## Installation
|
55
65
|
|
56
66
|
From the command line using pip:
|
57
67
|
|
@@ -59,7 +69,7 @@ From the command line using pip:
|
|
59
69
|
pip install nbcat
|
60
70
|
```
|
61
71
|
|
62
|
-
##
|
72
|
+
## Quickstart
|
63
73
|
|
64
74
|
```bash
|
65
75
|
$ nbcat notebook.ipynb
|
@@ -91,15 +101,15 @@ Check code quality:
|
|
91
101
|
make format lint
|
92
102
|
```
|
93
103
|
|
94
|
-
##
|
104
|
+
## Contributing
|
95
105
|
|
96
106
|
Contributions are welcome! Please open an issue or [pull request](https://github.com/akopdev/nbcat/pulls).
|
97
107
|
|
98
|
-
##
|
108
|
+
## License
|
99
109
|
|
100
110
|
Distributed under the MIT License. See [`LICENSE`](./LICENSE) for more information.
|
101
111
|
|
102
|
-
##
|
112
|
+
## Useful Links
|
103
113
|
|
104
114
|
- 📘 Documentation: _coming soon_
|
105
115
|
- 🐛 Issues: [GitHub Issues](https://github.com/akopdev/nbcat/issues)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
nbcat/__init__.py,sha256=ORAtCCI2THBDcdzIbh6oBsoshDvkkmXUWpmO4Q5McAk,22
|
2
|
+
nbcat/enums.py,sha256=Fn8PIcLl_uY4nQIs1EUvmKTwfhNUIZgmhRFiCSJk9wk,411
|
3
|
+
nbcat/exceptions.py,sha256=Ho7LQz9K70VtIMDNtAwuAtGmb-lFKxGxSj7MN3-EpDA,321
|
4
|
+
nbcat/main.py,sha256=H2gQgJYzf00DLOVp8v6yKbcKW3ZL3O9jb65VZEM7IZ0,5809
|
5
|
+
nbcat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
nbcat/schemas.py,sha256=fjSbdXa4pHKRV1Z-vUESkYZywkojanCvSu8s7rc9Xkw,3134
|
7
|
+
nbcat-0.9.5.dist-info/METADATA,sha256=6X7lT_xc9vkN1HI6pCbxE9cIK7dqeIB6NJQ1ATuLJlU,3970
|
8
|
+
nbcat-0.9.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
+
nbcat-0.9.5.dist-info/entry_points.txt,sha256=io_GRDsecAkYuCZALsjyea3VBq91VCoSznqlZEAJshY,42
|
10
|
+
nbcat-0.9.5.dist-info/licenses/LICENSE,sha256=7GjUnahXdd5opdvlpJdb1BisLbiXt2iOFhzIUduhdkE,1072
|
11
|
+
nbcat-0.9.5.dist-info/RECORD,,
|
nbcat-0.9.3.dist-info/RECORD
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
nbcat/__init__.py,sha256=xKd3pzbczuMsdB08eLAOqZDUd_q1IRxwZ_ccAFL4c4A,22
|
2
|
-
nbcat/enums.py,sha256=ZsuOwYLF0D4PVwSkS74LwoXY0y0DkeBToLBWnmiS97Y,300
|
3
|
-
nbcat/exceptions.py,sha256=Ho7LQz9K70VtIMDNtAwuAtGmb-lFKxGxSj7MN3-EpDA,321
|
4
|
-
nbcat/main.py,sha256=X1UbLxXF9Y9V4Z8vE_pUz5cG22zx2oBMMlvpJVWITD0,5236
|
5
|
-
nbcat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
nbcat/schemas.py,sha256=IK1l2a4UcP6Ivh8xRBzV5BIQTbeES1b1cCH-6goEq8Q,2366
|
7
|
-
nbcat-0.9.3.dist-info/METADATA,sha256=IQV8OPxQ0sQFu1BdLK9g6z5-nSv4j36rUhaMJYv0FQ0,3376
|
8
|
-
nbcat-0.9.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
-
nbcat-0.9.3.dist-info/entry_points.txt,sha256=io_GRDsecAkYuCZALsjyea3VBq91VCoSznqlZEAJshY,42
|
10
|
-
nbcat-0.9.3.dist-info/licenses/LICENSE,sha256=7GjUnahXdd5opdvlpJdb1BisLbiXt2iOFhzIUduhdkE,1072
|
11
|
-
nbcat-0.9.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|