Fix Python API ignoring language parameter (fixes #1640)

The API's 'language' param was silently dropped because OcrOptions uses
'languages' (plural). Map language->languages in create_options() and
_pdf_to_hocr(), coercing bare strings to lists and splitting '+'
separated codes to match CLI behavior.
This commit is contained in:
James R. Barlow
2026-02-20 17:10:57 -08:00
parent aca5eb626b
commit b4e8e9dac9
2 changed files with 92 additions and 0 deletions
+34
View File
@@ -283,6 +283,34 @@ def _check_no_conflicting_ocr_params(
)
def _remap_language_to_languages(options_kwargs: dict) -> None:
"""Map the public API 'language' parameter to OcrOptions 'languages' field.
The public API uses 'language' (matching CLI --language) but OcrOptions
uses 'languages' (plural). This also coerces a bare string to a list
and splits '+'-separated language codes (e.g. 'eng+deu' -> ['eng', 'deu'])
to match the CLI behavior.
"""
if 'language' in options_kwargs and 'languages' not in options_kwargs:
lang = options_kwargs.pop('language')
if lang is None:
return
if isinstance(lang, str):
lang = lang.split('+')
else:
# Flatten any '+'-separated entries in the list
expanded: list[str] = []
for item in lang:
if isinstance(item, str) and '+' in item:
expanded.extend(item.split('+'))
else:
expanded.append(item)
lang = expanded
options_kwargs['languages'] = lang
elif 'language' in options_kwargs:
del options_kwargs['language']
def create_options(
*, input_file: PathOrIO, output_file: PathOrIO, parser: ArgumentParser, **kwargs
) -> OcrOptions:
@@ -304,6 +332,9 @@ def create_options(
# Prepare kwargs for direct OcrOptions construction
options_kwargs = kwargs.copy()
# Map API parameter 'language' to OcrOptions field 'languages'
_remap_language_to_languages(options_kwargs)
# Set input and output files
options_kwargs['input_file'] = input_file
options_kwargs['output_file'] = output_file
@@ -762,6 +793,9 @@ def _pdf_to_hocr( # noqa: D417
):
options_kwargs[param_name] = param_value
# Map API parameter 'language' to OcrOptions field 'languages'
_remap_language_to_languages(options_kwargs)
# Handle plugins
if plugins:
options_kwargs['plugins'] = plugins
+58
View File
@@ -22,6 +22,64 @@ def test_language_list():
ocrmypdf.ocr('doesnotexist.pdf', '_.pdf', language=['eng', 'deu'])
def test_language_parameter_mapped_to_languages():
"""Test that the API 'language' parameter is mapped to OcrOptions 'languages'.
Regression test for GitHub issue #1640: the Python API ignored the language
parameter, always defaulting to 'eng'.
"""
from ocrmypdf._options import OcrOptions
from ocrmypdf.api import create_options, setup_plugin_infrastructure
from ocrmypdf.cli import get_parser
setup_plugin_infrastructure()
parser = get_parser()
options = create_options(
input_file='test.pdf',
output_file='output.pdf',
parser=parser,
language=['tam'],
)
assert options.languages == ['tam']
# Test with a list of multiple languages
options = create_options(
input_file='test.pdf',
output_file='output.pdf',
parser=parser,
language=['fra', 'deu'],
)
assert options.languages == ['fra', 'deu']
# Test with a bare string (single language)
options = create_options(
input_file='test.pdf',
output_file='output.pdf',
parser=parser,
language='tam',
)
assert options.languages == ['tam']
# Test '+'-separated string is split like CLI --language
options = create_options(
input_file='test.pdf',
output_file='output.pdf',
parser=parser,
language='eng+spa',
)
assert options.languages == ['eng', 'spa']
# Test '+'-separated entry within a list is also split
options = create_options(
input_file='test.pdf',
output_file='output.pdf',
parser=parser,
language=['eng+spa'],
)
assert options.languages == ['eng', 'spa']
def test_stream_api(resources: Path):
in_ = (resources / 'graph.pdf').open('rb')
out = BytesIO()