Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

remanence

Read and analyse disk images from Python — floppy and hard disk images from vintage and modern systems alike.

Give it an image file and it will tell you what the file actually is, what disk geometry it records, which drive it came from, and what filesystem is on it — then let you list and read the files inside. It handles raw images, QCOW2, VDI, Heathkit H8D, ZIP and 7z archives, KryoFlux flux captures and P64, and it reads HDOS, CBM DOS and FAT filesystems.

This is the Python interface to remanence-lib, which is written in Rust. The wheel contains everything it needs: no other packages to install, no external tools to call, not even for decompression.

This is an alpha release. The API will change without notice, and installing needs --pre. The package is currently tested on Windows only — the code for Linux and macOS is there, but it is untested and unsupported for now.

Install

pip install --pre remanence

Needs Python 3.10 or newer. One wheel covers every supported version, and type hints are included, so editors and type checkers work out of the box.

Getting started

You open the file; the library never opens it behind your back. You also tell it what format the file is, and it checks that claim against the file's actual contents — if you say H8D and hand it a ZIP, it says so rather than guessing.

import remanence

print(remanence.formats())          # the formats you can name

session = remanence.Session()
with open("disk.h8d", "rb") as source:
    medium = session.load_media(source, "h8d")

# What the file turned out to be, layer by layer, with a confidence
# score and a plain-language reason for each.
for layer in medium.identify().layers:
    print(layer.kind, layer.id, layer.confidence)

Because you opened the file, you control whether it can be written to. The library asks your file handle that one question, respects the answer, and takes no lock of its own. Closing your Python file afterwards is safe — the library keeps its own copy of the descriptor.

Reading the disk

Disk geometry comes back with a note of where each number came from, and if two sources disagree, you are told rather than being handed one answer:

geometry = medium.geometry
print(geometry.cylinders, geometry.heads,
      geometry.sectors_per_track, geometry.sector_bytes)
for reading in geometry.readings:
    print(" ", reading.source, reading.at, reading.detail)

first = medium.read_sector(0, 0, 1)     # sectors are numbered from one

Reading the files

Files live behind a partition. An image with no partition table has a single partition covering the whole disk, at index 0. You name the filesystem you expect and the library verifies it:

filesystem = medium.partition(0).filesystem_as("hdos")
for entry in filesystem.entries():
    print(entry.name, entry.size_bytes)
    # Anything else this filesystem records about the file — an HDOS
    # catalog date, its flag letters — in its own terms.
    for fact in entry.declared:
        print("   ", fact.key, fact.value)

data = filesystem.get_file("HDOS.SYS").bytes()

Drives

You can model the drive a disk belonged in, as specific as the real ones — a Commodore 1541, a Heathkit H-17, a hard disk. Putting a disk in a drive and taking it out again changes nothing about the disk:

device = session.add_device("h17")
print(device.attachment)            # heathfloppy0
device.insert(medium.id)
device.eject()                      # the drive stays, and so does the disk

session.release_media(medium.id)    # this is what actually discards it

Identifying a file before you commit to it

discover_media answers "what is this?" on its own, and hands back a result you can pass straight to a load, so the file is only opened once:

discovery = remanence.discover_media("disk.h8d", writable=False)
print(discovery.article, discovery.accepting_devices, discovery.device_type)
found = session.load_discovery(discovery)

# Or do both at once, when the format says which drive recorded it.
drive = session.add_device_for("disk.h8d", writable=False)

Beyond the basics

There is more than fits here: flux captures decoded down to bit and byte level, KryoFlux capture sets loaded as a group, CBM DOS directories, and creating blank disks from scratch. The full documentation covers all of it with examples.

Links

License

GPL-3.0-only. See LICENSE.

Release files for remanence 0.0.1a7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for remanence 0.0.1a7
File Size Uploaded
remanence-0.0.1a7.tar.gz 685.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for remanence 0.0.1a7
File Interpreter ABI Platform
remanence-0.0.1a7-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details

Total release size: 1.9 MB

Release files / remanence-0.0.1a7.tar.gz

Download URL remanence-0.0.1a7.tar.gz
Size 685.2 kB
Tags Source
SHA-256 checksum
How to use checksums
507d2898335eec627c3a514083880469ba5b1f7e768ab13a0aa3abf7d563a1c4
BLAKE2b-256 checksum
How to use checksums
f78ea86fd5cd941ffc705289fbce5bf4cc791bf8456119f6e557a0bfe25f0972
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / remanence-0.0.1a7-cp310-abi3-win_amd64.whl

Download URL remanence-0.0.1a7-cp310-abi3-win_amd64.whl
Size 1.2 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
821cae6cf3e42323a1a0ba13a9f5cd560b10650725331e45c153e3d091c8c629
BLAKE2b-256 checksum
How to use checksums
19dc1405ea9e8d73d78c2aeb532cc542bd288c8ab80ffc90dbf861ba1d8b1ce8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page