Polish: atomic zip commit via Path.replace, widen sink params to ExportSink

Path.rename() raises FileExistsError on Windows when the destination
already exists; Path.replace() is atomic cross-platform. Also widen
document_exporter's sink parameters from the concrete
DirectoryExportSink | ZipExportSink union to the ExportSink ABC, so a
future sink implementation is a pure addition rather than requiring
every call site's annotation to change.
This commit is contained in:
stumpylog
2026-07-23 12:59:27 -07:00
parent 7044d8ae5f
commit 581fbab8f3
2 changed files with 7 additions and 6 deletions
+1 -1
View File
@@ -320,7 +320,7 @@ class ZipExportSink(ExportSink):
self._zip = None
if self._delete:
self._wipe_destination()
self._tmp_path.rename(self._zip_path)
self._tmp_path.replace(self._zip_path)
def _wipe_destination(self) -> None:
skip = {self._zip_path.resolve(), self._tmp_path.resolve()}
@@ -30,6 +30,7 @@ if settings.AUDIT_LOG_ENABLED:
from auditlog.models import LogEntry
from documents.export.sinks import DirectoryExportSink
from documents.export.sinks import ExportSink
from documents.export.sinks import StreamingManifestWriter
from documents.export.sinks import ZipExportSink
from documents.file_handling import generate_filename
@@ -245,7 +246,7 @@ class Command(CryptMixin, PaperlessCommand):
if not os.access(self.target, os.W_OK):
raise CommandError("That path doesn't appear to be writable")
sink: DirectoryExportSink | ZipExportSink
sink: ExportSink
if self.zip_export:
sink = ZipExportSink(
self.target,
@@ -264,7 +265,7 @@ class Command(CryptMixin, PaperlessCommand):
with FileLock(settings.MEDIA_LOCK), sink:
self.dump(sink)
def dump(self, sink: DirectoryExportSink | ZipExportSink) -> None:
def dump(self, sink: ExportSink) -> None:
# 1. Create manifest, containing all correspondents, types, tags, storage
# paths, note, documents and ui_settings
_excluded_usernames = ["consumer", "AnonymousUser"]
@@ -487,7 +488,7 @@ class Command(CryptMixin, PaperlessCommand):
def copy_document_files(
self,
document: Document,
sink: DirectoryExportSink | ZipExportSink,
sink: ExportSink,
original_arc: str,
thumbnail_arc: str | None,
archive_arc: str | None,
@@ -536,7 +537,7 @@ class Command(CryptMixin, PaperlessCommand):
def copy_share_link_bundle_file(
self,
bundle: ShareLinkBundle,
sink: DirectoryExportSink | ZipExportSink,
sink: ExportSink,
bundle_arc: str,
) -> None:
"""
@@ -562,7 +563,7 @@ class Command(CryptMixin, PaperlessCommand):
def _write_split_manifest(
self,
sink: DirectoryExportSink | ZipExportSink,
sink: ExportSink,
document_dict: dict,
document: Document,
base_name: Path,