Skip to main content

Atomic filesystem operations for safe batch processing.

Project description

fs-transaction ๐Ÿ›ก๏ธ

PyPI version License: GPL v3 Python Versions Tests

Stop writing corrupted files.

fs-transaction provides Python context managers for atomic, crash-safe file operations. It ensures your file writes are "all-or-nothing," preventing data corruption during crashes, power failures, or concurrent access.

๐Ÿ’ฅ The Problem

In standard Python, writing to a file is risky:

# โš ๏ธ DANGEROUS CODE
with open("database.json", "w") as f:
    f.write(start_processing())
    # <--- CRASH HERE (Power loss, Exception, OOM)
    f.write(finish_processing())
# RESULT: "database.json" is now half-written and corrupted forever.

โœ… The Solution

fs-transaction uses the Write-Replace Pattern:

  1. It writes data to a temporary file in the same directory.
  2. It calls os.fsync() for crash safety.
  3. It performs an atomic os.replace() to swap the new file with the old one.

If the script crashes at any point before step 3, your original file remains 100% untouched and valid.

๐Ÿ†š Why use fs-transaction?

Feature Standard open() fs-transaction
Atomic Writes โŒ No (Partial writes possible) โœ… Yes (All or nothing)
Crash Safety โŒ Low (Data corruption risk) โœ… High (fsync + atomic replace)
Concurrency โŒ Manual locking required โœ… Thread-safe implementation
Cleanup โŒ Manual try/finally blocks โœ… Automatic temp file cleanup
Rollback โŒ Not possible โœ… Automatic on failure
Overwrite Safety โŒ Destroys original โœ… Backup + restore on failure
Ease of Use ๐ŸŸก Native ๐ŸŸข Drop-in replacement

๐Ÿ“ฆ Installation

pip install fs-transaction

๐Ÿš€ Usage

Quick Start: AtomicWrite

Use AtomicWrite as a drop-in replacement for open() when you need crash-safe single-file writes:

from fs_transaction import AtomicWrite
import json

data = {"status": "processing", "items": [1, 2, 3]}

# Even if this block raises an Exception, 'config.json' will NOT be corrupted.
with AtomicWrite("config.json", mode="w") as f:
    f.write(json.dumps(data, indent=2))

print("File written safely and atomically!")

Batch Operations: Transaction

Use Transaction to group multiple file operations into a single atomic unit:

from fs_transaction import Transaction

with Transaction() as t:
    t.write("config.json", json.dumps(new_config), overwrite=True)
    t.move("data/old.csv", "archive/old.csv")
    t.copy("templates/default.yaml", "config/app.yaml")
    t.delete("cache/stale.tmp")
# โœ… All 4 operations succeed together, or none of them happen.

Overwriting Existing Files

By default, operations raise FileExistsError if the destination exists. Use overwrite=True to safely replace:

# AtomicWrite overwrites by default (like open())
with AtomicWrite("existing_file.txt") as f:
    f.write("Updated content")

# Transaction methods require explicit overwrite=True
with Transaction() as t:
    t.write("existing_file.txt", "Updated", overwrite=True)
    t.copy("src.txt", "existing_dst.txt", overwrite=True)
    t.move("new.txt", "existing.txt", overwrite=True)

Dry-Run Mode

Validate all operations without executing them:

with Transaction(dry_run=True) as t:
    t.move("important.txt", "archive/important.txt")
    t.write("report.txt", generate_report())
# โœ… Validation passed, but no files were changed.

Deleting Files Safely

with Transaction() as t:
    t.delete("obsolete_config.json")
    t.delete("old_data.csv")
# Files are backed up before deletion.
# If something fails, they are restored automatically.

๐Ÿ”ง API Reference

AtomicWrite(path, mode='w', overwrite=True, fsync=True, **kwargs)

Context manager for atomic single-file writes.

Parameter Type Default Description
path str | Path โ€” Target file path
mode str 'w' File open mode ('w', 'wb', etc.)
overwrite bool True Replace existing files
fsync bool True Call os.fsync() for crash safety
**kwargs โ€” โ€” Passed to open()

Transaction(dry_run=False, fsync=True)

Context manager for batching multiple file operations atomically.

Parameter Type Default Description
dry_run bool False Validate without executing
fsync bool True Call os.fsync() for crash safety

Methods:

Method Description
write(dst, content, mode='w', overwrite=False) Atomic file write
move(src, dst, overwrite=False) Move/rename a file
copy(src, dst, overwrite=False) Copy a file
delete(path) Delete a file (with backup for rollback)
commit() Manually commit (auto-called on __exit__)

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  Transaction                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚FileMove โ”‚ โ”‚FileCopy โ”‚ โ”‚FileWriteโ”‚ โ”‚FileDel โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚       โ”‚           โ”‚           โ”‚           โ”‚      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚           1. Validate All                   โ”‚ โ”‚
โ”‚  โ”‚           2. Execute All (with backups)      โ”‚ โ”‚
โ”‚  โ”‚           3. Cleanup / Rollback              โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ›ก๏ธ Safety Guarantees

  • Atomicity: Operations are committed as a single unit. Partial state is impossible.
  • Crash Safety: os.fsync() ensures data hits disk before the atomic rename.
  • Backup-Restore: Original files are backed up before overwrite. On failure, they are restored.
  • Thread Safety: Internal locking prevents concurrent commits.
  • Automatic Cleanup: Temp files are always cleaned up, even on exceptions.

๐Ÿค Contributing

Contributions, issues, and feature requests are welcome!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

See CONTRIBUTING.md for detailed guidelines.

๐Ÿ“„ License

This project is licensed under the GNU General Public License v3.0 โ€” see the LICENSE file for details.

๐Ÿ“‹ Changelog

See CHANGELOG.md for a list of changes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fs_transaction-0.2.0.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fs_transaction-0.2.0-py3-none-any.whl (22.9 kB view details)

Uploaded Python 3

File details

Details for the file fs_transaction-0.2.0.tar.gz.

File metadata

  • Download URL: fs_transaction-0.2.0.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fs_transaction-0.2.0.tar.gz
Algorithm Hash digest
SHA256 dbc5a745b37190ef8b792a32993195b80f65038606659c18f4c16c3544d9de78
MD5 808470ea22084b658d13dabb198a6432
BLAKE2b-256 e5c1d7b29e7cee746be650825ddd08c4ac3df8751b6c3a8cea972475a99b8d84

See more details on using hashes here.

Provenance

The following attestation bundles were made for fs_transaction-0.2.0.tar.gz:

Publisher: python-publish.yml on SKAUL05/fs-transaction

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fs_transaction-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fs_transaction-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 22.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fs_transaction-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c1c33050cefc9bc5811068aa0407e398f319b162a38c902a42c4f5313df87485
MD5 6dc2f9b973346372f55a3d34fd22ba51
BLAKE2b-256 495f94a5b2a9de6635957d9681377164ba8f395d2882d7971efb1703b35c1473

See more details on using hashes here.

Provenance

The following attestation bundles were made for fs_transaction-0.2.0-py3-none-any.whl:

Publisher: python-publish.yml on SKAUL05/fs-transaction

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page