From 47e0aba5a5a27109e7d5336e1fc3c5314f550768 Mon Sep 17 00:00:00 2001 From: Jayant-Kernel Date: Sun, 17 May 2026 11:53:13 +0530 Subject: [PATCH] pdf-converter: add renderer dispatch --- qubespdfconverter/server.py | 23 +++++++++++++++---- qubespdfconverter/tests/test_password.py | 28 +++++++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/qubespdfconverter/server.py b/qubespdfconverter/server.py index c2ae071..60f9e5c 100644 --- a/qubespdfconverter/server.py +++ b/qubespdfconverter/server.py @@ -146,6 +146,21 @@ async def render_page(self, page, prefix): return rep +RENDERERS = { + "pdf": PdfRenderer, +} + + +def create_renderer(name, path, password=b"", resolution=RESOLUTION): + """Create a renderer for the requested converter type.""" + try: + renderer_cls = RENDERERS[name] + except KeyError as exc: + raise ValueError(f"Unsupported renderer: {name}") from exc + + return renderer_cls(path, password, resolution) + + class Representation: """Umbrella object for a file's initial and final representations @@ -220,10 +235,9 @@ class BatchEntry: class BaseFile: """Unsanitized file""" - def __init__(self, path, password=b""): + def __init__(self, path, renderer): self.path = path - self.password = password - self.renderer = PdfRenderer(path, password, args.resolution) + self.renderer = renderer self.pagenums = 0 self.batch = None @@ -333,7 +347,8 @@ def main(): with TemporaryDirectory(prefix="qvm-sanitize") as tmpdir: pdf_path = Path(tmpdir, "original") pdf_path.write_bytes(data) - base = BaseFile(pdf_path, password) + renderer = create_renderer("pdf", pdf_path, password, args.resolution) + base = BaseFile(pdf_path, renderer) try: asyncio.run(base.sanitize()) diff --git a/qubespdfconverter/tests/test_password.py b/qubespdfconverter/tests/test_password.py index 784682f..c6263d5 100644 --- a/qubespdfconverter/tests/test_password.py +++ b/qubespdfconverter/tests/test_password.py @@ -11,7 +11,7 @@ from pathlib import Path from unittest import mock -from qubespdfconverter.server import BaseFile, PdfRenderer +from qubespdfconverter.server import BaseFile, PdfRenderer, create_renderer class TC_ServerPassword(unittest.IsolatedAsyncioTestCase): @@ -20,7 +20,8 @@ class TC_ServerPassword(unittest.IsolatedAsyncioTestCase): def test_pagenums_includes_password_flags(self): """pdfinfo receives -opw/-upw when a password is provided.""" with tempfile.NamedTemporaryFile(suffix=".pdf") as f: - base = BaseFile(Path(f.name), password=b"secret") + renderer = PdfRenderer(Path(f.name), password=b"secret") + base = BaseFile(Path(f.name), renderer) mock_result = mock.Mock() mock_result.stdout = b"Pages: 3\n" @@ -36,7 +37,8 @@ def test_pagenums_includes_password_flags(self): def test_pagenums_omits_password_flags_when_empty(self): """pdfinfo does not receive password flags when password is empty.""" with tempfile.NamedTemporaryFile(suffix=".pdf") as f: - base = BaseFile(Path(f.name), password=b"") + renderer = PdfRenderer(Path(f.name), password=b"") + base = BaseFile(Path(f.name), renderer) mock_result = mock.Mock() mock_result.stdout = b"Pages: 2\n" @@ -91,6 +93,26 @@ async def test_create_page_image_omits_password_flags_when_empty(self): self.assertNotIn("-opw", cmd) self.assertNotIn("-upw", cmd) + def test_create_renderer_returns_pdf_renderer(self): + """The server dispatch table creates the PDF renderer.""" + with tempfile.NamedTemporaryFile(suffix=".pdf") as f: + renderer = create_renderer( + "pdf", + Path(f.name), + password=b"secret", + resolution=200, + ) + + self.assertIsInstance(renderer, PdfRenderer) + self.assertEqual(renderer.password, b"secret") + self.assertEqual(renderer.resolution, "200") + + def test_create_renderer_rejects_unknown_type(self): + """Unknown renderer names fail before any conversion starts.""" + with tempfile.NamedTemporaryFile(suffix=".pdf") as f: + with self.assertRaises(ValueError): + create_renderer("office", Path(f.name)) + class TC_ServerBackwardCompat(unittest.TestCase): """Tests for backward-compatible stdin parsing in main()."""