sft-cli 0.1.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.
@@ -0,0 +1,73 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v4
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.14
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --dev
27
+
28
+ - name: Run ruff linter
29
+ run: uv run ruff check .
30
+
31
+ - name: Run ruff formatter check
32
+ run: uv run ruff format --check .
33
+
34
+ test:
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+
43
+ - name: Install uv
44
+ uses: astral-sh/setup-uv@v4
45
+
46
+ - name: Set up Python ${{ matrix.python-version }}
47
+ run: uv python install ${{ matrix.python-version }}
48
+
49
+ - name: Install dependencies
50
+ run: uv sync
51
+
52
+ - name: Verify package imports
53
+ run: uv run python -c "from sft.cli import app; from sft.browser import SftApp; from sft.index import TensorIndex; print('All imports successful')"
54
+
55
+ build:
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+
60
+ - name: Install uv
61
+ uses: astral-sh/setup-uv@v4
62
+
63
+ - name: Set up Python
64
+ run: uv python install 3.14
65
+
66
+ - name: Build package
67
+ run: uv build
68
+
69
+ - name: Upload build artifacts
70
+ uses: actions/upload-artifact@v4
71
+ with:
72
+ name: dist
73
+ path: dist/
@@ -0,0 +1,44 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+
13
+ - name: Install uv
14
+ uses: astral-sh/setup-uv@v4
15
+
16
+ - name: Set up Python
17
+ run: uv python install 3.12
18
+
19
+ - name: Build package
20
+ run: uv build
21
+
22
+ - name: Upload build artifacts
23
+ uses: actions/upload-artifact@v4
24
+ with:
25
+ name: dist
26
+ path: dist/
27
+
28
+ publish-pypi:
29
+ needs: build
30
+ runs-on: ubuntu-latest
31
+ environment:
32
+ name: pypi
33
+ url: https://pypi.org/p/sft-cli
34
+ permissions:
35
+ id-token: write
36
+ steps:
37
+ - name: Download build artifacts
38
+ uses: actions/download-artifact@v4
39
+ with:
40
+ name: dist
41
+ path: dist/
42
+
43
+ - name: Publish to PyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,23 @@
1
+ # AI agent documents
2
+ .ai/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.so
8
+ dist/
9
+ *.egg-info/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+
14
+ # IDE
15
+ .vscode/
16
+ .idea/
17
+
18
+ # Testing
19
+ .pytest_cache/
20
+ .coverage
21
+
22
+ # Test files
23
+ *.safetensors
@@ -0,0 +1,18 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v6.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-toml
9
+ - id: check-added-large-files
10
+ - id: check-merge-conflict
11
+ - id: debug-statements
12
+
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: v0.14.10
15
+ hooks:
16
+ - id: ruff
17
+ args: [--fix]
18
+ - id: ruff-format
@@ -0,0 +1 @@
1
+ 3.14
sft_cli-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.4
2
+ Name: sft-cli
3
+ Version: 0.1.0
4
+ Summary: An interactive terminal browser for .safetensors files
5
+ Project-URL: Homepage, https://github.com/matanby/sft-cli
6
+ Project-URL: Repository, https://github.com/matanby/sft-cli
7
+ Author: Matan Ben-Yosef
8
+ License: MIT
9
+ Keywords: browser,cli,machine-learning,safetensors,tui
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Utilities
22
+ Requires-Python: >=3.9
23
+ Requires-Dist: textual>=0.40
24
+ Requires-Dist: typer>=0.9
25
+ Description-Content-Type: text/markdown
26
+
27
+ # sft
28
+
29
+ An interactive terminal browser for `.safetensors` files.
30
+
31
+ ## Installation
32
+
33
+ The recommended way to install `sft` is via [uv](https://docs.astral.sh/uv/):
34
+
35
+ ```bash
36
+ uv tool install sft-cli
37
+ ```
38
+
39
+ This makes `sft` available globally as a command-line tool.
40
+
41
+ Alternatively, install via pip:
42
+
43
+ ```bash
44
+ pip install sft-cli
45
+ ```
46
+
47
+ Or install from source:
48
+
49
+ ```bash
50
+ git clone https://github.com/matanby/sft-cli
51
+ cd sft-cli
52
+ pip install -e .
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ ```bash
58
+ sft model.safetensors
59
+ ```
60
+
61
+ ## Features
62
+
63
+ - **Interactive TUI** — Browse tensors with keyboard navigation
64
+ - **Hierarchy View** — Tensors organized by namespace (e.g., `unet.down_blocks.0`)
65
+ - **Fast** — Header-only parsing, instant startup even for multi-GB files
66
+ - **Safe** — Read-only, never loads tensor data
67
+ - **Search** — Find tensors by name with `/`
68
+ - **Filter** — Filter by dtype with `f`
69
+ - **Sort** — Sort by name, size, or rank with `s`
70
+ - **Details** — View tensor details with `Space`
71
+ - **Metadata** — View file metadata with `m`
72
+
73
+ ## Keybindings
74
+
75
+ ### Navigation
76
+ | Key | Action |
77
+ |-----|--------|
78
+ | `↑`/`↓` | Move selection |
79
+ | `←`/`→` | Collapse/Expand tree node |
80
+ | `Enter` | Select/focus node |
81
+ | `Tab` | Switch between tree and table |
82
+ | `g`/`G` | Go to top/bottom |
83
+
84
+ ### Search & Filter
85
+ | Key | Action |
86
+ |-----|--------|
87
+ | `/` | Start search |
88
+ | `f` | Open filter palette |
89
+ | `Esc` | Cancel search/close dialogs |
90
+
91
+ ### Sorting
92
+ | Key | Action |
93
+ |-----|--------|
94
+ | `s` | Cycle sort mode (name ↑↓, size ↑↓, rank ↑↓) |
95
+
96
+ ### Inspection
97
+ | Key | Action |
98
+ |-----|--------|
99
+ | `Space` | Show tensor details |
100
+ | `m` | Show file metadata |
101
+
102
+ ### Application
103
+ | Key | Action |
104
+ |-----|--------|
105
+ | `q` | Quit |
106
+
107
+ ## Technical Details
108
+
109
+ - **Header-only parsing** — sft reads only the safetensors header, never loading tensor data
110
+ - **Instant startup** — Even multi-GB model files open instantly
111
+ - **Memory efficient** — Uses minimal memory regardless of file size
112
+
113
+ ## License
114
+
115
+ MIT
@@ -0,0 +1,89 @@
1
+ # sft
2
+
3
+ An interactive terminal browser for `.safetensors` files.
4
+
5
+ ## Installation
6
+
7
+ The recommended way to install `sft` is via [uv](https://docs.astral.sh/uv/):
8
+
9
+ ```bash
10
+ uv tool install sft-cli
11
+ ```
12
+
13
+ This makes `sft` available globally as a command-line tool.
14
+
15
+ Alternatively, install via pip:
16
+
17
+ ```bash
18
+ pip install sft-cli
19
+ ```
20
+
21
+ Or install from source:
22
+
23
+ ```bash
24
+ git clone https://github.com/matanby/sft-cli
25
+ cd sft-cli
26
+ pip install -e .
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```bash
32
+ sft model.safetensors
33
+ ```
34
+
35
+ ## Features
36
+
37
+ - **Interactive TUI** — Browse tensors with keyboard navigation
38
+ - **Hierarchy View** — Tensors organized by namespace (e.g., `unet.down_blocks.0`)
39
+ - **Fast** — Header-only parsing, instant startup even for multi-GB files
40
+ - **Safe** — Read-only, never loads tensor data
41
+ - **Search** — Find tensors by name with `/`
42
+ - **Filter** — Filter by dtype with `f`
43
+ - **Sort** — Sort by name, size, or rank with `s`
44
+ - **Details** — View tensor details with `Space`
45
+ - **Metadata** — View file metadata with `m`
46
+
47
+ ## Keybindings
48
+
49
+ ### Navigation
50
+ | Key | Action |
51
+ |-----|--------|
52
+ | `↑`/`↓` | Move selection |
53
+ | `←`/`→` | Collapse/Expand tree node |
54
+ | `Enter` | Select/focus node |
55
+ | `Tab` | Switch between tree and table |
56
+ | `g`/`G` | Go to top/bottom |
57
+
58
+ ### Search & Filter
59
+ | Key | Action |
60
+ |-----|--------|
61
+ | `/` | Start search |
62
+ | `f` | Open filter palette |
63
+ | `Esc` | Cancel search/close dialogs |
64
+
65
+ ### Sorting
66
+ | Key | Action |
67
+ |-----|--------|
68
+ | `s` | Cycle sort mode (name ↑↓, size ↑↓, rank ↑↓) |
69
+
70
+ ### Inspection
71
+ | Key | Action |
72
+ |-----|--------|
73
+ | `Space` | Show tensor details |
74
+ | `m` | Show file metadata |
75
+
76
+ ### Application
77
+ | Key | Action |
78
+ |-----|--------|
79
+ | `q` | Quit |
80
+
81
+ ## Technical Details
82
+
83
+ - **Header-only parsing** — sft reads only the safetensors header, never loading tensor data
84
+ - **Instant startup** — Even multi-GB model files open instantly
85
+ - **Memory efficient** — Uses minimal memory regardless of file size
86
+
87
+ ## License
88
+
89
+ MIT
@@ -0,0 +1,77 @@
1
+ [project]
2
+ name = "sft-cli"
3
+ dynamic = ["version"]
4
+ description = "An interactive terminal browser for .safetensors files"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.9"
8
+ authors = [
9
+ { name = "Matan Ben-Yosef" }
10
+ ]
11
+ keywords = ["safetensors", "tui", "browser", "machine-learning", "cli"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "Intended Audience :: Science/Research",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
24
+ "Topic :: Utilities",
25
+ ]
26
+ dependencies = [
27
+ "textual>=0.40",
28
+ "typer>=0.9",
29
+ ]
30
+
31
+ [project.scripts]
32
+ sft = "sft.cli:app"
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/matanby/sft-cli"
36
+ Repository = "https://github.com/matanby/sft-cli"
37
+
38
+ [build-system]
39
+ requires = ["hatchling"]
40
+ build-backend = "hatchling.build"
41
+
42
+ [tool.hatch.version]
43
+ path = "src/sft/__init__.py"
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = ["src/sft"]
47
+
48
+ [tool.ruff]
49
+ target-version = "py39"
50
+ line-length = 88
51
+ src = ["src"]
52
+
53
+ [tool.ruff.lint]
54
+ select = [
55
+ "E", # pycodestyle errors
56
+ "W", # pycodestyle warnings
57
+ "F", # Pyflakes
58
+ "I", # isort
59
+ "B", # flake8-bugbear
60
+ "C4", # flake8-comprehensions
61
+ "UP", # pyupgrade
62
+ "ARG", # flake8-unused-arguments
63
+ "SIM", # flake8-simplify
64
+ ]
65
+ ignore = [
66
+ "E501", # line too long (handled by formatter)
67
+ "B008", # do not perform function calls in argument defaults (needed for typer)
68
+ ]
69
+
70
+ [tool.ruff.lint.isort]
71
+ known-first-party = ["sft"]
72
+
73
+ [dependency-groups]
74
+ dev = [
75
+ "pre-commit>=4.3.0",
76
+ "ruff>=0.14.10",
77
+ ]
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # dependencies = [
4
+ # "numpy",
5
+ # "safetensors",
6
+ # ]
7
+ # ///
8
+ """Create a test safetensors file for development."""
9
+
10
+ import numpy as np
11
+ from safetensors.numpy import save_file
12
+
13
+ # Create a variety of tensors with different shapes and dtypes
14
+ tensors = {
15
+ # Simulating a transformer-like structure
16
+ "model.embed_tokens.weight": np.random.randn(32000, 4096).astype(np.float16),
17
+ "model.layers.0.self_attn.q_proj.weight": np.random.randn(4096, 4096).astype(
18
+ np.float16
19
+ ),
20
+ "model.layers.0.self_attn.k_proj.weight": np.random.randn(4096, 4096).astype(
21
+ np.float16
22
+ ),
23
+ "model.layers.0.self_attn.v_proj.weight": np.random.randn(4096, 4096).astype(
24
+ np.float16
25
+ ),
26
+ "model.layers.0.self_attn.o_proj.weight": np.random.randn(4096, 4096).astype(
27
+ np.float16
28
+ ),
29
+ "model.layers.0.mlp.gate_proj.weight": np.random.randn(11008, 4096).astype(
30
+ np.float16
31
+ ),
32
+ "model.layers.0.mlp.up_proj.weight": np.random.randn(11008, 4096).astype(
33
+ np.float16
34
+ ),
35
+ "model.layers.0.mlp.down_proj.weight": np.random.randn(4096, 11008).astype(
36
+ np.float16
37
+ ),
38
+ "model.layers.0.input_layernorm.weight": np.random.randn(4096).astype(np.float16),
39
+ "model.layers.0.post_attention_layernorm.weight": np.random.randn(4096).astype(
40
+ np.float16
41
+ ),
42
+ "model.layers.1.self_attn.q_proj.weight": np.random.randn(4096, 4096).astype(
43
+ np.float16
44
+ ),
45
+ "model.layers.1.self_attn.k_proj.weight": np.random.randn(4096, 4096).astype(
46
+ np.float16
47
+ ),
48
+ "model.layers.1.self_attn.v_proj.weight": np.random.randn(4096, 4096).astype(
49
+ np.float16
50
+ ),
51
+ "model.layers.1.self_attn.o_proj.weight": np.random.randn(4096, 4096).astype(
52
+ np.float16
53
+ ),
54
+ "model.layers.1.mlp.gate_proj.weight": np.random.randn(11008, 4096).astype(
55
+ np.float16
56
+ ),
57
+ "model.layers.1.mlp.up_proj.weight": np.random.randn(11008, 4096).astype(
58
+ np.float16
59
+ ),
60
+ "model.layers.1.mlp.down_proj.weight": np.random.randn(4096, 11008).astype(
61
+ np.float16
62
+ ),
63
+ "model.layers.1.input_layernorm.weight": np.random.randn(4096).astype(np.float16),
64
+ "model.layers.1.post_attention_layernorm.weight": np.random.randn(4096).astype(
65
+ np.float16
66
+ ),
67
+ "model.norm.weight": np.random.randn(4096).astype(np.float16),
68
+ "lm_head.weight": np.random.randn(32000, 4096).astype(np.float16),
69
+ }
70
+
71
+ # Add some float32 tensors for dtype variety
72
+ tensors["model.layers.0.self_attn.rotary_emb.inv_freq"] = np.random.randn(64).astype(
73
+ np.float32
74
+ )
75
+ tensors["model.layers.1.self_attn.rotary_emb.inv_freq"] = np.random.randn(64).astype(
76
+ np.float32
77
+ )
78
+
79
+ metadata = {
80
+ "format": "pt",
81
+ "framework": "pytorch",
82
+ "model_type": "llama",
83
+ }
84
+
85
+ save_file(tensors, "test_model.safetensors", metadata=metadata)
86
+ print(f"Created test_model.safetensors with {len(tensors)} tensors")
@@ -0,0 +1,3 @@
1
+ """sft — An interactive terminal browser for .safetensors files."""
2
+
3
+ __version__ = "0.1.0"