|
|
||
|---|---|---|
| iso_scalpel | ||
| resources/icons | ||
| tests | ||
| BLOG.md | ||
| LICENSE | ||
| MANIFEST.in | ||
| QUICKSTART.md | ||
| README.md | ||
| cli.py | ||
| main.py | ||
| pyproject.toml | ||
| requirements.txt | ||
README.md
ISO Scalpel
A disc-image editor for ISO 9660 and UDF, built with PySide6 (Qt 6) and pycdlib. Runs as a gui or cli.
Author: Jeremy Anderson · info@dcos.net · https://dcos.net License: GPL-2.0
Features
- ISO 9660 interchange levels 1, 2, 3
- Rock Ridge 1.09 / 1.12
- Joliet 1 / 2 / 3
- UDF 2.50 / 2.60
- El Torito boot images (BIOS and EFI)
- Add, extract, rename, delete files and folders
- Volume metadata editing
- Filesystem diff between two images
- Command-line interface
- Split-navigation GUI with tabs, breadcrumbs, and filtering
Requirements
- Python 3.10+
- PySide6 >= 6.6
- pycdlib >= 1.13
On a minimal Linux install you also need the Qt runtime libraries:
# Debian / Ubuntu
sudo apt install libegl1 libgl1 libglib2.0-0 libfontconfig1 \
libdbus-1-3 libxkbcommon0 libxcb-cursor0
Install
tar xzf iso-scalpel-1.1.0.tar.gz
cd iso_scalpel_py
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Running the GUI
python main.py # empty window
python main.py my_image.iso # open an image
The interface is a split-nav file manager: two panes side by side, each
with breadcrumb navigation, back/forward/up history, a live filter box,
and tabs. Either pane can host the filesystem or the ISO image; press
Ctrl+Shift+X to swap them.
Running the CLI
python cli.py --help
Commands:
| Command | Description |
|---|---|
new |
Create a new ISO image |
list |
List the contents of an image |
info |
Show volume metadata |
add |
Add a file or directory to an image |
extract |
Extract a file or directory |
rm |
Remove an entry |
boot |
Show or configure El Torito boot |
diff |
Compare the filesystems of two images |
gui |
Launch the graphical interface |
Examples:
# create a UDF image with a file in it
python cli.py new disc.iso -l MYDISC --joliet 3 --rock-ridge 1.09 --udf 2.60 \
--add readme.txt
# list contents
python cli.py list disc.iso
python cli.py list disc.iso / --view udf
# show metadata
python cli.py info disc.iso
# add a directory tree
python cli.py add disc.iso ./myfolder /sub
# extract a file
python cli.py extract disc.iso /readme.txt ./out.txt
# remove an entry
python cli.py rm disc.iso /old.txt
# compare two images (filesystem diff)
python cli.py diff old.iso new.iso
python cli.py diff old.iso new.iso --all
The diff command follows the POSIX diff(1) exit-code convention:
0 when the images are identical, 1 when they differ, 2 on error.
This makes it scriptable in a shell if / && pipeline.
The diff view
diff compares two images at the filesystem level — which entries were
added, removed, or modified — without comparing file contents. The GUI
exposes the same comparison under Tools → Compare Images…
(Ctrl+D), showing a unified tree with status indicators:
+added (only in B)-removed (only in A)Mmodified (in both, different size or date)=unchanged
Output example:
--- old.iso
+++ new.iso
2 added, 1 removed, 1 modified, 14 unchanged
+ /newfile.txt (2048 bytes)
- /oldfile.txt (1024 bytes)
M /readme.txt (12 -> 48 bytes)
(14 entries unchanged)
Keyboard shortcuts
| Shortcut | Action |
|---|---|
Ctrl+N |
New image |
Ctrl+O |
Open image |
Ctrl+S |
Save |
Ctrl+Shift+S |
Save As… |
Ctrl+W |
Close image / close tab |
Ctrl+Q |
Quit |
Alt+← / Alt+→ |
Back / forward |
Alt+↑ |
Up to parent |
Ctrl+L |
Go to location |
Ctrl+Shift+X |
Swap panes |
Ctrl+T |
New tab |
Insert |
Add to image |
Ctrl+E |
Extract |
Ctrl+Shift+N |
New folder |
F2 |
Rename |
Delete |
Delete |
Ctrl+F |
Filter |
Ctrl+A |
Select all |
Alt+Enter |
Properties |
Ctrl+B |
Boot image |
Ctrl+D |
Compare images |
F5 |
Refresh |
Ctrl+, |
Preferences |
Project layout
iso_scalpel_py/
├── main.py # GUI entry point
├── cli.py # CLI entry point
├── requirements.txt
├── README.md
├── QUICKSTART.md
├── BLOG.md
├── LICENSE
└── iso_scalpel/
├── __init__.py # version metadata
├── app.py # QApplication + stylesheet
├── main_window.py # split-nav window, menus, toolbar
├── iso_handler.py # pycdlib wrapper (no Qt dependency)
├── iso_record.py # record abstraction
├── iso_model.py # Qt tree model
├── diff.py # filesystem diff engine (no Qt dependency)
├── config.py # settings persistence
├── dialogs/ # New, Properties, Boot, Extract, Diff, Settings, About
└── widgets/ # filesystem + ISO panes
iso_handler.py and diff.py are GUI-agnostic. They never import
PySide6, so the entire engine can be driven from a script or test
harness with no display attached.
Configuration
Settings are stored as JSON:
- Linux:
~/.config/iso-scalpel/settings.json - macOS:
~/Library/Application Support/iso-scalpel/settings.json - Windows:
%APPDATA%\iso-scalpel\settings.json
Coding standards
The codebase is held to a fixed set of rules enforced by
ruff (configured in pyproject.toml):
- PEP 8 style and PEP 585 / 604 annotations (
list[str],str | None). - SEI CERT error handling: no blind
except Exceptionand no silenttry/except/pass. pycdlib calls catch a narrow tuple (PyCdlibException,OSError,ValueError,KeyError); top-level CLI and GUI error boundaries opt out per-occurrence with an auditable# noqa: BLE001 -- <reason>comment. - MISRA-aligned immutability: no mutable default arguments, no function
calls in defaults (
parent=QModelIndex()uses a module-level singleton). - POSIX discipline: entry-point scripts (
main.py,cli.py) carry a shebang on line 1 and the executable bit;cli.py diffexits0/1/2perdiff(1). - Dispatch tables over if/elif chains for status, name-type, and
flag parsing (
_FLAG_TABLE,_PATH_KWARG,_NAME_TYPE_PROBES,_PKG_MANAGERS,VolumeProperties.extensions). - Comprehensions and
next()over explicit loops where the body is a pure filter/map (list_dir,available_name_types,from_pycdlibmodified-time probe,_human_size). - Step-down / guard clauses at choice forks: early
returnon the unhappy path, main logic at the top indentation level.
Run the checks with:
pip install -e '.[dev]' # installs pytest + ruff
ruff check . # lint (must be clean)
python -m pytest # test suite
License
Copyright © 2026 Jeremy Anderson info@dcos.net.
GPL-2.0. See LICENSE for the full text. This program comes with ABSOLUTELY NO WARRANTY.
ISO Scalpel is an independent project. No source code from any other ISO editing tool was used.