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.1.0a1

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.1.0a1
File Size Uploaded
remanence-0.1.0a1.tar.gz 714.2 kB Details

Built distribution (wheel)

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

Total release size: 2.0 MB

Release files / remanence-0.1.0a1.tar.gz

Download URL remanence-0.1.0a1.tar.gz
Size 714.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7fd5e8d9ed3e2558bf79f61d0bd9ec207e0edaf36c41977fbfe855c730837e8b
BLAKE2b-256 checksum
How to use checksums
9b1e2a387756adcf23425fafd84ae6343760eeaca1851815cb152b6f494ff497
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.1.0a1-cp310-abi3-win_amd64.whl

Download URL remanence-0.1.0a1-cp310-abi3-win_amd64.whl
Size 1.3 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
d55bb578d4fa2442ec112f94059256354b0f4a5c298b3544152827607b91a266
BLAKE2b-256 checksum
How to use checksums
f9dbb3d6e52a518df0520fe5171e8ee1de0bc2ea6206d0a79b674baa74e8f29a
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