Everything the command line does is available as plain functions. The library never prints and never imports the terminal UI; it returns structured results and raises meaningful exceptions.
import batchvault as bv
result = bv.pack(
["report.pdf", "holiday.mp4"],
"archives",
level=7,
volume_size="100m",
verify=True,
)
print(result.status) # Status.SUCCESS / FAILED / SKIPPED / PARTIAL
for entry in result.entries:
print(entry.source.name, entry.status, entry.message)| Function | Purpose |
|---|---|
bv.pack(files, output, **options) |
Archive files; returns a RunResult |
bv.unpack(source, output, **options) |
Restore files; returns a RunResult |
bv.verify(source, **options) |
Check archives; returns a RunResult |
bv.inspect(source) |
Describe existing archives (source is a manifest, archive folder, volume or list of volumes, not the original files); returns list[InspectEntry] |
bv.list_files(folder, include=, exclude=) |
Files in a folder; list[FileEntry] |
bv.list_archives(folder) |
Archives in a folder; list[FileEntry] |
Paths can be str or pathlib.Path. Sizes accept "10m" or a number of bytes.
bv.pack(
files=(), output="archives", *,
list_file=None, engine="auto", seven_zip=None, format=None,
level="auto", # 0-9, or "auto" to pick one for each file from its type
volume_size="10m", jobs=0,
root=None, # optional override for where stored folders start
include=(), exclude=(), force=False, update=False, verify=False,
manifest=None, allow_archives=False, strict=False, dry_run=False,
password=None, retries=3, sign_key=None, sign_key_password=None,
delete_source=False, confirm=None, progress=None,
)-
engine:"auto","native"or"7zip".format:"xz","gzip","bzip2"or"store"(built-in engine only). -
passwordencrypts the archives (the built-in engine needsbatchvault[crypto]).sign_keyis the path of an Ed25519 private key. -
delete_source=Truedeletes each original after a restore-and-compare proves the archive.confirm(paths) -> bool, if given, is asked first; with noconfirm, deletion is automatic once the check passes. -
jobsis the thread budget;0(the default) uses no worker threads and handles one file at a time. -
Folders are kept automatically: a file is stored under
<output>/<folder>/<name>/andunpackrecreates the tree. The folder starts from the root thatbv.list_files()recorded on eachFileEntry(so the listed folder's name is kept), or, for files you pass directly, from the deepest folder they all share.rootoverrides this with a folder of your choice. Files with the same name in different folders are fine.FileResult.folderandInspectEntry.folderhold the stored folder (""when the file is not in a subfolder).files = bv.list_files("D:/Media") # each entry remembers D:/ as its root bv.pack([f.path for f in files], "archives") # shared folder: keeps below D:/Media # to keep "Media" too, pass the listing's root: bv.pack([f.path for f in files], "archives", root=files[0].root)
result = bv.unpack("archives", "restored", force=False, update=False,
password=None, public_key=None, retries=3)
result = bv.verify("archives", against="originals", password=None,
public_key=None)source can be a manifest, a folder, any volume, or a list of volumes.
public_key requires a valid manifest signature first. max_output_size
("50g" or bytes) refuses an archive that would expand beyond that size before
anything is written; with a manifest, an archive can never expand beyond the
size recorded for its file.
RunResult has:
status:Status.SUCCESS,FAILED,SKIPPEDorPARTIALentries: oneFileResultper file (source,status,message,size,volumes,warnings,archive,stored_size,restored,name,folder). Forpack,sourceis the original file andarchiveits first volume; forunpackandverify,sourceis the archive (its first volume) andrestoredlists the files written.messagedescribes what happened, for example3 volumes, 28.4 MiB -> 9.1 MiB (32%), verified.manifest: path of the manifest that was writtenengine,warnings,count(status)to_dict()for JSON (json.dumps(result.to_dict()))
One failing file does not stop the others; check result.status or
result.count(bv.Status.FAILED).
Problems that stop a run before any work (bad input, damaged manifest, missing
engine, bad signature) raise exceptions that all derive from
bv.BatchVaultError:
InputError, OptionsError, ManifestError, EngineNotFoundError,
EngineError, OutputExistsError, VolumeError, SignatureError,
ConfigError.
try:
bv.unpack("archives", "restored", public_key="batchvault.pub")
except bv.SignatureError as exc:
print("Do not trust this archive:", exc)Pass a callback to follow a run. It is called from worker threads, so keep it thread-safe.
def show(event: bv.ProgressEvent):
print(event.kind, event.source.name, event.status)
bv.pack(["a.bin", "b.bin"], "archives", progress=show)Events are "plan" (once, with the total size and file count), then "start"
and "finish" for each file.
The library only writes to the batchvault logger, and adds no handlers. Send
it where you like:
import logging
logging.getLogger("batchvault").addHandler(logging.StreamHandler())
logging.getLogger("batchvault").setLevel(logging.INFO)Only re-archive what changed, without ever deleting anything:
result = bv.pack(bv_files, "archives", update=True)
print(result.count(bv.Status.SKIPPED), "files were up to date")Restore only if the manifest is signed by you:
bv.unpack("archives", "restored", public_key="batchvault.pub", password="...")Free disk space safely, asking first:
bv.pack(files, "archives", delete_source=True,
confirm=lambda paths: input(f"Delete {len(paths)} files? ") == "y")