nbcat 0.13.1__tar.gz → 1.0.0__tar.gz

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.
Files changed (43) hide show
  1. {nbcat-0.13.1 → nbcat-1.0.0}/.github/workflows/ci.yml +20 -0
  2. {nbcat-0.13.1 → nbcat-1.0.0}/PKG-INFO +35 -11
  3. {nbcat-0.13.1 → nbcat-1.0.0}/README.md +32 -8
  4. nbcat-1.0.0/docs/screenshot.png +0 -0
  5. nbcat-1.0.0/docs/screenshot2.png +0 -0
  6. nbcat-1.0.0/docs/screenshot3.png +0 -0
  7. {nbcat-0.13.1 → nbcat-1.0.0}/pyproject.toml +5 -5
  8. nbcat-1.0.0/src/nbcat/__init__.py +1 -0
  9. nbcat-1.0.0/src/nbcat/image.py +26 -0
  10. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/main.py +5 -3
  11. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/markdown.py +2 -5
  12. {nbcat-0.13.1 → nbcat-1.0.0}/uv.lock +425 -484
  13. nbcat-0.13.1/.github/workflows/homebrew.yml +0 -23
  14. nbcat-0.13.1/docs/screenshot.png +0 -0
  15. nbcat-0.13.1/docs/screenshot2.png +0 -0
  16. nbcat-0.13.1/src/nbcat/__init__.py +0 -1
  17. nbcat-0.13.1/src/nbcat/image.py +0 -31
  18. {nbcat-0.13.1 → nbcat-1.0.0}/.gitignore +0 -0
  19. {nbcat-0.13.1 → nbcat-1.0.0}/LICENSE +0 -0
  20. {nbcat-0.13.1 → nbcat-1.0.0}/Makefile +0 -0
  21. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/enums.py +0 -0
  22. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/exceptions.py +0 -0
  23. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/pager.py +0 -0
  24. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/py.typed +0 -0
  25. {nbcat-0.13.1 → nbcat-1.0.0}/src/nbcat/schemas.py +0 -0
  26. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/invalid.ipynb +0 -0
  27. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/many_tracebacks.ipynb +0 -0
  28. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/no_min_version.ipynb +0 -0
  29. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/sqlite.ipynb +0 -0
  30. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test3.ipynb +0 -0
  31. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test3_no_metadata.ipynb +0 -0
  32. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test3_no_min_version.ipynb +0 -0
  33. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test3_no_worksheets.ipynb +0 -0
  34. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test3_worksheet_with_no_cells.ipynb +0 -0
  35. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4.5.ipynb +0 -0
  36. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4.ipynb +0 -0
  37. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4custom.ipynb +0 -0
  38. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4docinfo.ipynb +0 -0
  39. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4jupyter_metadata.ipynb +0 -0
  40. {nbcat-0.13.1 → nbcat-1.0.0}/tests/assets/test4jupyter_metadata_timings.ipynb +0 -0
  41. {nbcat-0.13.1 → nbcat-1.0.0}/tests/conftest.py +0 -0
  42. {nbcat-0.13.1 → nbcat-1.0.0}/tests/test_read_notebook.py +0 -0
  43. {nbcat-0.13.1 → nbcat-1.0.0}/tests/test_render_cell.py +0 -0
@@ -62,3 +62,23 @@ jobs:
62
62
  uses: softprops/action-gh-release@v2
63
63
  with:
