fix: refine validation coordinator error handling
Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
@@ -161,8 +161,6 @@ class OCROptions(BaseModel):
|
||||
tesseract_non_ocr_timeout: float | None = None
|
||||
tesseract_downsample_above: int = 32767
|
||||
tesseract_downsample_large_images: bool | None = None
|
||||
user_words: str | None = None
|
||||
user_patterns: str | None = None
|
||||
|
||||
# Legacy ghostscript options (for backward compatibility)
|
||||
pdfa_image_compression: str | None = None
|
||||
|
||||
@@ -42,54 +42,47 @@ class ValidationCoordinator:
|
||||
|
||||
def _validate_plugin_contexts(self, options: OCROptions) -> None:
|
||||
"""Validate plugin options that require external context."""
|
||||
if not self.registry:
|
||||
return
|
||||
|
||||
registered_models = self.registry.get_registered_models()
|
||||
# For now, we'll run the plugin validation directly since the models
|
||||
# are still being integrated. This ensures the validation warnings
|
||||
# and checks still work as expected.
|
||||
|
||||
# Validate Tesseract options with language context
|
||||
if 'tesseract' in registered_models:
|
||||
from ocrmypdf.builtin_plugins.tesseract_ocr import TesseractOptions
|
||||
|
||||
# Create TesseractOptions from legacy fields for validation
|
||||
tesseract_data = {
|
||||
'config': options.tesseract_config,
|
||||
'pagesegmode': options.tesseract_pagesegmode,
|
||||
'oem': options.tesseract_oem,
|
||||
'thresholding': options.tesseract_thresholding,
|
||||
'timeout': options.tesseract_timeout,
|
||||
'non_ocr_timeout': options.tesseract_non_ocr_timeout or 180.0,
|
||||
'downsample_large_images': options.tesseract_downsample_large_images,
|
||||
'downsample_above': options.tesseract_downsample_above,
|
||||
'user_words': options.user_words,
|
||||
'user_patterns': options.user_patterns,
|
||||
}
|
||||
# Remove None values
|
||||
tesseract_data = {k: v for k, v in tesseract_data.items() if v is not None}
|
||||
|
||||
tesseract_options = TesseractOptions(**tesseract_data)
|
||||
tesseract_options.validate_with_context(options.languages)
|
||||
# Run Tesseract validation
|
||||
self._validate_tesseract_options(options)
|
||||
|
||||
# Validate Optimize options with external program context
|
||||
if 'optimize' in registered_models:
|
||||
from ocrmypdf.builtin_plugins.optimize import OptimizeOptions
|
||||
from ocrmypdf._exec import jbig2enc, pngquant
|
||||
|
||||
optimize_data = {
|
||||
'level': options.optimize,
|
||||
'jpeg_quality': options.jpeg_quality or 0,
|
||||
'png_quality': options.png_quality or 0,
|
||||
'jbig2_lossy': options.jbig2_lossy or False,
|
||||
'jbig2_page_group_size': options.jbig2_page_group_size or 0,
|
||||
'jbig2_threshold': options.jbig2_threshold,
|
||||
}
|
||||
|
||||
optimize_options = OptimizeOptions(**optimize_data)
|
||||
external_programs = {
|
||||
'pngquant': pngquant.available(),
|
||||
'jbig2enc': jbig2enc.available(),
|
||||
}
|
||||
optimize_options.validate_with_context(external_programs)
|
||||
# Run Optimize validation
|
||||
self._validate_optimize_options(options)
|
||||
|
||||
def _validate_tesseract_options(self, options: OCROptions) -> None:
|
||||
"""Validate Tesseract options."""
|
||||
# Check pagesegmode warning
|
||||
if options.tesseract_pagesegmode in (0, 2):
|
||||
log.warning(
|
||||
"The tesseract-pagesegmode you selected will disable OCR. "
|
||||
"This may cause processing to fail."
|
||||
)
|
||||
|
||||
# Check downsample consistency
|
||||
if (
|
||||
options.tesseract_downsample_above != 32767
|
||||
and not options.tesseract_downsample_large_images
|
||||
):
|
||||
log.warning(
|
||||
"The --tesseract-downsample-above argument will have no effect unless "
|
||||
"--tesseract-downsample-large-images is also given."
|
||||
)
|
||||
|
||||
def _validate_optimize_options(self, options: OCROptions) -> None:
|
||||
"""Validate optimization options."""
|
||||
# Check optimization consistency
|
||||
if options.optimize == 0 and any([
|
||||
options.jbig2_lossy,
|
||||
options.png_quality and options.png_quality > 0,
|
||||
options.jpeg_quality and options.jpeg_quality > 0
|
||||
]):
|
||||
log.warning(
|
||||
"The arguments --jbig2-lossy, --png-quality, and --jpeg-quality "
|
||||
"will be ignored because --optimize=0."
|
||||
)
|
||||
|
||||
def _validate_cross_cutting_concerns(self, options: OCROptions) -> None:
|
||||
"""Validate cross-cutting concerns that span multiple plugins."""
|
||||
@@ -98,14 +91,12 @@ class ValidationCoordinator:
|
||||
1 for opt in [options.force_ocr, options.skip_text, options.redo_ocr] if opt
|
||||
)
|
||||
if exclusive_options >= 2:
|
||||
from ocrmypdf.exceptions import BadArgsError
|
||||
raise BadArgsError("Choose only one of --force-ocr, --skip-text, --redo-ocr.")
|
||||
raise ValueError("Choose only one of --force-ocr, --skip-text, --redo-ocr.")
|
||||
|
||||
# Validate redo_ocr compatibility
|
||||
if options.redo_ocr:
|
||||
if options.deskew or options.clean_final or options.remove_background:
|
||||
from ocrmypdf.exceptions import BadArgsError
|
||||
raise BadArgsError(
|
||||
raise ValueError(
|
||||
"--redo-ocr is not currently compatible with --deskew, "
|
||||
"--clean-final, and --remove-background"
|
||||
)
|
||||
@@ -114,8 +105,7 @@ class ValidationCoordinator:
|
||||
if options.output_type == 'none' and str(options.output_file) not in (
|
||||
os.devnull, '-'
|
||||
):
|
||||
from ocrmypdf.exceptions import BadArgsError
|
||||
raise BadArgsError(
|
||||
raise ValueError(
|
||||
"Since you specified `--output-type none`, the output file "
|
||||
f"{options.output_file} cannot be produced. Set the output file to "
|
||||
"`-` to suppress this message."
|
||||
|
||||
Reference in New Issue
Block a user