From 134f4fcc2848261430c7f0362f06bf3c25c1e7a8 Mon Sep 17 00:00:00 2001 From: "James R. Barlow" Date: Tue, 9 Dec 2025 23:49:24 -0800 Subject: [PATCH] fix: remove Union type hints and add default values in OCROptions Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) --- src/ocrmypdf/_options.py | 54 ++++++++++++++++++++++++++++++------- src/ocrmypdf/_validation.py | 8 +++--- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/ocrmypdf/_options.py b/src/ocrmypdf/_options.py index be6f169b..cfe9daeb 100644 --- a/src/ocrmypdf/_options.py +++ b/src/ocrmypdf/_options.py @@ -119,7 +119,7 @@ class OCROptions(BaseModel): keywords: str | None = None # Optimization - optimize: int | None = None + optimize: int = 0 jpg_quality: int | None = None png_quality: int | None = None jbig2_lossy: bool | None = None @@ -133,13 +133,13 @@ class OCROptions(BaseModel): tesseract_pagesegmode: int | None = None tesseract_oem: int | None = None tesseract_thresholding: int | None = None - tesseract_timeout: float | None = None - tesseract_non_ocr_timeout: float | None = None - tesseract_downsample_above: int | None = None - tesseract_downsample_large_images: bool | None = None + tesseract_timeout: float = 180.0 + tesseract_non_ocr_timeout: float = 60.0 + tesseract_downsample_above: int = 150 + tesseract_downsample_large_images: bool = False rotate_pages_threshold: float = DEFAULT_ROTATE_PAGES_THRESHOLD - pdfa_image_compression: str | None = None - color_conversion_strategy: str | None = None + pdfa_image_compression: str = 'auto' + color_conversion_strategy: str = 'auto' user_words: os.PathLike | None = None user_patterns: os.PathLike | None = None fast_web_view: float | None = None @@ -248,6 +248,28 @@ class OCROptions(BaseModel): raise ValueError(f"pdf_renderer must be one of {valid_renderers}") return v + @field_validator('color_conversion_strategy') + @classmethod + def validate_color_conversion_strategy(cls, v): + """Validate color conversion strategy.""" + if v is None: + return 'auto' + valid_strategies = {'auto', 'RGB', 'CMYK', 'Gray'} + if v not in valid_strategies: + raise ValueError(f"color_conversion_strategy must be one of {valid_strategies}") + return v + + @field_validator('pdfa_image_compression') + @classmethod + def validate_pdfa_image_compression(cls, v): + """Validate PDF/A image compression.""" + if v is None: + return 'auto' + valid_compressions = {'auto', 'jpeg', 'lossless'} + if v not in valid_compressions: + raise ValueError(f"pdfa_image_compression must be one of {valid_compressions}") + return v + @field_validator('clean_final') @classmethod def validate_clean_final(cls, v, info): @@ -332,9 +354,21 @@ class OCROptions(BaseModel): # For hOCR API, output_file might not be present if 'output_folder' in data and 'output_file' not in data: data['output_file'] = '/dev/null' # Placeholder - # Handle pdf_renderer 'auto' case - if data.get('pdf_renderer') == 'auto': - data['pdf_renderer'] = 'hocr' # Default to hocr for auto + # Set default values for fields that might be None + if data.get('tesseract_timeout') is None: + data['tesseract_timeout'] = 180.0 + if data.get('tesseract_non_ocr_timeout') is None: + data['tesseract_non_ocr_timeout'] = 60.0 + if data.get('tesseract_downsample_above') is None: + data['tesseract_downsample_above'] = 150 + if data.get('tesseract_downsample_large_images') is None: + data['tesseract_downsample_large_images'] = False + if data.get('optimize') is None: + data['optimize'] = 0 + if data.get('color_conversion_strategy') is None: + data['color_conversion_strategy'] = 'auto' + if data.get('pdfa_image_compression') is None: + data['pdfa_image_compression'] = 'auto' return data @model_validator(mode='after') diff --git a/src/ocrmypdf/_validation.py b/src/ocrmypdf/_validation.py index 01e8e1ed..55ec3194 100644 --- a/src/ocrmypdf/_validation.py +++ b/src/ocrmypdf/_validation.py @@ -49,7 +49,7 @@ def check_platform() -> None: def check_options_languages( - options: Union[OCROptions], ocr_engine_languages: list[str] + options: OCROptions, ocr_engine_languages: list[str] ) -> None: if not ocr_engine_languages: return @@ -75,7 +75,7 @@ def check_options_languages( -def check_options_sidecar(options: Union[OCROptions]) -> None: +def check_options_sidecar(options: OCROptions) -> None: if options.sidecar == '\0': if options.output_file == '-': raise BadArgsError("--sidecar filename needed when output file is stdout.") @@ -90,7 +90,7 @@ def check_options_sidecar(options: Union[OCROptions]) -> None: ) -def check_options_preprocessing(options: Union[OCROptions]) -> None: +def check_options_preprocessing(options: OCROptions) -> None: if options.clean_final: options.clean = True if options.unpaper_args and not options.clean: @@ -118,7 +118,7 @@ def check_options_preprocessing(options: Union[OCROptions]) -> None: -def _check_plugin_invariant_options(options: Union[OCROptions]) -> None: +def _check_plugin_invariant_options(options: OCROptions) -> None: check_platform() check_options_sidecar(options) check_options_preprocessing(options)