Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] skip_noarchive behavior contradicts the documentation since 1.9
### Description

Hi,  
first let me once more thank you all for maintaining this project and advancing it at such quick pace! :)

I updated from 1.7.1 to 1.9.1 (now .2). In 1.7, PAPERLESS_OCR_MODE=skip_noarchive would do exactly as the docs say:
If there is text in the document already, it would skip OCR and not generate an archive. On the other hand, if there is no text in the document, an archive (by definition with no text) and a new version with text overlay would be created.
In 1.9.2, however, the same setting leads to no version with text overlay. I understand this was introduced in [#1442](https://github.com/paperless-ngx/paperless-ngx/pull/1442), but I think the documentation is pretty clear on what should be happening, am I wrong? Right now it states "In addition to skip, paperless won’t create an archived version of your documents _when it finds any text in them_." [Emphasis added]

Of course I'm completely fine with that decision, even though I was relying on this setting and found it very useful.
But if it should be kept as is, I suppose the Docs should be updated to reflect that there will be no archive even for text-free documents.

Also I would like to know if there is now any setting that would result in what happened before:

Document has text -> no archived version, no OCR
Document has no text -> archived version, version with text overlay, OCR

### Steps to reproduce

Set PAPERLESS_OCR_MODE=skip_noarchive, import a document with no text.

### Webserver logs

_No response_

### Paperless-ngx version

1.9.2

### Host OS

Raspbian Buster

### Installation method

Docker - official image

### Browser

_No response_

### Configuration changes

_No response_

### Other

_No response_


Discussion:
I can see how this is confusing.  I think the docs need to be updated to note that `skip_noarchive` will never create an archive file.  To me, if it says `noarchive`, there shouldn't be an archive created ever.
I totally understand the point of not expecting an archive when the flag literally says 'no archive'. But as mentioned, I found the functionality itself quite useful.
It's really only nitpicking, but I don't like the idea too much that the backing folders of my library will now have somewhat inconsistent contents. Either it's `skip` from now on, meaning (as I understand the docs) that every new file in `/originals` will have a backup in `/archive` or file parity stays as is with `skip_noarchive` but new documents will have no text overlay.
Luckily it seems to be enough for now to invalidate the if check in line 280 of parsers.py, which I could figure out despite my limited experience 😅.
If at some point, you think it's a good idea to reintroduce the behavior under a more literal flag, all the better. But as stated, this is a highly specific objection and mostly owed to me being neurotic about the file level consistency. 😉

Thanks for the hard work and the quick reply! Please feel free to close this. (presumably with the docs update PR?)

Resolving patch:
diff --git a/src/paperless_tesseract/parsers.py b/src/paperless_tesseract/parsers.py
--- a/src/paperless_tesseract/parsers.py
+++ b/src/paperless_tesseract/parsers.py
@@ -249,16 +249,22 @@ def parse(self, document_path, mime_type, file_name=None):
 
         if mime_type == "application/pdf":
             text_original = self.extract_text(None, document_path)
-            original_has_text = text_original and len(text_original) > 50
+            original_has_text = text_original is not None and len(text_original) > 50
         else:
             text_original = None
             original_has_text = False
 
+        # If the original has text, and the user doesn't want an archive,
+        # we're done here
         if settings.OCR_MODE == "skip_noarchive" and original_has_text:
             self.log("debug", "Document has text, skipping OCRmyPDF entirely.")
             self.text = text_original
             return
 
+        # Either no text was in the original or there should be an archive
+        # file created, so OCR the file and create an archive with any
+        # test located via OCR
+
         import ocrmypdf
         from ocrmypdf import InputFileError, EncryptedPdfError
 
@@ -276,9 +282,7 @@ def parse(self, document_path, mime_type, file_name=None):
             self.log("debug", f"Calling OCRmyPDF with args: {args}")
             ocrmypdf.ocr(**args)
 
-            # Only create archive file if archiving isn't being skipped
-            if settings.OCR_MODE != "skip_noarchive":
-                self.archive_path = archive_path
+            self.archive_path = archive_path
 
             self.text = self.extract_text(sidecar_file, archive_path)
 


Test patch:
diff --git a/src/paperless_tesseract/tests/test_parser.py b/src/paperless_tesseract/tests/test_parser.py
--- a/src/paperless_tesseract/tests/test_parser.py
+++ b/src/paperless_tesseract/tests/test_parser.py
@@ -341,6 +341,17 @@ def test_multi_page_analog_pages_skip(self):
 
     @override_settings(OCR_PAGES=2, OCR_MODE="redo")
     def test_multi_page_analog_pages_redo(self):
+        """
+        GIVEN:
+            - File with text contained in images but no text layer
+            - OCR of only pages 1 and 2 requested
+            - OCR mode set to redo
+        WHEN:
+            - Document is parsed
+        THEN:
+            - Text of page 1 and 2 extracted
+            - An archive file is created
+        """
         parser = RasterisedDocumentParser(None)
         parser.parse(
             os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"),
@@ -352,6 +363,17 @@ def test_multi_page_analog_pages_redo(self):
 
     @override_settings(OCR_PAGES=1, OCR_MODE="force")
     def test_multi_page_analog_pages_force(self):
+        """
+        GIVEN:
+            - File with text contained in images but no text layer
+            - OCR of only page 1 requested
+            - OCR mode set to force
+        WHEN:
+            - Document is parsed
+        THEN:
+            - Only text of page 1 is extracted
+            - An archive file is created
+        """
         parser = RasterisedDocumentParser(None)
         parser.parse(
             os.path.join(self.SAMPLE_FILES, "multi-page-images.pdf"),
@@ -395,7 +417,7 @@ def test_skip_noarchive_notext(self):
             - Document is parsed
         THEN:
             - Text from images is extracted
-            - No archive file is created
+            - An archive file is created with the OCRd text
         """
         parser = RasterisedDocumentParser(None)
         parser.parse(
@@ -408,15 +430,26 @@ def test_skip_noarchive_notext(self):
             ["page 1", "page 2", "page 3"],
         )
 
-        self.assertIsNone(parser.archive_path)
+        self.assertIsNotNone(parser.archive_path)
 
     @override_settings(OCR_MODE="skip")
     def test_multi_page_mixed(self):
+        """
+        GIVEN:
+            - File with some text contained in images and some in text layer
+            - OCR mode set to skip
+        WHEN:
+            - Document is parsed
+        THEN:
+            - Text from images is extracted
+            - An archive file is created with the OCRd text and the original text
+        """
         parser = RasterisedDocumentParser(None)
         parser.parse(
             os.path.join(self.SAMPLE_FILES, "multi-page-mixed.pdf"),
             "application/pdf",
         )
+        self.assertIsNotNone(parser.archive_path)
         self.assertTrue(os.path.isfile(parser.archive_path))
         self.assertContainsStrings(
             parser.get_text().lower(),
@@ -438,7 +471,7 @@ def test_multi_page_mixed_no_archive(self):
             - Document is parsed
         THEN:
             - Text from images is extracted
-            - No archive file is created
+            - No archive file is created as original file contains text
         """
         parser = RasterisedDocumentParser(None)
         parser.parse(