64
64
  files: dist/*
65
+
66
+ homebrew:
67
+ needs: deploy
68
+ runs-on: ubuntu-latest
69
+ steps:
70
+ - name: Release project to Homebrew tap
71
+ uses: Justintime50/homebrew-releaser@v2
72
+ with:
73
+ homebrew_owner: akopdev
74
+ homebrew_tap: homebrew-formulas
75
+ github_token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
76
+ install: 'virtualenv_install_with_resources'
77
+ test: 'assert_match version.to_s, shell_output("#{bin}/nbcat --version")'
78
+ commit_owner: akopdev
79
+ commit_email: devnull@akop.dev
80
+ update_readme_table: true
81
+ formula_includes: 'include Language::Python::Virtualenv'
82
+ depends_on: |
83
+ "python@3.13"
84
+ "pillow"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbcat
3
- Version: 0.13.1
3
+ Version: 1.0.0
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,14 +28,14 @@ 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.9
31
+ Requires-Python: >=3.10
32
32
  Requires-Dist: argcomplete
33
33
  Requires-Dist: markdownify
34
34
  Requires-Dist: pydantic
35
35
  Requires-Dist: requests
36
36
  Requires-Dist: rich
37
37
  Requires-Dist: textual
38
- Requires-Dist: timg
38
+ Requires-Dist: textual-image[textual]
39
39
  Provides-Extra: dev
40
40
  Requires-Dist: pytest; extra == 'dev'
41
41
  Requires-Dist: pytest-cov; extra == 'dev'
@@ -44,9 +44,9 @@ Requires-Dist: pytest-responses; extra == 'dev'
44
44
  Requires-Dist: ruff; extra == 'dev'
45
45
  Description-Content-Type: text/markdown
46
46
 
47
- # nbcat
47
+ <h1 align="center">nbcat: Jupyter notebooks viewer</h1>
48
48
 
49
- `nbcat` let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
49
+ [nbcat](https://github.com/akopdev/nbcat) let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
50
50
 
51
51
  <p align="center">
52
52
  <a href="docs/screenshot.png" target="blank"><img src="docs/screenshot.png" width="400" /></a>
@@ -58,7 +58,7 @@ Description-Content-Type: text/markdown
58
58
  - Very fast and lightweight with minimal dependencies.
59
59
  - Preview remote notebooks without downloading them.
60
60
  - Enable paginated view mode with keyboard navigation (similar to `less`).
61
- - Supports image rendering (some protocols in beta)
61
+ - Supports image rendering in high resolution
62
62
  - Supports for all Jupyter notebook versions, including old legacy formats.
63
63
 
64
64
  ## Motivation
@@ -74,12 +74,12 @@ Please note, that `nbcat` doesn't aim to replace JupyterLab. If you need a full-
74
74
  ## Installation
75
75
 
76
76
  ```bash
77
- # Install from PyPI
78
- pip install nbcat
77
+ # Install from PyPI (recommended)
78
+ $ pip install nbcat
79
79
 
80
80
  # Install via Homebrew
81
- brew tab akopdev/formulas/nbcat
82
- brew install nbcat
81
+ $ brew tab akopdev/formulas/nbcat
82
+ $ brew install nbcat
83
83
  ```
84
84
 
85
85
  ## Quickstart
@@ -93,13 +93,37 @@ You can pass URLs as well.
93
93
  ```bash
94
94
  $ nbcat https://raw.githubusercontent.com/akopdev/nbcat/refs/heads/main/tests/assets/test4.ipynb
95
95
  ```
96
+ In most cases system `less` will render images in low resolution. Consider using an internal pager instead:
96
97
 
97
- Example use case with `fzf` command that lists all `.ipynb` files and uses `nbcat` for previewing them:
98
+ ```bash
99
+ $ nbcat notebook.ipynb --page
100
+ ```
101
+ ## Integrations
102
+
103
+ `nbcat` is designed to integrate seamlessly with other tools. Here are a few examples of how easily it can be done.
104
+
105
+ ### FZF (Fuzzy finder)
106
+
107
+ List all `.ipynb` files and use `nbcat` to preview them:
98
108
 
99
109
  ```bash
100
110
  find . -type f -name "*.ipynb" | fzf --preview 'nbcat {}'
101
111
  ```
102
112
 
113
+ ### Ranger
114
+ To enable previews in Ranger, add the `ipynb` extension to the `handle_extension` function in `~/.config/ranger/scope.sh`:
115
+
116
+ ```bash
117
+ ...
118
+
119
+ handle_extension() {
120
+ case "${FILE_EXTENSION_LOWER}" in
121
+ ipynb)
122
+ nbcat "${FILE_PATH}" && exit 5
123
+ exit 1;;
124
+ ...
125
+ ```
126
+
103
127
  ## Testing & Development
104
128
 
105
129
  Run the tests:
@@ -1,6 +1,6 @@
1
- # nbcat
1
+ <h1 align="center">nbcat: Jupyter notebooks viewer</h1>
2
2
 
3
- `nbcat` let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
3
+ [nbcat](https://github.com/akopdev/nbcat) let you preview Jupyter notebooks directly in your terminal. Think of it as `cat`, but for `.ipynb` files.
4
4
 
5
5
  <p align="center">
6
6
  <a href="docs/screenshot.png" target="blank"><img src="docs/screenshot.png" width="400" /></a>
@@ -12,7 +12,7 @@
12
12
  - Very fast and lightweight with minimal dependencies.
13
13
  - Preview remote notebooks without downloading them.
14
14
  - Enable paginated view mode with keyboard navigation (similar to `less`).
15
- - Supports image rendering (some protocols in beta)
15
+ - Supports image rendering in high resolution
16
16
  - Supports for all Jupyter notebook versions, including old legacy formats.
17
17
 
18
18
  ## Motivation
@@ -28,12 +28,12 @@ Please note, that `nbcat` doesn't aim to replace JupyterLab. If you need a full-
28
28
  ## Installation
29
29
 
30
30
  ```bash
31
- # Install from PyPI
32
- pip install nbcat
31
+ # Install from PyPI (recommended)
32
+ $ pip install nbcat
33
33
 
34
34
  # Install via Homebrew
35
- brew tab akopdev/formulas/nbcat
36
- brew install nbcat
35
+ $ brew tab akopdev/formulas/nbcat
36
+ $ brew install nbcat
37
37
  ```
38
38
 
39
39
  ## Quickstart
@@ -47,13 +47,37 @@ You can pass URLs as well.
47
47
  ```bash
48
48
  $ nbcat https://raw.githubusercontent.com/akopdev/nbcat/refs/heads/main/tests/assets/test4.ipynb
49
49
  ```
50
+ In most cases system `less` will render images in low resolution. Consider using an internal pager instead:
50
51
 
51
- Example use case with `fzf` command that lists all `.ipynb` files and uses `nbcat` for previewing them:
52
+ ```bash
53
+ $ nbcat notebook.ipynb --page
54
+ ```
55
+ ## Integrations
56
+
57
+ `nbcat` is designed to integrate seamlessly with other tools. Here are a few examples of how easily it can be done.
58
+
59
+ ### FZF (Fuzzy finder)
60
+
61
+ List all `.ipynb` files and use `nbcat` to preview them:
52
62
 
53
63
  ```bash
54
64
  find . -type f -name "*.ipynb" | fzf --preview 'nbcat {}'
55
65
  ```
56
66
 
67
+ ### Ranger
68
+ To enable previews in Ranger, add the `ipynb` extension to the `handle_extension` function in `~/.config/ranger/scope.sh`:
69
+
70
+ ```bash
71
+ ...
72
+
73
+ handle_extension() {
74
+ case "${FILE_EXTENSION_LOWER}" in
75
+ ipynb)
76
+ nbcat "${FILE_PATH}" && exit 5
77
+ exit 1;;
78
+ ...
79
+ ```
80
+
57
81
  ## Testing & Development
58
82
 
59
83
  Run the tests:
Binary file
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nbcat"
3
- version = "0.13.1"
3
+ version = "1.0.0"
4
4
  description = "cat for jupyter notebooks"
5
5
  authors = [
6
6
  { name = "Akop Kesheshyan", email = "devnull@akop.dev" }
@@ -10,15 +10,15 @@ maintainers = [
10
10
  ]
11
11
  license = {file = "LICENSE"}
12
12
  readme = "README.md"
13
- requires-python = ">=3.9"
13
+ requires-python = ">=3.10"
14
14
  dependencies = [
15
15
  "argcomplete",
16
- "requests",
16
+ "markdownify",
17
17
  "pydantic",
18
+ "requests",
18
19
  "rich",
19
- "timg",
20
20
  "textual",
21
- "markdownify"
21
+ "textual-image[textual]",
22
22
  ]
23
23
 
24
24
  [project.optional-dependencies]
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,26 @@
1
+ import shutil
2
+ from io import BytesIO
3
+
4
+ from PIL import Image as PilImage
5
+ from textual_image.renderable import Image
6
+ from textual_image.renderable.halfcell import Image as HalfcellImage
7
+ from textual_image.renderable.sixel import Image as SixelImage
8
+ from textual_image.renderable.tgp import Image as TGPImage
9
+ from textual_image.renderable.unicode import Image as UnicodeImage
10
+
11
+
12
+ def render_image(image_content: bytes) -> TGPImage | SixelImage | HalfcellImage | UnicodeImage:
13
+ """
14
+ Render an image from raw byte content and adjusts it to fit the terminal width.
15
+
16
+ Args:
17
+ image_content (bytes): The raw byte content of the image.
18
+
19
+ Returns
20
+ -------
21
+ TGPImage | SixelImage | HalfcellImage | UnicodeImage: A terminal-compatible image
22
+ object adjusted to the current terminal width.
23
+ """
24
+ image = PilImage.open(BytesIO(image_content))
25
+ width = min(image.size[0], shutil.get_terminal_size()[0])
26
+ return Image(image, width=width, height="auto")
@@ -1,4 +1,5 @@
1
1
  import argparse
2
+ import base64
2
3
  import sys
3
4
  from pathlib import Path
4
5
 
@@ -14,6 +15,8 @@ from rich.pretty import Pretty
14
15
  from rich.syntax import Syntax
15
16
  from rich.text import Text
16
17
 
18
+ from nbcat.image import render_image
19
+
17
20
  from . import __version__
18
21
  from .enums import CellType, OutputCellType
19
22
  from .exceptions import (
@@ -21,7 +24,6 @@ from .exceptions import (
21
24
  NotebookNotFoundError,
22
25
  UnsupportedNotebookTypeError,
23
26
  )
24
- from .image import Image
25
27
  from .markdown import Markdown
26
28
  from .pager import Pager
27
29
  from .schemas import Cell, Notebook
@@ -94,8 +96,8 @@ def render_cell(cell: Cell) -> RenderableType:
94
96
  def _render_raw(input: str) -> Text:
95
97
  return Text(input)
96
98
 
97
- def _render_image(input: str) -> Image:
98
- return Image(input)
99
+ def _render_image(input: str) -> RenderableType:
100
+ return render_image(base64.b64decode(input.replace("\n", "")))
99
101
 
100
102
  def _render_json(input: str) -> Pretty:
101
103
  return Pretty(input)
@@ -10,7 +10,6 @@
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
- import base64
14
13
  from pathlib import Path
15
14
  from typing import ClassVar
16
15
 
@@ -19,7 +18,7 @@ from rich import markdown as md
19
18
  from rich.console import Console, ConsoleOptions, RenderResult
20
19
  from rich.text import Text
21
20
 
22
- from .image import Image
21
+ from .image import render_image
23
22
 
24
23
 
25
24
  class Heading(md.Heading):
@@ -53,9 +52,7 @@ class ImageItem(md.ImageItem):
53
52
  except requests.RequestException:
54
53
  return super().__rich_console__(console, options)
55
54
  if image_content:
56
- # TODO: This part can be improved by changing Image class to accept file objects
57
- image = base64.b64encode(image_content).decode("utf-8")
58
- return Image(image).__rich_console__(console, options)
55
+ return render_image(image_content).__rich_console__(console, options)
59
56
  return super().__rich_console__(console, options)
60
57
 
61
58