From 2bd586e093a191fb6e9e939b56eb801de5069035 Mon Sep 17 00:00:00 2001 From: "James R. Barlow" Date: Sat, 16 May 2020 01:50:37 -0700 Subject: [PATCH] Compare requested languages to OCR engine instead of tesseract directly Also refactoring to facilitating validation needing the plugin manager. --- src/ocrmypdf/__main__.py | 2 +- src/ocrmypdf/_validation.py | 16 +++++++++------- src/ocrmypdf/api.py | 2 +- src/ocrmypdf/builtin_plugins/tesseract_ocr.py | 7 +++++-- src/ocrmypdf/pluginspec.py | 8 ++++++-- tests/conftest.py | 9 ++++++--- tests/test_unpaper.py | 6 ++++-- tests/test_validation.py | 9 ++++++--- 8 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/ocrmypdf/__main__.py b/src/ocrmypdf/__main__.py index 01f0a478..1cf84daf 100755 --- a/src/ocrmypdf/__main__.py +++ b/src/ocrmypdf/__main__.py @@ -58,7 +58,7 @@ def run(args=None): ) log.debug('ocrmypdf %s', __version__) try: - check_options(options) + check_options(options, plugin_manager) except ValueError as e: log.error(e) return ExitCode.bad_args diff --git a/src/ocrmypdf/_validation.py b/src/ocrmypdf/_validation.py index 4ef6fcdf..bfd52e69 100644 --- a/src/ocrmypdf/_validation.py +++ b/src/ocrmypdf/_validation.py @@ -27,6 +27,7 @@ from shutil import copyfileobj import PIL +from ocrmypdf._plugin_manager import get_plugin_manager from ocrmypdf._unicodefun import verify_python3_env from ocrmypdf.exceptions import ( BadArgsError, @@ -72,7 +73,7 @@ def check_platform(): ) -def check_options_languages(options): +def check_options_languages(options, plugin_manager): if not options.language: options.language = [DEFAULT_LANGUAGE] system_lang = locale.getlocale()[0] @@ -84,12 +85,13 @@ def check_options_languages(options): options.language = options.language[0].split('+') languages = set(options.language) - if not languages.issubset(tesseract.get_languages(options.tesseract_env)): + ocr_engine = plugin_manager.hook.get_ocr_engine() + if not languages.issubset(ocr_engine.languages(options)): msg = ( - "The installed version of tesseract does not have language " - "data for the following requested languages: \n" + f"{ocr_engine} does not have language data for the following " + "requested languages: \n" ) - for lang in languages - tesseract.get_languages(options.tesseract_env): + for lang in languages - ocr_engine.languages(options): msg += lang + '\n' raise MissingDependencyError(msg) @@ -308,9 +310,9 @@ def check_options_pillow(options): PIL.Image.MAX_IMAGE_PIXELS = None -def check_options(options): +def check_options(options, plugin_manager): check_platform() - check_options_languages(options) + check_options_languages(options, plugin_manager) check_options_metadata(options) check_options_output(options) check_options_sidecar(options) diff --git a/src/ocrmypdf/api.py b/src/ocrmypdf/api.py index f53107fa..7edce482 100644 --- a/src/ocrmypdf/api.py +++ b/src/ocrmypdf/api.py @@ -279,5 +279,5 @@ def ocr( # pylint: disable=unused-argument options = create_options( **{k: v for k, v in locals().items() if not k.startswith('_')} ) - check_options(options) + check_options(options, _plugin_manager) return run_pipeline(options=options, plugin_manager=_plugin_manager, api=True) diff --git a/src/ocrmypdf/builtin_plugins/tesseract_ocr.py b/src/ocrmypdf/builtin_plugins/tesseract_ocr.py index d68a2946..85b2e4c8 100644 --- a/src/ocrmypdf/builtin_plugins/tesseract_ocr.py +++ b/src/ocrmypdf/builtin_plugins/tesseract_ocr.py @@ -30,9 +30,12 @@ class TesseractOcrEngine(OcrEngine): tag = '-PDF' if options.pdf_renderer == 'sandwich' else '' return f"Tesseract OCR{tag} {TesseractOcrEngine.version()}" + def __str__(self): + return f"Tesseract OCR {TesseractOcrEngine.version()}" + @staticmethod - def languages(): - return tesseract.get_languages() + def languages(options): + return tesseract.get_languages(options.tesseract_env) @staticmethod def get_orientation(input_file, options): diff --git a/src/ocrmypdf/pluginspec.py b/src/ocrmypdf/pluginspec.py index 366c51d3..5e0a4f88 100644 --- a/src/ocrmypdf/pluginspec.py +++ b/src/ocrmypdf/pluginspec.py @@ -100,11 +100,15 @@ class OcrEngine(ABC): """Returns the version of the OCR engine.""" @abstractstaticmethod - def creator_tag(options) -> str: + def creator_tag(options: Namespace) -> str: """Returns the creator tag to identify this software's role in creating the PDF.""" @abstractstaticmethod - def languages() -> AbstractSet[str]: + def __str__(self): + """Returns name of OCR engine and version.""" + + @abstractstaticmethod + def languages(options: Namespace) -> AbstractSet[str]: """Returns set of languages that are supported.""" @abstractstaticmethod diff --git a/tests/conftest.py b/tests/conftest.py index 8eaede2a..55bd8376 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -25,6 +25,7 @@ from subprocess import PIPE, run import pytest from ocrmypdf import api, cli, pdfinfo +from ocrmypdf._plugin_manager import get_plugin_manager from ocrmypdf.exec import unpaper pytest_plugins = ['helpers_namespace'] @@ -217,11 +218,12 @@ def check_ocrmypdf(input_file, output_file, *args, env=None): [str(input_file), str(output_file)] + [str(arg) for arg in args if arg is not None] ) - api.check_options(options) + plugin_manager = get_plugin_manager(options.plugins) + api.check_options(options, plugin_manager) if env: options.tesseract_env = env options.tesseract_env['_OCRMYPDF_TEST_INFILE'] = os.fspath(input_file) - result = api.run_pipeline(options, plugin_manager=None, api=True) + result = api.run_pipeline(options, plugin_manager=plugin_manager, api=True) assert result == 0 assert output_file.exists(), "Output file not created" @@ -251,7 +253,8 @@ def run_ocrmypdf_api(input_file, output_file, *args, env=None): if options.tesseract_env: assert all(isinstance(v, (str, bytes)) for v in options.tesseract_env.values()) - api.check_options(options) + plugin_manager = get_plugin_manager(options.plugins) + api.check_options(options, plugin_manager) return api.run_pipeline(options, plugin_manager=None, api=False) diff --git a/tests/test_unpaper.py b/tests/test_unpaper.py index 836ef0a8..e87800c9 100644 --- a/tests/test_unpaper.py +++ b/tests/test_unpaper.py @@ -20,6 +20,7 @@ from unittest.mock import patch import pytest +from ocrmypdf._plugin_manager import get_plugin_manager from ocrmypdf._validation import check_options from ocrmypdf.cli import get_parser from ocrmypdf.exceptions import ExitCode, MissingDependencyError @@ -43,11 +44,12 @@ def test_no_unpaper(resources, no_outpdf): input_ = fspath(resources / "c02-22.pdf") output = fspath(no_outpdf) options = get_parser().parse_args(args=["--clean", input_, output]) - + plugin_manager = get_plugin_manager(options.plugins) with patch("ocrmypdf.exec.unpaper.version") as mock_unpaper_version: mock_unpaper_version.side_effect = FileNotFoundError("unpaper") + with pytest.raises(MissingDependencyError): - check_options(options) + check_options(options, plugin_manager) def test_old_unpaper(spoof_unpaper_oldversion, resources, no_outpdf): diff --git a/tests/test_validation.py b/tests/test_validation.py index 35c21fa0..3d3221a4 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -22,6 +22,7 @@ from unittest.mock import patch import pytest import ocrmypdf._validation as vd +from ocrmypdf._plugin_manager import get_plugin_manager from ocrmypdf.api import create_options from ocrmypdf.cli import get_parser from ocrmypdf.exceptions import BadArgsError, MissingDependencyError @@ -153,8 +154,9 @@ def test_false_action_store_true(): @pytest.mark.parametrize('progress_bar', [True, False]) def test_no_progress_bar(progress_bar, resources): opts = make_opts(progress_bar=progress_bar, input_file=(resources / 'trivial.pdf')) + plugin_manager = get_plugin_manager(opts.plugins) with patch('ocrmypdf._concurrent.tqdm', autospec=True) as tqdmpatch: - vd.check_options(opts) + vd.check_options(opts, plugin_manager) pdfinfo = PdfInfo(opts.input_file, progbar=opts.progress_bar) assert pdfinfo is not None assert tqdmpatch.called @@ -164,11 +166,12 @@ def test_no_progress_bar(progress_bar, resources): def test_language_warning(caplog): opts = make_opts(language=None) + plugin_manager = get_plugin_manager(opts.plugins) caplog.set_level(logging.DEBUG) with patch( 'ocrmypdf._validation.locale.getlocale', return_value=('en_US', 'UTF-8') ): - vd.check_options_languages(opts) + vd.check_options_languages(opts, plugin_manager) assert opts.language == ['eng'] assert '' in caplog.text @@ -176,7 +179,7 @@ def test_language_warning(caplog): with patch( 'ocrmypdf._validation.locale.getlocale', return_value=('fr_FR', 'UTF-8') ): - vd.check_options_languages(opts) + vd.check_options_languages(opts, plugin_manager) assert opts.language == ['eng'] assert 'assuming --language' in caplog.text