refactor: post-AI code cleanup
This commit is contained in:
@@ -18,7 +18,6 @@ def main(
|
||||
engine: Annotated[str, typer.Option()] = 'pdftotext',
|
||||
):
|
||||
"""Compare text in PDFs."""
|
||||
|
||||
text1 = run(
|
||||
['pdftotext', '-layout', '-', '-'], stdin=pdf1, capture_output=True, check=True
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ import logging
|
||||
import os
|
||||
import re
|
||||
from collections import deque
|
||||
from io import BytesIO
|
||||
from os import fspath
|
||||
from pathlib import Path
|
||||
from subprocess import PIPE, CalledProcessError
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from collections.abc import Iterator
|
||||
from copy import copy
|
||||
from argparse import Namespace
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
from pluggy import PluginManager
|
||||
|
||||
@@ -29,7 +26,7 @@ class PdfContext:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
options: Union[OCROptions, Namespace],
|
||||
options: OCROptions | Namespace,
|
||||
work_folder: Path,
|
||||
origin: Path,
|
||||
pdfinfo: PdfInfo,
|
||||
@@ -114,7 +111,6 @@ class PageContext:
|
||||
# Fallback: if JSON serialization fails, convert to namespace
|
||||
# This shouldn't happen but provides safety
|
||||
from argparse import Namespace
|
||||
import os
|
||||
|
||||
clean_options = Namespace()
|
||||
for key, value in vars(self.options.to_namespace()).items():
|
||||
@@ -122,6 +118,7 @@ class PageContext:
|
||||
continue
|
||||
try:
|
||||
import pickle
|
||||
|
||||
pickle.dumps(value)
|
||||
setattr(clean_options, key, value)
|
||||
except TypeError:
|
||||
@@ -138,6 +135,7 @@ class PageContext:
|
||||
# Reconstruct OCROptions from JSON if available
|
||||
if 'options_json' in state:
|
||||
from ocrmypdf._options import OCROptions
|
||||
|
||||
self.options = OCROptions.model_validate_json_safe(state['options_json'])
|
||||
# Otherwise, we have a fallback Namespace (shouldn't happen in normal operation)
|
||||
# Leave it as-is for compatibility
|
||||
|
||||
@@ -15,7 +15,6 @@ from pikepdf import Dictionary, Name, Pdf
|
||||
from pikepdf import __version__ as PIKEPDF_VERSION
|
||||
from pikepdf.models.metadata import PdfMetadata, encode_pdf_date
|
||||
|
||||
from ocrmypdf._annots import remove_broken_goto_annotations
|
||||
from ocrmypdf._defaults import PROGRAM_NAME
|
||||
from ocrmypdf._jobcontext import PdfContext
|
||||
from ocrmypdf._version import __version__ as OCRMYPF_VERSION
|
||||
|
||||
+20
-14
@@ -10,11 +10,10 @@ import logging
|
||||
import os
|
||||
import unicodedata
|
||||
from argparse import Namespace
|
||||
from collections.abc import Iterable, Sequence
|
||||
from copy import copy
|
||||
from collections.abc import Sequence
|
||||
from io import IOBase
|
||||
from pathlib import Path
|
||||
from typing import Any, BinaryIO, Union
|
||||
from typing import Any, BinaryIO
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
@@ -24,7 +23,7 @@ from ocrmypdf.helpers import monotonic
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
PathOrIO = Union[BinaryIO, IOBase, Path, str, bytes]
|
||||
PathOrIO = BinaryIO | IOBase | Path | str | bytes
|
||||
|
||||
|
||||
def _pages_from_ranges(ranges: str) -> set[int]:
|
||||
@@ -159,7 +158,6 @@ class OCROptions(BaseModel):
|
||||
# Plugin system
|
||||
plugins: Sequence[Path | str] | None = None
|
||||
|
||||
|
||||
# Store any extra attributes (for plugins and dynamic options)
|
||||
extra_attrs: dict[str, Any] = Field(
|
||||
default_factory=dict, exclude=True, alias='_extra_attrs'
|
||||
@@ -259,7 +257,6 @@ class OCROptions(BaseModel):
|
||||
raise ValueError(f"pdf_renderer must be one of {valid_renderers}")
|
||||
return v
|
||||
|
||||
|
||||
@field_validator('clean_final')
|
||||
@classmethod
|
||||
def validate_clean_final(cls, v, info):
|
||||
@@ -359,7 +356,10 @@ class OCROptions(BaseModel):
|
||||
@model_validator(mode='after')
|
||||
def validate_output_type_compatibility(self):
|
||||
"""Validate output type is compatible with output file."""
|
||||
if self.output_type == 'none' and str(self.output_file) not in (os.devnull, '-'):
|
||||
if self.output_type == 'none' and str(self.output_file) not in (
|
||||
os.devnull,
|
||||
'-',
|
||||
):
|
||||
raise ValueError(
|
||||
"Since you specified `--output-type none`, the output file "
|
||||
f"{self.output_file} cannot be produced. Set the output file to "
|
||||
@@ -370,12 +370,14 @@ class OCROptions(BaseModel):
|
||||
@model_validator(mode='after')
|
||||
def set_lossless_reconstruction(self):
|
||||
"""Set lossless_reconstruction based on other options."""
|
||||
lossless = not any([
|
||||
self.deskew,
|
||||
self.clean_final,
|
||||
self.force_ocr,
|
||||
self.remove_background,
|
||||
])
|
||||
lossless = not any(
|
||||
[
|
||||
self.deskew,
|
||||
self.clean_final,
|
||||
self.force_ocr,
|
||||
self.remove_background,
|
||||
]
|
||||
)
|
||||
|
||||
if not lossless and self.redo_ocr:
|
||||
raise ValueError(
|
||||
@@ -396,7 +398,11 @@ class OCROptions(BaseModel):
|
||||
def _serialize_value(value):
|
||||
if isinstance(value, Path):
|
||||
return {'__type__': 'Path', 'value': str(value)}
|
||||
elif isinstance(value, (BinaryIO, IOBase)) or hasattr(value, 'read') or hasattr(value, 'write'):
|
||||
elif (
|
||||
isinstance(value, (BinaryIO, IOBase))
|
||||
or hasattr(value, 'read')
|
||||
or hasattr(value, 'write')
|
||||
):
|
||||
# Stream object - replace with placeholder
|
||||
return {'__type__': 'Stream', 'value': 'stream'}
|
||||
elif hasattr(value, '__class__') and 'Iterator' in value.__class__.__name__:
|
||||
|
||||
@@ -915,7 +915,9 @@ def convert_to_pdfa(input_pdf: Path, input_ps_stub: Path, context: PdfContext) -
|
||||
if options.output_type == 'pdfa':
|
||||
pdfa_part = '2' # Default to PDF/A-2
|
||||
else:
|
||||
pdfa_part = options.output_type.split('-')[-1] # Extract number from pdfa-1, pdfa-2, etc.
|
||||
pdfa_part = options.output_type.split('-')[
|
||||
-1
|
||||
] # Extract number from pdfa-1, pdfa-2, etc.
|
||||
else:
|
||||
pdfa_part = '2' # Fallback
|
||||
|
||||
|
||||
@@ -50,9 +50,8 @@ from ocrmypdf._plugin_manager import OcrmypdfPluginManager
|
||||
from ocrmypdf._validation import (
|
||||
report_output_file_size,
|
||||
)
|
||||
from ocrmypdf.exceptions import BadArgsError, ExitCode, ExitCodeException
|
||||
from ocrmypdf.exceptions import ExitCode, ExitCodeException
|
||||
from ocrmypdf.helpers import (
|
||||
available_cpu_count,
|
||||
check_pdf,
|
||||
pikepdf_enable_mmap,
|
||||
running_in_docker,
|
||||
@@ -328,13 +327,12 @@ def setup_pipeline(
|
||||
return executor
|
||||
|
||||
|
||||
def do_get_pdfinfo(
|
||||
pdf_path: Path, executor: Executor, options
|
||||
) -> PdfInfo:
|
||||
def do_get_pdfinfo(pdf_path: Path, executor: Executor, options) -> PdfInfo:
|
||||
# Handle pages field - it might be a string that needs conversion
|
||||
check_pages = options.pages
|
||||
if isinstance(check_pages, str):
|
||||
from ocrmypdf._options import _pages_from_ranges
|
||||
|
||||
check_pages = _pages_from_ranges(check_pages)
|
||||
|
||||
return get_pdfinfo(
|
||||
|
||||
@@ -6,19 +6,17 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
from shutil import copyfileobj
|
||||
from typing import Union
|
||||
|
||||
import pikepdf
|
||||
from pluggy import PluginManager
|
||||
|
||||
from ocrmypdf._defaults import DEFAULT_LANGUAGE, DEFAULT_ROTATE_PAGES_THRESHOLD
|
||||
from ocrmypdf._defaults import DEFAULT_ROTATE_PAGES_THRESHOLD
|
||||
from ocrmypdf._exec import unpaper
|
||||
from ocrmypdf._options import OCROptions
|
||||
from ocrmypdf.exceptions import (
|
||||
@@ -74,7 +72,6 @@ def check_options_languages(
|
||||
raise MissingDependencyError(msg)
|
||||
|
||||
|
||||
|
||||
def check_options_sidecar(options: OCROptions) -> None:
|
||||
if options.sidecar == '\0':
|
||||
if options.output_file == '-':
|
||||
@@ -117,16 +114,13 @@ def check_options_preprocessing(options: OCROptions) -> None:
|
||||
raise BadArgsError("--unpaper-args: " + str(e)) from e
|
||||
|
||||
|
||||
|
||||
def _check_plugin_invariant_options(options: OCROptions) -> None:
|
||||
check_platform()
|
||||
check_options_sidecar(options)
|
||||
check_options_preprocessing(options)
|
||||
|
||||
|
||||
def _check_plugin_options(
|
||||
options: OCROptions, plugin_manager: PluginManager
|
||||
) -> None:
|
||||
def _check_plugin_options(options: OCROptions, plugin_manager: PluginManager) -> None:
|
||||
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)
|
||||
|
||||
+19
-8
@@ -43,7 +43,6 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
from argparse import Namespace
|
||||
from collections.abc import Iterable, Sequence
|
||||
from enum import IntEnum
|
||||
from io import IOBase
|
||||
@@ -172,8 +171,6 @@ def configure_logging(
|
||||
return log
|
||||
|
||||
|
||||
|
||||
|
||||
def create_options(
|
||||
*, input_file: PathOrIO, output_file: PathOrIO, parser: ArgumentParser, **kwargs
|
||||
) -> OCROptions:
|
||||
@@ -199,7 +196,9 @@ def create_options(
|
||||
options_kwargs['output_file'] = output_file
|
||||
|
||||
# Handle special stream cases for sidecar
|
||||
if 'sidecar' in options_kwargs and isinstance(options_kwargs['sidecar'], BinaryIO | IOBase):
|
||||
if 'sidecar' in options_kwargs and isinstance(
|
||||
options_kwargs['sidecar'], BinaryIO | IOBase
|
||||
):
|
||||
# Keep the stream object as-is - OCROptions can handle it
|
||||
pass
|
||||
|
||||
@@ -454,7 +453,11 @@ def _pdf_to_hocr( # noqa: D417
|
||||
|
||||
# Add all the function parameters
|
||||
for param_name, param_value in locals().items():
|
||||
if param_name not in {'input_pdf', 'output_folder', 'kwargs', 'plugin_manager', 'plugins'} and param_value is not None:
|
||||
if (
|
||||
param_name
|
||||
not in {'input_pdf', 'output_folder', 'kwargs', 'plugin_manager', 'plugins'}
|
||||
and param_value is not None
|
||||
):
|
||||
options_kwargs[param_name] = param_value
|
||||
|
||||
# Handle plugins separately
|
||||
@@ -484,7 +487,9 @@ def _pdf_to_hocr( # noqa: D417
|
||||
if extra_attrs:
|
||||
options.extra_attrs.update(extra_attrs)
|
||||
except Exception as e:
|
||||
raise TypeError(f"Failed to create OCROptions for hOCR pipeline: {e}") from e
|
||||
raise TypeError(
|
||||
f"Failed to create OCROptions for hOCR pipeline: {e}"
|
||||
) from e
|
||||
|
||||
return run_hocr_pipeline(options=options, plugin_manager=plugin_manager)
|
||||
|
||||
@@ -533,7 +538,11 @@ def _hocr_to_ocr_pdf( # noqa: D417
|
||||
|
||||
# Add all the function parameters
|
||||
for param_name, param_value in locals().items():
|
||||
if param_name not in {'work_folder', 'output_file', 'kwargs', 'plugin_manager', 'plugins'} and param_value is not None:
|
||||
if (
|
||||
param_name
|
||||
not in {'work_folder', 'output_file', 'kwargs', 'plugin_manager', 'plugins'}
|
||||
and param_value is not None
|
||||
):
|
||||
options_kwargs[param_name] = param_value
|
||||
|
||||
# Handle plugins separately
|
||||
@@ -563,7 +572,9 @@ def _hocr_to_ocr_pdf( # noqa: D417
|
||||
if extra_attrs:
|
||||
options.extra_attrs.update(extra_attrs)
|
||||
except Exception as e:
|
||||
raise TypeError(f"Failed to create OCROptions for hOCR to PDF pipeline: {e}") from e
|
||||
raise TypeError(
|
||||
f"Failed to create OCROptions for hOCR to PDF pipeline: {e}"
|
||||
) from e
|
||||
|
||||
return run_hocr_to_ocr_pdf_pipeline(
|
||||
options=options, plugin_manager=plugin_manager
|
||||
|
||||
@@ -44,7 +44,6 @@ from ocrmypdf.helpers import Resolution, available_cpu_count, pikepdf_enable_mma
|
||||
from ocrmypdf.pdfinfo.layout import (
|
||||
LTStateAwareChar,
|
||||
PdfMinerState,
|
||||
get_page_analysis,
|
||||
get_text_boxes,
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pikepdf import Array, Dictionary, Name, NameTree, Pdf
|
||||
|
||||
from ocrmypdf._annots import remove_broken_goto_annotations
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
"""Test JSON serialization of OCROptions for multiprocessing compatibility."""
|
||||
|
||||
import multiprocessing
|
||||
from pathlib import Path
|
||||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
from ocrmypdf._options import OCROptions
|
||||
|
||||
|
||||
@@ -10,10 +10,8 @@ from shutil import copyfile
|
||||
|
||||
import pikepdf
|
||||
import pytest
|
||||
from packaging.version import Version
|
||||
from pikepdf.models.metadata import decode_pdf_date
|
||||
|
||||
from ocrmypdf._exec import ghostscript
|
||||
from ocrmypdf._jobcontext import PdfContext
|
||||
from ocrmypdf._metadata import metadata_fixup
|
||||
from ocrmypdf._pipeline import convert_to_pdfa
|
||||
|
||||
@@ -13,7 +13,7 @@ import pytest
|
||||
|
||||
from ocrmypdf import pdfinfo
|
||||
from ocrmypdf._exec import tesseract
|
||||
from ocrmypdf.exceptions import BadArgsError, ExitCode, MissingDependencyError
|
||||
from ocrmypdf.exceptions import BadArgsError, MissingDependencyError
|
||||
|
||||
from .conftest import check_ocrmypdf, run_ocrmypdf_api
|
||||
|
||||
|
||||
Reference in New Issue
Block a user