Skip to content

Commit 7b96684

Browse files
committed
Make string reference expansion opt-in
* Retain references to string definitions in the default parse stack. * Document and test explicit interpolation before enclosure removal. * Preserve macro linkage during ordinary parse/write use.
1 parent 08e370a commit 7b96684

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

‎bibtexparser/middlewares/parsestack.py‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from bibtexparser.middlewares import ResolveStringReferencesMiddleware
21
from bibtexparser.middlewares.enclosing import AddEnclosingMiddleware
32
from bibtexparser.middlewares.enclosing import RemoveEnclosingMiddleware
43

@@ -8,7 +7,6 @@
87
def default_parse_stack(allow_inplace_modification: bool = True) -> list[Middleware]:
98
"""The default parse stack to be applied after splitting, if not specified otherwise."""
109
return [
11-
ResolveStringReferencesMiddleware(allow_inplace_modification=allow_inplace_modification),
1210
RemoveEnclosingMiddleware(allow_inplace_modification=allow_inplace_modification),
1311
]
1412

‎docs/source/customize.rst‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,22 @@ part of the expected functionality for most users.
4848

4949
Currently, the default parse stack consists of the following layers:
5050

51-
* :class:`bibtexparser.middlewares.ResolveStringReferencesMiddleware`: De-Reference reference to @string definitions.
5251
* :class:`bibtexparser.middlewares.RemoveEnclosingMiddleware`: Removes enclosing (e.g. curly braces or "") from values.
5352

53+
String references are retained by default because replacing a reference with
54+
its current value destroys the relationship with its ``@string`` definition.
55+
Applications that intentionally want dereferenced values can select
56+
:class:`bibtexparser.middlewares.ResolveStringReferencesMiddleware` explicitly,
57+
before removing enclosures:
58+
59+
.. code-block:: python
60+
61+
layers = [
62+
m.ResolveStringReferencesMiddleware(),
63+
m.RemoveEnclosingMiddleware(),
64+
]
65+
library = bibtexparser.parse_file("bibtex.bib", parse_stack=layers)
66+
5467
The default write stack consists of the following layers:
5568

5669
* :class:`bibtexparser.middlewares.AddEnclosingMiddleware`: Encloses values in curly braces where needed.

‎tests/middleware_tests/test_interpolate.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import pytest
22

3+
import bibtexparser
34
from bibtexparser.middlewares.enclosing import RemoveEnclosingMiddleware
45
from bibtexparser.middlewares.interpolate import ResolveStringReferencesMiddleware
56
from bibtexparser.splitter import Splitter
@@ -18,6 +19,28 @@
1819
"""
1920

2021

22+
def test_default_parse_retains_string_reference_linkage():
23+
"""Ordinary parse/write use must not replace a reusable macro with its current value."""
24+
library = bibtexparser.parse_string(bibtex_string)
25+
26+
assert library.entries_dict["test_article"]["note"] == "test_note"
27+
written = bibtexparser.write_string(library)
28+
assert "note = test_note" in written
29+
30+
31+
def test_public_parse_can_expand_string_references_explicitly():
32+
"""Callers can request dereferencing before the enclosing representation changes."""
33+
library = bibtexparser.parse_string(
34+
bibtex_string,
35+
parse_stack=[
36+
ResolveStringReferencesMiddleware(),
37+
RemoveEnclosingMiddleware(),
38+
],
39+
)
40+
41+
assert library.entries_dict["test_article"]["note"] == "This is a test note."
42+
43+
2144
def test_string_interpolation_middleware_interpolates_string():
2245
original_lib = Splitter(bibtex_string).split()
2346

0 commit comments

Comments
 (0)