Chore: State the test directory layout in one place (#14171)

The temp directory layout used by the tests was written out four separate
times: once in the documents conftest, once in the paperless checks tests,
once in a fixture local to the NFC upload tests, and once in the helper
behind the old paperless_environment context manager. Each copy covered a
different subset of the settings, so which directories a test actually got
depended on which copy it happened to reach.

The layout now lives in paperless_testing.dirs. build_paperless_dirs owns
where things go and creates them, dirs_settings maps them onto Django
setting names and is pure, and a paperless_dirs fixture in the root conftest
applies that mapping through pytest-django's settings fixture so every app
can reach it. Tests that need a second environment part way through a test
body use the paperless_environment context manager from the same module,
which expresses the identical layout through override_settings. The three
redundant implementations and the old media settings fixture are gone, and
their consumers now take paperless_dirs.
This commit is contained in:
Trenton H
2026-09-21 10:57:11 -07:00
committed by GitHub
parent 48d97b78bb
commit 4c264651e8
10 changed files with 215 additions and 129 deletions
+131
View File
@@ -0,0 +1,131 @@
"""The Paperless-ngx temp directory layout, stated once.
``build_paperless_dirs`` owns where things go and creates them.
``dirs_settings`` owns the mapping onto Django setting names and is pure.
Everything else in the test suite is a caller of these two.
"""
from __future__ import annotations
from contextlib import contextmanager
from dataclasses import dataclass
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import TYPE_CHECKING
from typing import TypedDict
from django.test import override_settings
if TYPE_CHECKING:
from collections.abc import Iterator
@dataclass(frozen=True, slots=True)
class PaperlessDirs:
"""Standard Paperless-ngx directory layout for tests."""
data_dir: Path
scratch_dir: Path
media_dir: Path
consumption_dir: Path
static_dir: Path
index_dir: Path
originals_dir: Path
thumbnail_dir: Path
archive_dir: Path
logging_dir: Path
model_file: Path
media_lock: Path
class DirSettings(TypedDict):
"""The Django settings the layout above maps onto."""
DATA_DIR: Path
SCRATCH_DIR: Path
MEDIA_ROOT: Path
ORIGINALS_DIR: Path
THUMBNAIL_DIR: Path
ARCHIVE_DIR: Path
CONSUMPTION_DIR: Path
LOGGING_DIR: Path
INDEX_DIR: Path
STATIC_ROOT: Path
MODEL_FILE: Path
MEDIA_LOCK: Path
def build_paperless_dirs(root: Path) -> PaperlessDirs:
"""Compute the layout under root and create the directories."""
data_dir = root / "data"
media_dir = root / "media"
documents_dir = media_dir / "documents"
dirs = PaperlessDirs(
data_dir=data_dir,
scratch_dir=root / "scratch",
media_dir=media_dir,
consumption_dir=root / "consume",
static_dir=root / "static",
index_dir=data_dir / "index",
originals_dir=documents_dir / "originals",
thumbnail_dir=documents_dir / "thumbnails",
archive_dir=documents_dir / "archive",
logging_dir=data_dir / "log",
model_file=data_dir / "classification_model.pickle",
media_lock=media_dir / "media.lock",
)
for directory in (
dirs.data_dir,
dirs.scratch_dir,
dirs.media_dir,
dirs.consumption_dir,
dirs.static_dir,
dirs.index_dir,
dirs.originals_dir,
dirs.thumbnail_dir,
dirs.archive_dir,
dirs.logging_dir,
):
directory.mkdir(parents=True, exist_ok=True)
return dirs
def dirs_settings(dirs: PaperlessDirs) -> DirSettings:
"""Map the layout onto Django setting names."""
return DirSettings(
DATA_DIR=dirs.data_dir,
SCRATCH_DIR=dirs.scratch_dir,
MEDIA_ROOT=dirs.media_dir,
ORIGINALS_DIR=dirs.originals_dir,
THUMBNAIL_DIR=dirs.thumbnail_dir,
ARCHIVE_DIR=dirs.archive_dir,
CONSUMPTION_DIR=dirs.consumption_dir,
LOGGING_DIR=dirs.logging_dir,
INDEX_DIR=dirs.index_dir,
STATIC_ROOT=dirs.static_dir,
MODEL_FILE=dirs.model_file,
MEDIA_LOCK=dirs.media_lock,
)
@contextmanager
def paperless_environment() -> Iterator[PaperlessDirs]:
"""A second, isolated environment for the duration of the block.
Only for tests needing a fresh environment part way through a test body,
which a fixture cannot provide. Everything else uses the paperless_dirs
fixture.
"""
from documents.search import reset_backend
with TemporaryDirectory(ignore_cleanup_errors=True) as tmp:
dirs = build_paperless_dirs(Path(tmp))
with override_settings(**dirs_settings(dirs)):
reset_backend()
try:
yield dirs
finally:
reset_backend()