Staged file publication writes a complete candidate before replacing the pathname readers use for the accepted report.
Python file project: stage a report before replacing the visible file
Operation contract
The receipt summary validates all bounded integer amounts before opening its candidate file. It creates that file in the target directory, writes UTF-8 text, flushes the language buffer and requests fsync on the file before os.replace. A failed validation leaves the prior report visible. Finally removes a leftover candidate if an I/O failure prevented replacement.
Failure and ownership boundary
The project uses an owned temporary directory and a fixed target name. It does not defend an attacker-controlled directory, coordinate multiple writers or prove crash durability. A deployment needs platform-specific directory synchronization, permission preservation and recovery tests. A replacement can fail across filesystems, which is why the candidate is created beside the target. Python pathlib files: specify encoding and close the resource owner and Python SQLite project: transactional batches, duplicate IDs and reopen checks provide different publication primitives.
Working program
import os
import tempfile
from pathlib import Path
def publish_report(target, amounts):
if len(amounts) > 32 or any(type(amount) is not int or not 0 <= amount <= 1000000 for amount in amounts):
raise ValueError("report amounts")
candidate = None
try:
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", dir=target.parent, delete=False) as output:
candidate = Path(output.name)
output.write("total_minor=" + str(sum(amounts)) + "\n")
output.flush()
os.fsync(output.fileno())
os.replace(candidate, target)
finally:
if candidate is not None:
candidate.unlink(missing_ok=True)
with tempfile.TemporaryDirectory() as directory:
target = Path(directory) / "report.txt"
publish_report(target, [125, 75])
try:
publish_report(target, [125, True])
except ValueError:
print("invalid report rejected")
print(target.read_text(encoding="utf-8").strip())Output
invalid report rejected
total_minor=200Costs and limits
Validation scans n amounts; the report is tiny. Filesystem write, sync and replacement costs depend on the platform and storage. Atomic visibility and crash durability are separate claims.
Common Mistakes
- Do not publish a candidate before its complete validation and write succeed.
- File fsync alone is not a tested cross-platform directory durability guarantee.
Connected lessons
Python pathlib files: specify encoding and close the resource owner, Python CSV ingestion: cap bytes, rows and fields before publication, Python SQLite project: transactional batches, duplicate IDs and reopen checks.
Related Python operation checks
Python unittest.mock: inject a collaborator failure before publication.
