From a253f8388ffb66348874065a25154e38346c5225 Mon Sep 17 00:00:00 2001 From: Michael Weiss Date: Fri, 12 Jun 2026 13:13:07 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20String=20values=20becoming?= =?UTF-8?q?=20tuples=20in=20latex=20transformation=20middlewares?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- bibtexparser/middlewares/latex_encoding.py | 4 +- tests/middleware_tests/test_latex_encoding.py | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/bibtexparser/middlewares/latex_encoding.py b/bibtexparser/middlewares/latex_encoding.py index 9139763..2bb244b 100644 --- a/bibtexparser/middlewares/latex_encoding.py +++ b/bibtexparser/middlewares/latex_encoding.py @@ -76,7 +76,9 @@ def transform_entry(self, entry: Entry, library: Library) -> Block: # docstr-coverage: inherited def transform_string(self, string: String, library: "Library") -> Block: if isinstance(string.value, str): - string.value = self._transform_python_value_string(string.value) + string.value, error = self._transform_python_value_string(string.value) + if error != "": + return MiddlewareErrorBlock(block=string, error=PartialMiddlewareException([error])) else: logger.info( f" [{self.metadata_key()}] Cannot python-str transform string {string.key}" diff --git a/tests/middleware_tests/test_latex_encoding.py b/tests/middleware_tests/test_latex_encoding.py index 4a0c1a8..f8057b4 100644 --- a/tests/middleware_tests/test_latex_encoding.py +++ b/tests/middleware_tests/test_latex_encoding.py @@ -4,14 +4,19 @@ Thus, we merely test that the middleware is correctly configured.""" from copy import deepcopy +from typing import Tuple import pytest from bibtexparser import Library +from bibtexparser.exceptions import PartialMiddlewareException from bibtexparser.middlewares.latex_encoding import LatexDecodingMiddleware from bibtexparser.middlewares.latex_encoding import LatexEncodingMiddleware +from bibtexparser.middlewares.latex_encoding import _PyStringTransformerMiddleware from bibtexparser.model import Entry from bibtexparser.model import Field +from bibtexparser.model import MiddlewareErrorBlock +from bibtexparser.model import String from tests.middleware_tests.middleware_test_util import assert_inplace_is_respected from tests.middleware_tests.middleware_test_util import assert_nonfield_entry_attributes_unchanged @@ -111,6 +116,49 @@ def test_latex_special_chars_encoding(human_string, expected_latex_string): assert_nonfield_entry_attributes_unchanged(original_copy, transformed_entry) +@pytest.mark.parametrize( + "middleware_class,input_value,expected_value", + [ + pytest.param(LatexDecodingMiddleware, r"M{\"u}ller", "Müller", id="decoding"), + pytest.param(LatexEncodingMiddleware, "Müller", r"M\"uller", id="encoding"), + ], +) +def test_string_block_value_transformation(middleware_class, input_value, expected_value): + """String block values must be transformed like field values (issue #529).""" + library = Library([String(key="me", value=input_value, start_line=1, raw="irrelevant")]) + + transformed_library = middleware_class(allow_inplace_modification=True).transform(library) + + transformed_value = transformed_library.strings[0].value + assert isinstance(transformed_value, str) + assert transformed_value == expected_value + + +def test_failing_string_transformation_becomes_error_block(): + """Transformation errors on String blocks must not be swallowed (issue #529).""" + + class _FailingMiddleware(_PyStringTransformerMiddleware): + """Test dummy that fails on every value.""" + + # docstr-coverage: inherited + @classmethod + def metadata_key(cls) -> str: + return "failing_test_middleware" + + # docstr-coverage: inherited + def _transform_python_value_string(self, python_string: str) -> Tuple[str, str]: + return python_string, "some error" + + library = Library([String(key="me", value="some value", start_line=1, raw="irrelevant")]) + + transformed_library = _FailingMiddleware(allow_inplace_modification=True).transform(library) + + assert len(transformed_library.failed_blocks) == 1 + error_block = transformed_library.failed_blocks[0] + assert isinstance(error_block, MiddlewareErrorBlock) + assert isinstance(error_block.error, PartialMiddlewareException) + + @pytest.mark.parametrize("inplace", [True, False]) @pytest.mark.parametrize("middleware_class", [LatexEncodingMiddleware, LatexDecodingMiddleware]) def test_inplace(inplace: bool, middleware_class):