diff --git a/src/documents/consumer.py b/src/documents/consumer.py index b940e6f22..5aba56fe6 100644 --- a/src/documents/consumer.py +++ b/src/documents/consumer.py @@ -17,6 +17,7 @@ from filelock import FileLock from rest_framework.reverse import reverse from documents.classifier import load_classifier +from documents.data_models import ConsumableDocument from documents.data_models import DocumentMetadataOverrides from documents.file_handling import create_source_path_directory from documents.file_handling import generate_unique_filename @@ -42,6 +43,7 @@ from documents.plugins.base import AlwaysRunPluginMixin from documents.plugins.base import ConsumeTaskPlugin from documents.plugins.base import NoCleanupPluginMixin from documents.plugins.base import NoSetupPluginMixin +from documents.plugins.helpers import ProgressManager from documents.signals import document_consumption_finished from documents.signals import document_consumption_started from documents.utils import copy_basic_file_stats @@ -254,6 +256,32 @@ class ConsumerFilePhase(str, Enum): class ConsumerPlugin(AlwaysRunPluginMixin, ConsumeTaskPlugin, LoggingMixin): logging_name = "paperless.consumer" + def __init__( + self, + input_doc: ConsumableDocument, + metadata: DocumentMetadataOverrides, + status_mgr: ProgressManager, + base_tmp_dir: Path, + task_id: str, + ) -> None: + super().__init__(input_doc, metadata, status_mgr, base_tmp_dir, task_id) + + self.original_path = self.input_doc.original_file + self.filename = self.metadata.filename or self.input_doc.original_file.name + self.override_title = self.metadata.title + self.override_correspondent_id = self.metadata.correspondent_id + self.override_document_type_id = self.metadata.document_type_id + self.override_tag_ids = self.metadata.tag_ids + self.override_storage_path_id = self.metadata.storage_path_id + self.override_created = self.metadata.created + self.override_asn = self.metadata.asn + self.override_owner_id = self.metadata.owner_id + self.override_view_users = self.metadata.view_users + self.override_view_groups = self.metadata.view_groups + self.override_change_users = self.metadata.change_users + self.override_change_groups = self.metadata.change_groups + self.override_custom_field_ids = self.metadata.custom_field_ids + def setup(self) -> None: pass @@ -474,22 +502,6 @@ class ConsumerPlugin(AlwaysRunPluginMixin, ConsumeTaskPlugin, LoggingMixin): Return the document object if it was successfully created. """ - self.original_path = self.input_doc.original_file - self.filename = self.metadata.filename or self.input_doc.original_file.name - self.override_title = self.metadata.title - self.override_correspondent_id = self.metadata.correspondent_id - self.override_document_type_id = self.metadata.document_type_id - self.override_tag_ids = self.metadata.tag_ids - self.override_storage_path_id = self.metadata.storage_path_id - self.override_created = self.metadata.created - self.override_asn = self.metadata.asn - self.override_owner_id = self.metadata.owner_id - self.override_view_users = self.metadata.view_users - self.override_view_groups = self.metadata.view_groups - self.override_change_users = self.metadata.change_users - self.override_change_groups = self.metadata.change_groups - self.override_custom_field_ids = self.metadata.custom_field_ids - self._send_progress( 0, 100, diff --git a/src/documents/tasks.py b/src/documents/tasks.py index c207b5672..1bc812bfd 100644 --- a/src/documents/tasks.py +++ b/src/documents/tasks.py @@ -162,6 +162,8 @@ def consume_file( finally: plugin.cleanup() + return msg + @shared_task def sanity_check(): diff --git a/src/documents/tests/test_consumer.py b/src/documents/tests/test_consumer.py index 891d6d9e2..5b3eb5f61 100644 --- a/src/documents/tests/test_consumer.py +++ b/src/documents/tests/test_consumer.py @@ -4,11 +4,9 @@ import re import shutil import stat import tempfile -import uuid import zoneinfo -from collections.abc import Generator -from contextlib import contextmanager from pathlib import Path +from unittest import TestCase as StdLibTestCase from unittest import mock from unittest.mock import MagicMock @@ -23,10 +21,7 @@ from guardian.core import ObjectPermissionChecker from documents.consumer import ConsumerError from documents.consumer import ConsumerFilePhase -from documents.consumer import ConsumerPlugin -from documents.data_models import ConsumableDocument from documents.data_models import DocumentMetadataOverrides -from documents.data_models import DocumentSource from documents.models import Correspondent from documents.models import CustomField from documents.models import Document @@ -38,11 +33,11 @@ from documents.parsers import DocumentParser from documents.parsers import ParseError from documents.tasks import sanity_check from documents.tests.utils import DirectoriesMixin -from documents.tests.utils import DummyProgressManager from documents.tests.utils import FileSystemAssertsMixin +from documents.tests.utils import GetConsumerMixin -class TestAttributes(TestCase): +class TestAttributes(StdLibTestCase): TAGS = ("tag1", "tag2", "tag3") def _test_guess_attributes_from_name(self, filename, sender, title, tags): @@ -253,7 +248,12 @@ def fake_magic_from_file(file, mime=False): @mock.patch("documents.consumer.magic.from_file", fake_magic_from_file) -class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): +class TestConsumer( + DirectoriesMixin, + FileSystemAssertsMixin, + GetConsumerMixin, + TestCase, +): def _assert_first_last_send_progress( self, first_status=ConsumerFilePhase.STARTED, @@ -293,26 +293,6 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): ): return FaultyGenericExceptionParser(logging_group, self.dirs.scratch_dir) - @contextmanager - def get_consumer( - self, - filepath: Path, - overrides: DocumentMetadataOverrides | None = None, - source: DocumentSource = DocumentSource.ConsumeFolder, - ) -> Generator[ConsumerPlugin, None, None]: - # Store this for verification - self.status = DummyProgressManager(filepath.name, None) - reader = ConsumerPlugin( - ConsumableDocument(source, original_file=filepath), - overrides or DocumentMetadataOverrides(), - self.status, # type: ignore - self.dirs.scratch_dir, - "task-id", - ) - reader.setup() - yield reader - reader.cleanup() - def setUp(self): super().setUp() @@ -723,7 +703,7 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): self._assert_first_last_send_progress(last_status="FAILED") - @mock.patch("documents.consumer.Consumer._write") + @mock.patch("documents.consumer.ConsumerPlugin._write") def testPostSaveError(self, m): filename = self.get_test_file() m.side_effect = OSError("NO.") @@ -745,9 +725,14 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): @override_settings(FILENAME_FORMAT="{correspondent}/{title}") def testFilenameHandling(self): - filename = self.get_test_file() - document = self.consumer.try_consume_file(filename, override_title="new docs") + with self.get_consumer( + self.get_test_file(), + DocumentMetadataOverrides(title="new docs"), + ) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual(document.title, "new docs") self.assertEqual(document.filename, "none/new docs.pdf") @@ -767,11 +752,15 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): m.side_effect = lambda f, archive_filename=False: get_filename() - filename = self.get_test_file() - Tag.objects.create(name="test", is_inbox_tag=True) - document = self.consumer.try_consume_file(filename, override_title="new docs") + with self.get_consumer( + self.get_test_file(), + DocumentMetadataOverrides(title="new docs"), + ) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual(document.title, "new docs") self.assertIsNotNone(document.title) @@ -798,7 +787,10 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): m.return_value.predict_document_type.return_value = dtype.pk m.return_value.predict_tags.return_value = [t1.pk] - document = self.consumer.try_consume_file(self.get_test_file()) + with self.get_consumer(self.get_test_file()) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual(document.correspondent, correspondent) self.assertEqual(document.document_type, dtype) @@ -811,18 +803,24 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): def test_delete_duplicate(self): dst = self.get_test_file() self.assertIsFile(dst) - doc = self.consumer.try_consume_file(dst) + + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() self._assert_first_last_send_progress() self.assertIsNotFile(dst) - self.assertIsNotNone(doc) - - self._send_progress.reset_mock() + self.assertIsNotNone(document) dst = self.get_test_file() self.assertIsFile(dst) - self.assertRaises(ConsumerError, self.consumer.try_consume_file, dst) + + with self.get_consumer(dst) as consumer: + with self.assertRaises(ConsumerError): + consumer.run() + self.assertIsNotFile(dst) self._assert_first_last_send_progress(last_status="FAILED") @@ -830,31 +828,40 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): def test_no_delete_duplicate(self): dst = self.get_test_file() self.assertIsFile(dst) - doc = self.consumer.try_consume_file(dst) + + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() + + self._assert_first_last_send_progress() self.assertIsNotFile(dst) - self.assertIsNotNone(doc) + self.assertIsNotNone(document) dst = self.get_test_file() self.assertIsFile(dst) - self.assertRaises(ConsumerError, self.consumer.try_consume_file, dst) - self.assertIsFile(dst) + with self.get_consumer(dst) as consumer: + with self.assertRaises(ConsumerError): + consumer.run() + + self.assertIsFile(dst) self._assert_first_last_send_progress(last_status="FAILED") @override_settings(FILENAME_FORMAT="{title}") @mock.patch("documents.parsers.document_consumer_declaration.send") def test_similar_filenames(self, m): shutil.copy( - os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), + os.path.join(Path(__file__).parent, "samples", "simple.pdf"), os.path.join(settings.CONSUMPTION_DIR, "simple.pdf"), ) shutil.copy( - os.path.join(os.path.dirname(__file__), "samples", "simple.png"), + os.path.join(Path(__file__).parent, "samples", "simple.png"), os.path.join(settings.CONSUMPTION_DIR, "simple.png"), ) shutil.copy( - os.path.join(os.path.dirname(__file__), "samples", "simple-noalpha.png"), + os.path.join(Path(__file__).parent, "samples", "simple-noalpha.png"), os.path.join(settings.CONSUMPTION_DIR, "simple.png.pdf"), ) m.return_value = [ @@ -867,15 +874,21 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): }, ), ] - doc1 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.png"), - ) - doc2 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.pdf"), - ) - doc3 = self.consumer.try_consume_file( - os.path.join(settings.CONSUMPTION_DIR, "simple.png.pdf"), - ) + + with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png") as consumer: + consumer.run() + + doc1 = Document.objects.last() + + with self.get_consumer(settings.CONSUMPTION_DIR / "simple.pdf") as consumer: + consumer.run() + + doc2 = Document.objects.last() + + with self.get_consumer(settings.CONSUMPTION_DIR / "simple.png.pdf") as consumer: + consumer.run() + + doc3 = Document.objects.last() self.assertEqual(doc1.filename, "simple.png") self.assertEqual(doc1.archive_filename, "simple.pdf") @@ -888,7 +901,7 @@ class TestConsumer(DirectoriesMixin, FileSystemAssertsMixin, TestCase): @mock.patch("documents.consumer.magic.from_file", fake_magic_from_file) -class TestConsumerCreatedDate(DirectoriesMixin, TestCase): +class TestConsumerCreatedDate(DirectoriesMixin, GetConsumerMixin, TestCase): def setUp(self): super().setUp() @@ -900,17 +913,20 @@ class TestConsumerCreatedDate(DirectoriesMixin, TestCase): THEN: - Should parse the date from the file content """ - src = os.path.join( - os.path.dirname(__file__), - "samples", - "documents", - "originals", - "0000005.pdf", + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000005.pdf" ) - dst = os.path.join(self.dirs.scratch_dir, "sample.pdf") + dst = self.dirs.scratch_dir / "sample.pdf" shutil.copy(src, dst) - document = self.consumer.try_consume_file(dst) + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual( document.created, @@ -927,17 +943,20 @@ class TestConsumerCreatedDate(DirectoriesMixin, TestCase): THEN: - Should parse the date from the filename """ - src = os.path.join( - os.path.dirname(__file__), - "samples", - "documents", - "originals", - "0000005.pdf", + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000005.pdf" ) - dst = os.path.join(self.dirs.scratch_dir, "Scan - 2022-02-01.pdf") + dst = self.dirs.scratch_dir / "Scan - 2022-02-01.pdf" shutil.copy(src, dst) - document = self.consumer.try_consume_file(dst) + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual( document.created, @@ -954,17 +973,20 @@ class TestConsumerCreatedDate(DirectoriesMixin, TestCase): THEN: - Should parse the date from the content """ - src = os.path.join( - os.path.dirname(__file__), - "samples", - "documents", - "originals", - "0000005.pdf", + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000005.pdf" ) - dst = os.path.join(self.dirs.scratch_dir, "Scan - 2022-02-01.pdf") + dst = self.dirs.scratch_dir / "Scan - 2022-02-01.pdf" shutil.copy(src, dst) - document = self.consumer.try_consume_file(dst) + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual( document.created, @@ -983,17 +1005,20 @@ class TestConsumerCreatedDate(DirectoriesMixin, TestCase): THEN: - Should parse the date from the filename """ - src = os.path.join( - os.path.dirname(__file__), - "samples", - "documents", - "originals", - "0000006.pdf", + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000006.pdf" ) - dst = os.path.join(self.dirs.scratch_dir, "0000006.pdf") + dst = self.dirs.scratch_dir / "0000006.pdf" shutil.copy(src, dst) - document = self.consumer.try_consume_file(dst) + with self.get_consumer(dst) as consumer: + consumer.run() + + document = Document.objects.first() self.assertEqual( document.created, @@ -1001,58 +1026,57 @@ class TestConsumerCreatedDate(DirectoriesMixin, TestCase): ) -class PreConsumeTestCase(TestCase): +class PreConsumeTestCase(DirectoriesMixin, GetConsumerMixin, TestCase): def setUp(self) -> None: - # this prevents websocket message reports during testing. - patcher = mock.patch("documents.consumer.Consumer._send_progress") - self._send_progress = patcher.start() - self.addCleanup(patcher.stop) - - return super().setUp() + super().setUp() + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000005.pdf" + ) + self.test_file = self.dirs.scratch_dir / "sample.pdf" + shutil.copy(src, self.test_file) @mock.patch("documents.consumer.run_subprocess") @override_settings(PRE_CONSUME_SCRIPT=None) def test_no_pre_consume_script(self, m): - c = Consumer() - c.working_copy = "path-to-file" - c.run_pre_consume_script() - m.assert_not_called() + with self.get_consumer(self.test_file) as c: + c.run() + m.assert_not_called() @mock.patch("documents.consumer.run_subprocess") - @mock.patch("documents.consumer.Consumer._send_progress") @override_settings(PRE_CONSUME_SCRIPT="does-not-exist") - def test_pre_consume_script_not_found(self, m, m2): - c = Consumer() - c.filename = "somefile.pdf" - c.working_copy = "path-to-file" - self.assertRaises(ConsumerError, c.run_pre_consume_script) + def test_pre_consume_script_not_found(self, m): + with self.get_consumer(self.test_file) as c: + + self.assertRaises(ConsumerError, c.run) + m.assert_not_called() @mock.patch("documents.consumer.run_subprocess") def test_pre_consume_script(self, m): with tempfile.NamedTemporaryFile() as script: with override_settings(PRE_CONSUME_SCRIPT=script.name): - c = Consumer() - c.original_path = "path-to-file" - c.working_copy = "/tmp/somewhere/path-to-file" - c.task_id = str(uuid.uuid4()) - c.run_pre_consume_script() + with self.get_consumer(self.test_file) as c: + c.run() - m.assert_called_once() + m.assert_called_once() - args, _ = m.call_args + args, _ = m.call_args - command = args[0] - environment = args[1] + command = args[0] + environment = args[1] - self.assertEqual(command[0], script.name) - self.assertEqual(command[1], "path-to-file") + self.assertEqual(command[0], script.name) + self.assertEqual(command[1], str(self.test_file)) - subset = { - "DOCUMENT_SOURCE_PATH": c.original_path, - "DOCUMENT_WORKING_PATH": c.working_copy, - "TASK_ID": c.task_id, - } - self.assertDictEqual(environment, {**environment, **subset}) + subset = { + "DOCUMENT_SOURCE_PATH": str(c.original_path), + "DOCUMENT_WORKING_PATH": str(c.working_copy), + "TASK_ID": c.task_id, + } + self.assertDictEqual(environment, {**environment, **subset}) def test_script_with_output(self): """ @@ -1076,10 +1100,8 @@ class PreConsumeTestCase(TestCase): with override_settings(PRE_CONSUME_SCRIPT=script.name): with self.assertLogs("paperless.consumer", level="INFO") as cm: - c = Consumer() - c.working_copy = "path-to-file" - - c.run_pre_consume_script() + with self.get_consumer(self.test_file) as c: + c.run() self.assertIn( "INFO:paperless.consumer:This message goes to stdout", cm.output, @@ -1109,22 +1131,25 @@ class PreConsumeTestCase(TestCase): os.chmod(script.name, st.st_mode | stat.S_IEXEC) with override_settings(PRE_CONSUME_SCRIPT=script.name): - c = Consumer() - c.working_copy = "path-to-file" - self.assertRaises( - ConsumerError, - c.run_pre_consume_script, - ) + with self.get_consumer(self.test_file) as c: + self.assertRaises( + ConsumerError, + c.run, + ) -class PostConsumeTestCase(TestCase): +class PostConsumeTestCase(DirectoriesMixin, GetConsumerMixin, TestCase): def setUp(self) -> None: - # this prevents websocket message reports during testing. - patcher = mock.patch("documents.consumer.Consumer._send_progress") - self._send_progress = patcher.start() - self.addCleanup(patcher.stop) - - return super().setUp() + super().setUp() + src = ( + Path(__file__).parent + / "samples" + / "documents" + / "originals" + / "0000005.pdf" + ) + self.test_file = self.dirs.scratch_dir / "sample.pdf" + shutil.copy(src, self.test_file) @mock.patch("documents.consumer.run_subprocess") @override_settings(POST_CONSUME_SCRIPT=None) @@ -1135,21 +1160,17 @@ class PostConsumeTestCase(TestCase): doc.tags.add(tag1) doc.tags.add(tag2) - Consumer().run_post_consume_script(doc) - + with self.get_consumer(self.test_file) as consumer: + consumer.run_post_consume_script(doc) m.assert_not_called() @override_settings(POST_CONSUME_SCRIPT="does-not-exist") - @mock.patch("documents.consumer.Consumer._send_progress") - def test_post_consume_script_not_found(self, m): + def test_post_consume_script_not_found(self): doc = Document.objects.create(title="Test", mime_type="application/pdf") - c = Consumer() - c.filename = "somefile.pdf" - self.assertRaises( - ConsumerError, - c.run_post_consume_script, - doc, - ) + + with self.get_consumer(self.test_file) as consumer: + with self.assertRaises(ConsumerError): + consumer.run_post_consume_script(doc) @mock.patch("documents.consumer.run_subprocess") def test_post_consume_script_simple(self, m): @@ -1157,7 +1178,8 @@ class PostConsumeTestCase(TestCase): with override_settings(POST_CONSUME_SCRIPT=script.name): doc = Document.objects.create(title="Test", mime_type="application/pdf") - Consumer().run_post_consume_script(doc) + with self.get_consumer(self.test_file) as consumer: + consumer.run_post_consume_script(doc) m.assert_called_once() @@ -1176,9 +1198,8 @@ class PostConsumeTestCase(TestCase): doc.tags.add(tag1) doc.tags.add(tag2) - consumer = Consumer() - consumer.task_id = str(uuid.uuid4()) - consumer.run_post_consume_script(doc) + with self.get_consumer(self.test_file) as consumer: + consumer.run_post_consume_script(doc) m.assert_called_once() @@ -1225,8 +1246,8 @@ class PostConsumeTestCase(TestCase): os.chmod(script.name, st.st_mode | stat.S_IEXEC) with override_settings(POST_CONSUME_SCRIPT=script.name): - c = Consumer() + doc = Document.objects.create(title="Test", mime_type="application/pdf") - c.path = "path-to-file" - with self.assertRaises(ConsumerError): - c.run_post_consume_script(doc) + with self.get_consumer(self.test_file) as consumer: + with self.assertRaises(ConsumerError): + consumer.run_post_consume_script(doc) diff --git a/src/documents/tests/test_double_sided.py b/src/documents/tests/test_double_sided.py index c66594491..64cd7be48 100644 --- a/src/documents/tests/test_double_sided.py +++ b/src/documents/tests/test_double_sided.py @@ -46,7 +46,7 @@ class TestDoubleSided(DirectoriesMixin, FileSystemAssertsMixin, TestCase): with mock.patch( "documents.tasks.ProgressManager", DummyProgressManager, - ), mock.patch("documents.consumer.async_to_sync"): + ): msg = tasks.consume_file( ConsumableDocument( source=DocumentSource.ConsumeFolder, diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index 509a8e54d..8c9f19a71 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -88,7 +88,7 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): return super().setUp() - @mock.patch("documents.consumer.Consumer.try_consume_file") + @mock.patch("documents.consumer.ConsumerPlugin.run") def test_workflow_match(self, m): """ GIVEN: @@ -1467,7 +1467,7 @@ class TestWorkflows(DirectoriesMixin, FileSystemAssertsMixin, APITestCase): expected_str = f"Document matched {trigger} from {w}" self.assertIn(expected_str, info) - @mock.patch("documents.consumer.Consumer.try_consume_file") + @mock.patch("documents.consumer.ConsumerPlugin.run") def test_removal_action_document_consumed_removeall(self, m): """ GIVEN: diff --git a/src/documents/tests/utils.py b/src/documents/tests/utils.py index abdd27017..47ef24f94 100644 --- a/src/documents/tests/utils.py +++ b/src/documents/tests/utils.py @@ -3,6 +3,7 @@ import tempfile import time import warnings from collections import namedtuple +from collections.abc import Generator from collections.abc import Iterator from contextlib import contextmanager from os import PathLike @@ -21,8 +22,10 @@ from django.db.migrations.executor import MigrationExecutor from django.test import TransactionTestCase from django.test import override_settings +from documents.consumer import ConsumerPlugin from documents.data_models import ConsumableDocument from documents.data_models import DocumentMetadataOverrides +from documents.data_models import DocumentSource from documents.parsers import ParseError from documents.plugins.helpers import ProgressStatusOptions @@ -326,6 +329,30 @@ class SampleDirMixin: BARCODE_SAMPLE_DIR = SAMPLE_DIR / "barcodes" +class GetConsumerMixin: + @contextmanager + def get_consumer( + self, + filepath: Path, + overrides: DocumentMetadataOverrides | None = None, + source: DocumentSource = DocumentSource.ConsumeFolder, + ) -> Generator[ConsumerPlugin, None, None]: + # Store this for verification + self.status = DummyProgressManager(filepath.name, None) + reader = ConsumerPlugin( + ConsumableDocument(source, original_file=filepath), + overrides or DocumentMetadataOverrides(), + self.status, # type: ignore + self.dirs.scratch_dir, + "task-id", + ) + reader.setup() + try: + yield reader + finally: + reader.cleanup() + + class DummyProgressManager: """ A dummy handler for progress management that doesn't actually try to