Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docassemble/AssemblyLine/al_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -2277,6 +2277,7 @@ def as_pdf(
pdfa: bool = False,
append_matching_suffix: bool = True,
ensure_parity: Optional[Literal["even", "odd"]] = None,
use_previously_cached_files: bool = False,
) -> Optional[DAFile]:
"""
Returns a consolidated PDF of all enabled documents in the bundle.
Expand All @@ -2289,6 +2290,10 @@ def as_pdf(
Used primarily to enhance automated tests.
ensure_parity (Optional[Literal["even", "odd"]]): Ensures the number of pages in the PDF is even or odd. If omitted,.
no parity is enforced. Defaults to None.
use_previously_cached_files (bool): Reuse a final bundled PDF previously
assembled in the background, if available. Defaults to False. Custom
keys, PDF/A, and page parity requests use the normal assembly path,
because the background cache does not identify those options.

Returns:
Optional[DAFile]: Combined PDF file or None if no documents are enabled.
Expand All @@ -2306,6 +2311,18 @@ def as_pdf(
${ al_user_bundle.as_pdf(key="preview") }
```
"""
if (
use_previously_cached_files
and key == "final"
and not pdfa
and ensure_parity is None
and not getattr(self, "default_parity", None)
and hasattr(self, "_downloadable_files")
):
_, _, bundled_pdf = self._downloadable_files
if bundled_pdf is not None:
return bundled_pdf

safe_key = space_to_underscore(key)
if pdfa:
safe_key = safe_key + "-pdfa"
Expand Down
60 changes: 60 additions & 0 deletions docassemble/AssemblyLine/test_al_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import json
import pickle
import tempfile

import pikepdf
import unittest
from unittest.mock import Mock
from html import unescape
Expand Down Expand Up @@ -701,3 +704,60 @@ def test_original_value_exceeds_trigger_with_newlines(self):

if __name__ == "__main__":
unittest.main()


class TestBackgroundBundlePdf(unittest.TestCase):
def make_bundle(self):
pdf = FakePdf()
bundle = ALDocumentBundle(
"bundle", elements=[FakeSingleDoc(pdf)], title="Bundle", filename="bundle"
)
return bundle, pdf

def test_opt_in_returns_background_pdf_without_evaluating_documents(self):
bundle, _ = self.make_bundle()
cached_pdf = FakePdf("cached.pdf")
bundle._downloadable_files = ([], None, cached_pdf)
with patch.object(
bundle, "enabled_documents", side_effect=AssertionError("regenerated")
):
self.assertIs(bundle.as_pdf(use_previously_cached_files=True), cached_pdf)

def test_default_keeps_foreground_behavior(self):
bundle, foreground = self.make_bundle()
bundle._downloadable_files = ([], None, FakePdf("cached.pdf"))
self.assertIs(bundle.as_pdf(), foreground)

def test_absent_or_missing_background_pdf_falls_back(self):
for cached in [None, ([], None, None)]:
with self.subTest(cached=cached):
bundle, foreground = self.make_bundle()
if cached is not None:
bundle._downloadable_files = cached
self.assertIs(
bundle.as_pdf(use_previously_cached_files=True), foreground
)

def test_custom_versions_and_pdfa_do_not_reuse_unknown_cache_options(self):
for options in [{"key": "preview"}, {"pdfa": True}]:
with self.subTest(options=options):
bundle, foreground = self.make_bundle()
bundle._downloadable_files = ([], None, FakePdf("cached.pdf"))
self.assertIs(
bundle.as_pdf(use_previously_cached_files=True, **options),
foreground,
)

def test_parity_request_uses_foreground_pdf(self):
bundle, foreground = self.make_bundle()
bundle._downloadable_files = ([], None, FakePdf("cached.pdf"))
with tempfile.NamedTemporaryFile(suffix=".pdf") as pdf_file:
with pikepdf.Pdf.new() as pdf:
pdf.add_blank_page()
pdf.add_blank_page()
pdf.save(pdf_file.name)
foreground.path = lambda: pdf_file.name
self.assertIs(
bundle.as_pdf(use_previously_cached_files=True, ensure_parity="even"),
foreground,
)