refactor: replace Namespace with OCROptions in plugins and validation
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
+11
-23
@@ -10,7 +10,6 @@ import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
from shutil import copyfileobj
|
||||
@@ -50,7 +49,7 @@ def check_platform() -> None:
|
||||
|
||||
|
||||
def check_options_languages(
|
||||
options: Union[Namespace, OCROptions], ocr_engine_languages: list[str]
|
||||
options: Union[OCROptions], ocr_engine_languages: list[str]
|
||||
) -> None:
|
||||
if not ocr_engine_languages:
|
||||
return
|
||||
@@ -76,7 +75,7 @@ def check_options_languages(
|
||||
|
||||
|
||||
|
||||
def check_options_sidecar(options: Union[Namespace, OCROptions]) -> None:
|
||||
def check_options_sidecar(options: Union[OCROptions]) -> None:
|
||||
if options.sidecar == '\0':
|
||||
if options.output_file == '-':
|
||||
raise BadArgsError("--sidecar filename needed when output file is stdout.")
|
||||
@@ -91,7 +90,7 @@ def check_options_sidecar(options: Union[Namespace, OCROptions]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def check_options_preprocessing(options: Union[Namespace, OCROptions]) -> None:
|
||||
def check_options_preprocessing(options: Union[OCROptions]) -> None:
|
||||
if options.clean_final:
|
||||
options.clean = True
|
||||
if options.unpaper_args and not options.clean:
|
||||
@@ -119,37 +118,26 @@ def check_options_preprocessing(options: Union[Namespace, OCROptions]) -> None:
|
||||
|
||||
|
||||
|
||||
def _check_plugin_invariant_options(options: Union[Namespace, OCROptions]) -> None:
|
||||
def _check_plugin_invariant_options(options: Union[OCROptions]) -> None:
|
||||
check_platform()
|
||||
check_options_sidecar(options)
|
||||
check_options_preprocessing(options)
|
||||
|
||||
|
||||
def _check_plugin_options(
|
||||
options: Union[Namespace, OCROptions], plugin_manager: PluginManager
|
||||
options: OCROptions, plugin_manager: PluginManager
|
||||
) -> None:
|
||||
# Convert to Namespace for plugin compatibility during transition
|
||||
if isinstance(options, OCROptions):
|
||||
legacy_options = options.to_namespace()
|
||||
else:
|
||||
legacy_options = options
|
||||
plugin_manager.hook.check_options(options=legacy_options)
|
||||
ocr_engine_languages = plugin_manager.hook.get_ocr_engine().languages(
|
||||
legacy_options
|
||||
)
|
||||
plugin_manager.hook.check_options(options=options)
|
||||
ocr_engine_languages = plugin_manager.hook.get_ocr_engine().languages(options)
|
||||
check_options_languages(options, ocr_engine_languages)
|
||||
|
||||
|
||||
def check_options(
|
||||
options: Union[Namespace, OCROptions], plugin_manager: PluginManager
|
||||
) -> None:
|
||||
def check_options(options: OCROptions, plugin_manager: PluginManager) -> None:
|
||||
_check_plugin_invariant_options(options)
|
||||
_check_plugin_options(options, plugin_manager)
|
||||
|
||||
|
||||
def create_input_file(
|
||||
options: Union[Namespace, OCROptions], work_folder: Path
|
||||
) -> tuple[Path, str]:
|
||||
def create_input_file(options: OCROptions, work_folder: Path) -> tuple[Path, str]:
|
||||
if options.input_file == '-':
|
||||
# stdin
|
||||
log.info('reading file from standard input')
|
||||
@@ -194,7 +182,7 @@ def create_input_file(
|
||||
raise InputFileError(msg) from e
|
||||
|
||||
|
||||
def check_requested_output_file(options: Union[Namespace, OCROptions]) -> None:
|
||||
def check_requested_output_file(options: OCROptions) -> None:
|
||||
if options.output_file == '-':
|
||||
if sys.stdout.isatty():
|
||||
raise BadArgsError(
|
||||
@@ -212,7 +200,7 @@ def check_requested_output_file(options: Union[Namespace, OCROptions]) -> None:
|
||||
|
||||
|
||||
def report_output_file_size(
|
||||
options: Union[Namespace, OCROptions],
|
||||
options: OCROptions,
|
||||
input_file: Path,
|
||||
output_file: Path,
|
||||
optimize_messages: Sequence[str] | None = None,
|
||||
|
||||
@@ -74,8 +74,6 @@ def check_options(options):
|
||||
"use --force-ocr to discard existing text."
|
||||
)
|
||||
|
||||
if options.output_type == 'pdfa':
|
||||
options.output_type = 'pdfa-2'
|
||||
if options.color_conversion_strategy not in ghostscript.COLOR_CONVERSION_STRATEGIES:
|
||||
raise ValueError(
|
||||
f"Invalid color conversion strategy: {options.color_conversion_strategy}"
|
||||
@@ -128,6 +126,11 @@ def generate_pdfa(
|
||||
stop_on_soft_error,
|
||||
):
|
||||
"""Generate a PDF/A from the list of PDF pages and PDF/A metadata."""
|
||||
# Normalize output_type at point of use
|
||||
output_type = context.options.output_type
|
||||
if output_type == 'pdfa':
|
||||
output_type = 'pdfa-2'
|
||||
|
||||
ghostscript.generate_pdfa(
|
||||
pdf_pages=[pdfmark, *pdf_pages],
|
||||
output_file=output_file,
|
||||
|
||||
@@ -152,14 +152,6 @@ def check_options(options):
|
||||
"Please upgrade to a newer or supported older version."
|
||||
)
|
||||
|
||||
# Decide on what renderer to use
|
||||
if options.pdf_renderer == 'auto':
|
||||
if {'ara', 'heb', 'fas', 'per'} & set(options.languages):
|
||||
log.info("Using sandwich renderer since there is an RTL language")
|
||||
options.pdf_renderer = 'sandwich'
|
||||
else:
|
||||
options.pdf_renderer = 'hocr'
|
||||
|
||||
if not tesseract.has_thresholding() and options.tesseract_thresholding != 0:
|
||||
log.warning(
|
||||
"The installed version of Tesseract does not support changes to its "
|
||||
@@ -234,9 +226,21 @@ class TesseractOcrEngine(OcrEngine):
|
||||
def version():
|
||||
return str(tesseract.version())
|
||||
|
||||
@staticmethod
|
||||
def _determine_renderer(options):
|
||||
"""Determine the PDF renderer to use based on options and languages."""
|
||||
if options.pdf_renderer == 'auto':
|
||||
if {'ara', 'heb', 'fas', 'per'} & set(options.languages):
|
||||
log.info("Using sandwich renderer since there is an RTL language")
|
||||
return 'sandwich'
|
||||
else:
|
||||
return 'hocr'
|
||||
return options.pdf_renderer
|
||||
|
||||
@staticmethod
|
||||
def creator_tag(options):
|
||||
tag = '-PDF' if options.pdf_renderer == 'sandwich' else '-hOCR'
|
||||
renderer = TesseractOcrEngine._determine_renderer(options)
|
||||
tag = '-PDF' if renderer == 'sandwich' else '-hOCR'
|
||||
return f"Tesseract OCR{tag} {TesseractOcrEngine.version()}"
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from argparse import ArgumentParser, Namespace
|
||||
from argparse import ArgumentParser
|
||||
from collections.abc import Sequence, Set
|
||||
from logging import Handler
|
||||
from pathlib import Path
|
||||
@@ -15,6 +15,7 @@ from typing import TYPE_CHECKING, NamedTuple
|
||||
import pluggy
|
||||
|
||||
from ocrmypdf import Executor, PdfContext
|
||||
from ocrmypdf._options import OCROptions
|
||||
from ocrmypdf._progressbar import ProgressBar
|
||||
from ocrmypdf.helpers import Resolution
|
||||
|
||||
@@ -87,7 +88,7 @@ def add_options(parser: ArgumentParser) -> None:
|
||||
|
||||
|
||||
@hookspec
|
||||
def check_options(options: Namespace) -> None:
|
||||
def check_options(options: OCROptions) -> None:
|
||||
"""Called to ask the plugin to check all of the options.
|
||||
|
||||
The plugin may check if options that it added are valid.
|
||||
@@ -158,7 +159,7 @@ def get_progressbar_class() -> type[ProgressBar]:
|
||||
|
||||
|
||||
@hookspec
|
||||
def validate(pdfinfo: PdfInfo, options: Namespace) -> None:
|
||||
def validate(pdfinfo: PdfInfo, options: OCROptions) -> None:
|
||||
"""Called to give a plugin an opportunity to review *options* and *pdfinfo*.
|
||||
|
||||
*options* contains the "work order" to process a particular file. *pdfinfo*
|
||||
@@ -368,7 +369,7 @@ class OcrEngine(ABC):
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def creator_tag(options: Namespace) -> str:
|
||||
def creator_tag(options: OCROptions) -> str:
|
||||
"""Returns the creator tag to identify this software's role in creating the PDF.
|
||||
|
||||
This tag will be inserted in the XMP metadata and DocumentInfo dictionary
|
||||
@@ -389,7 +390,7 @@ class OcrEngine(ABC):
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def languages(options: Namespace) -> Set[str]:
|
||||
def languages(options: OCROptions) -> Set[str]:
|
||||
"""Returns the set of all languages that are supported by the engine.
|
||||
|
||||
Languages are typically given in 3-letter ISO 3166-1 codes, but actually
|
||||
@@ -398,18 +399,18 @@ class OcrEngine(ABC):
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def get_orientation(input_file: Path, options: Namespace) -> OrientationConfidence:
|
||||
def get_orientation(input_file: Path, options: OCROptions) -> OrientationConfidence:
|
||||
"""Returns the orientation of the image."""
|
||||
|
||||
@staticmethod
|
||||
def get_deskew(input_file: Path, options: Namespace) -> float:
|
||||
def get_deskew(input_file: Path, options: OCROptions) -> float:
|
||||
"""Returns the deskew angle of the image, in degrees."""
|
||||
return 0.0
|
||||
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def generate_hocr(
|
||||
input_file: Path, output_hocr: Path, output_text: Path, options: Namespace
|
||||
input_file: Path, output_hocr: Path, output_text: Path, options: OCROptions
|
||||
) -> None:
|
||||
"""Called to produce a hOCR file from a page image and sidecar text file.
|
||||
|
||||
@@ -432,7 +433,7 @@ class OcrEngine(ABC):
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def generate_pdf(
|
||||
input_file: Path, output_pdf: Path, output_text: Path, options: Namespace
|
||||
input_file: Path, output_pdf: Path, output_text: Path, options: OCROptions
|
||||
) -> None:
|
||||
"""Called to produce a text only PDF from a page image.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user