From b1da09f141fe1c9af0aa6c7e3b4cc8b39b5c31ed Mon Sep 17 00:00:00 2001 From: "James R. Barlow" Date: Sun, 31 Jan 2021 02:21:03 -0800 Subject: [PATCH] Add plugin for setting logging console So that we are not tied to tqdm. --- docs/plugins.rst | 2 ++ src/ocrmypdf/__main__.py | 5 +++- src/ocrmypdf/_pipeline.py | 7 ++++-- src/ocrmypdf/api.py | 26 ++++++++++++++------- src/ocrmypdf/builtin_plugins/concurrency.py | 6 +++++ src/ocrmypdf/optimize.py | 2 +- src/ocrmypdf/pluginspec.py | 6 +++++ 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index fb97f7f9..f1c3037c 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -136,6 +136,8 @@ Execution and progress reporting .. autoclass: ocrmypdf.pluginspec.Executor :members: +.. autofunction:: ocrmypdf.pluginspec.get_logging_console + .. autofunction:: ocrmypdf.pluginspec.get_executor .. autofunction:: ocrmypdf.pluginspec.get_progress_bar diff --git a/src/ocrmypdf/__main__.py b/src/ocrmypdf/__main__.py index 3c897b72..1046a50c 100755 --- a/src/ocrmypdf/__main__.py +++ b/src/ocrmypdf/__main__.py @@ -47,7 +47,10 @@ def run(args=None): verbosity = Verbosity.quiet options.progress_bar = False configure_logging( - verbosity, progress_bar_friendly=options.progress_bar, manage_root_logger=True + verbosity, + progress_bar_friendly=options.progress_bar, + manage_root_logger=True, + plugin_manager=plugin_manager, ) log.debug('ocrmypdf %s', __version__) try: diff --git a/src/ocrmypdf/_pipeline.py b/src/ocrmypdf/_pipeline.py index d4c171d8..30ab9751 100644 --- a/src/ocrmypdf/_pipeline.py +++ b/src/ocrmypdf/_pipeline.py @@ -19,7 +19,6 @@ import img2pdf import pikepdf from pikepdf.models.metadata import encode_pdf_date from PIL import Image, ImageColor, ImageDraw -from tqdm import tqdm from ocrmypdf import leptonica from ocrmypdf._concurrent import Executor @@ -726,7 +725,11 @@ def convert_to_pdfa(input_pdf: Path, input_ps_stub: Path, context: PdfContext): output_file=output_file, compression=options.pdfa_image_compression, pdfa_part=options.output_type[-1], # is pdfa-1, pdfa-2, or pdfa-3 - progressbar_class=tqdm if options.progress_bar else None, + progressbar_class=( + context.plugin_manager.hook.get_progress_bar() + if options.progress_bar + else None + ), ) return output_file diff --git a/src/ocrmypdf/api.py b/src/ocrmypdf/api.py index 9a37cad6..60de98fe 100644 --- a/src/ocrmypdf/api.py +++ b/src/ocrmypdf/api.py @@ -15,7 +15,10 @@ from pathlib import Path from typing import AnyStr, BinaryIO, Iterable, Optional, Union from warnings import warn -from ocrmypdf._logging import PageNumberFilter, TqdmConsole +from ocrmypdf._logging import ( # pylint: disable=unused-import + PageNumberFilter, + TqdmConsole, +) from ocrmypdf._plugin_manager import get_plugin_manager from ocrmypdf._sync import run_pipeline from ocrmypdf._validation import check_options @@ -47,6 +50,7 @@ def configure_logging( verbosity: Verbosity, progress_bar_friendly: bool = True, manage_root_logger: bool = False, + plugin_manager=None, ): """Set up logging. @@ -74,12 +78,13 @@ def configure_logging( their own debug logging. Args: - verbosity (Verbosity): Verbosity level. - progress_bar_friendly (bool): Install the TqdmConsole log handler, which is + verbosity: Verbosity level. + progress_bar_friendly: Install the TqdmConsole log handler, which is compatible with the tqdm progress bar; without this log messages will - overwrite the progress bar - manage_root_logger (bool): Configure the process's root logger, to ensure + overwrite the progress bar. + manage_root_logger: Configure the process's root logger, to ensure all log output is sent through + plugin_manager: The plugin manager. Returns: The toplevel logger for ocrmypdf (or the root logger, if we are managing it). @@ -90,8 +95,8 @@ def configure_logging( log = logging.getLogger(prefix) log.setLevel(logging.DEBUG) - if progress_bar_friendly: - console = logging.StreamHandler(stream=TqdmConsole(sys.stderr)) + if plugin_manager and progress_bar_friendly: + console = plugin_manager.hook.get_logging_console() else: console = logging.StreamHandler(stream=sys.stderr) @@ -245,6 +250,7 @@ def ocr( # pylint: disable=unused-argument user_patterns: os.PathLike = None, fast_web_view: float = None, plugins: Iterable[StrPath] = None, + plugin_manager=None, keep_temporary_files: bool = None, progress_bar: bool = None, **kwargs, @@ -296,6 +302,9 @@ def ocr( # pylint: disable=unused-argument Returns: :class:`ocrmypdf.ExitCode` """ + if plugins and plugin_manager: + raise ValueError("plugins= and plugin_manager are mutually exclusive") + if not plugins: plugins = [] elif isinstance(plugins, (str, Path)): @@ -315,7 +324,8 @@ def ocr( # pylint: disable=unused-argument # they might install different plugins, and generally speaking we have areas # of code that use global state. - plugin_manager = get_plugin_manager(plugins) + if not plugin_manager: + plugin_manager = get_plugin_manager(plugins) plugin_manager.hook.add_options(parser=parser) # pylint: disable=no-member if 'verbose' in kwargs: diff --git a/src/ocrmypdf/builtin_plugins/concurrency.py b/src/ocrmypdf/builtin_plugins/concurrency.py index df6d42c6..5bfc05b3 100644 --- a/src/ocrmypdf/builtin_plugins/concurrency.py +++ b/src/ocrmypdf/builtin_plugins/concurrency.py @@ -27,6 +27,7 @@ from typing import Callable, Iterable, Optional, Union from tqdm import tqdm from ocrmypdf import Executor, hookimpl +from ocrmypdf._logging import TqdmConsole from ocrmypdf.exceptions import InputFileError Queue = Union[multiprocessing.Queue, queue.Queue] @@ -161,3 +162,8 @@ def get_executor(): @hookimpl def get_progress_bar(): return tqdm + + +@hookimpl +def get_logging_console(): + return logging.StreamHandler(stream=TqdmConsole(sys.stderr)) diff --git a/src/ocrmypdf/optimize.py b/src/ocrmypdf/optimize.py index 112a26c3..7acb9241 100644 --- a/src/ocrmypdf/optimize.py +++ b/src/ocrmypdf/optimize.py @@ -423,7 +423,7 @@ def transcode_jpegs( pbar.update() executor( - use_threads=True, + use_threads=True, # Processes are significantly slower at this task max_workers=options.jobs, tqdm_kwargs=dict( desc="JPEGs", diff --git a/src/ocrmypdf/pluginspec.py b/src/ocrmypdf/pluginspec.py index cf68fd77..ee4e8dc4 100644 --- a/src/ocrmypdf/pluginspec.py +++ b/src/ocrmypdf/pluginspec.py @@ -8,6 +8,7 @@ from abc import ABC, abstractmethod, abstractstaticmethod from argparse import ArgumentParser, Namespace from collections import namedtuple +from logging import Handler from pathlib import Path from typing import TYPE_CHECKING, AbstractSet, Callable, Iterable, List, Optional @@ -27,6 +28,11 @@ hookspec = pluggy.HookspecMarker('ocrmypdf') # pylint: disable=unused-argument +@hookspec +def get_logging_console() -> Handler: + """Returns a logging handler. Should be configured to handle progress bars.""" + + @hookspec def add_options(parser: ArgumentParser) -> None: """Allows the plugin to add its own command line and API arguments.