Skip to content

Commit 4701ea9

Browse files
authored
🦖 Make previous breaking change temporarily backwards compatible (#517)
1 parent 9d58eb1 commit 4701ea9

2 files changed

Lines changed: 217 additions & 1 deletion

File tree

‎bibtexparser/entrypoint.py‎

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,52 @@ def _build_unparse_stack(
7575
return list(prepend_middleware) + list(unparse_stack)
7676

7777

78+
def _handle_deprecated_write_params(
79+
unparse_stack: Optional[Iterable[Middleware]],
80+
prepend_middleware: Optional[Iterable[Middleware]],
81+
kwargs: dict,
82+
function_name: str,
83+
) -> tuple[Optional[Iterable[Middleware]], Optional[Iterable[Middleware]]]:
84+
"""Handle deprecated parameter names for write functions.
85+
86+
:param unparse_stack: Current unparse_stack value
87+
:param prepend_middleware: Current prepend_middleware value
88+
:param kwargs: Dictionary of keyword arguments to check for deprecated params
89+
:param function_name: Name of the calling function (for error messages)
90+
:return: Tuple of (unparse_stack, prepend_middleware) with deprecated values migrated
91+
"""
92+
if "parse_stack" in kwargs:
93+
warnings.warn(
94+
"Parameter 'parse_stack' is deprecated. Use 'unparse_stack' instead.",
95+
DeprecationWarning,
96+
stacklevel=3,
97+
)
98+
if unparse_stack is not None:
99+
raise ValueError(
100+
"Cannot provide both 'parse_stack' (deprecated) and 'unparse_stack'. "
101+
"Use 'unparse_stack' instead."
102+
)
103+
unparse_stack = kwargs.pop("parse_stack")
104+
105+
if "append_middleware" in kwargs:
106+
warnings.warn(
107+
"Parameter 'append_middleware' is deprecated. Use 'prepend_middleware' instead.",
108+
DeprecationWarning,
109+
stacklevel=3,
110+
)
111+
if prepend_middleware is not None:
112+
raise ValueError(
113+
"Cannot provide both 'append_middleware' (deprecated) and 'prepend_middleware'. "
114+
"Use 'prepend_middleware' instead."
115+
)
116+
prepend_middleware = kwargs.pop("append_middleware")
117+
118+
if kwargs:
119+
raise TypeError(f"{function_name}() got unexpected keyword arguments: {', '.join(kwargs)}")
120+
121+
return unparse_stack, prepend_middleware
122+
123+
78124
def parse_string(
79125
bibtex_str: str,
80126
parse_stack: Optional[Iterable[Middleware]] = None,
@@ -147,6 +193,7 @@ def write_file(
147193
prepend_middleware: Optional[Iterable[Middleware]] = None,
148194
bibtex_format: Optional[BibtexFormat] = None,
149195
encoding: str = "UTF-8",
196+
**kwargs,
150197
) -> None:
151198
"""Write a BibTeX database to a file.
152199
@@ -157,7 +204,16 @@ def write_file(
157204
:param prepend_middleware: List of middleware to prepend to the default stack.
158205
Only applicable if `unparse_stack` is None.
159206
:param bibtex_format: Customized BibTeX format to use (optional).
160-
:param encoding: Encoding of the .bib file. Default encoding is ``"UTF-8"``."""
207+
:param encoding: Encoding of the .bib file. Default encoding is ``"UTF-8"``.
208+
209+
.. deprecated:: (next version)
210+
Parameters 'parse_stack' and 'append_middleware' are deprecated, will be deleted soon.
211+
Use 'unparse_stack' and 'prepend_middleware' instead.
212+
"""
213+
unparse_stack, prepend_middleware = _handle_deprecated_write_params(
214+
unparse_stack, prepend_middleware, kwargs, "write_file"
215+
)
216+
161217
bibtex_str = write_string(
162218
library=library,
163219
unparse_stack=unparse_stack,
@@ -176,6 +232,7 @@ def write_string(
176232
unparse_stack: Optional[Iterable[Middleware]] = None,
177233
prepend_middleware: Optional[Iterable[Middleware]] = None,
178234
bibtex_format: Optional["BibtexFormat"] = None,
235+
**kwargs,
179236
) -> str:
180237
"""Serialize a BibTeX database to a string.
181238
@@ -185,7 +242,15 @@ def write_string(
185242
:param prepend_middleware: List of middleware to prepend to the default stack.
186243
Only applicable if `unparse_stack` is None.
187244
:param bibtex_format: Customized BibTeX format to use (optional).
245+
246+
.. deprecated:: (next version)
247+
Parameters 'parse_stack' and 'append_middleware' are deprecated.
248+
Use 'unparse_stack' and 'prepend_middleware' instead.
188249
"""
250+
unparse_stack, prepend_middleware = _handle_deprecated_write_params(
251+
unparse_stack, prepend_middleware, kwargs, "write_string"
252+
)
253+
189254
middleware: Middleware
190255
for middleware in _build_unparse_stack(unparse_stack, prepend_middleware):
191256
library = middleware.transform(library=library)

‎tests/test_entrypoint.py‎

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
import os
44
import tempfile
5+
import warnings
6+
7+
import pytest
58

69
from bibtexparser import parse_file
710
from bibtexparser import write_file
11+
from bibtexparser import write_string
812
from bibtexparser.library import Library
913
from bibtexparser.model import Entry
1014
from bibtexparser.model import Field
@@ -90,3 +94,150 @@ def test_write_file_roundtrip_gbk():
9094
assert library2.entries[0]["journal"] == original_journal
9195
finally:
9296
os.unlink(temp_path)
97+
98+
99+
# Deprecation warning tests for write_file and write_string
100+
def test_write_file_deprecated_parse_stack_parameter():
101+
"""Test that using deprecated 'parse_stack' parameter issues a warning."""
102+
library = Library([])
103+
104+
with tempfile.NamedTemporaryFile(mode="w", suffix=".bib", delete=False) as f:
105+
temp_path = f.name
106+
107+
try:
108+
with warnings.catch_warnings(record=True) as w:
109+
warnings.simplefilter("always")
110+
write_file(temp_path, library, parse_stack=[])
111+
assert len(w) == 1
112+
assert issubclass(w[0].category, DeprecationWarning)
113+
assert "parse_stack" in str(w[0].message)
114+
assert "unparse_stack" in str(w[0].message)
115+
finally:
116+
os.unlink(temp_path)
117+
118+
119+
def test_write_file_deprecated_append_middleware_parameter():
120+
"""Test that using deprecated 'append_middleware' parameter issues a warning."""
121+
library = Library([])
122+
123+
with tempfile.NamedTemporaryFile(mode="w", suffix=".bib", delete=False) as f:
124+
temp_path = f.name
125+
126+
try:
127+
with warnings.catch_warnings(record=True) as w:
128+
warnings.simplefilter("always")
129+
write_file(temp_path, library, append_middleware=[])
130+
assert len(w) == 1
131+
assert issubclass(w[0].category, DeprecationWarning)
132+
assert "append_middleware" in str(w[0].message)
133+
assert "prepend_middleware" in str(w[0].message)
134+
finally:
135+
os.unlink(temp_path)
136+
137+
138+
def test_write_file_both_parse_stack_and_unparse_stack_raises_error():
139+
"""Test that providing both parse_stack and unparse_stack raises ValueError."""
140+
library = Library([])
141+
142+
with tempfile.NamedTemporaryFile(mode="w", suffix=".bib", delete=False) as f:
143+
temp_path = f.name
144+
145+
try:
146+
with pytest.raises(ValueError) as excinfo:
147+
write_file(temp_path, library, parse_stack=[], unparse_stack=[])
148+
assert "parse_stack" in str(excinfo.value)
149+
assert "unparse_stack" in str(excinfo.value)
150+
assert "Use 'unparse_stack' instead" in str(excinfo.value)
151+
finally:
152+
os.unlink(temp_path)
153+
154+
155+
def test_write_file_both_append_and_prepend_middleware_raises_error():
156+
"""Test that providing both append_middleware and prepend_middleware raises ValueError."""
157+
library = Library([])
158+
159+
with tempfile.NamedTemporaryFile(mode="w", suffix=".bib", delete=False) as f:
160+
temp_path = f.name
161+
162+
try:
163+
with pytest.raises(ValueError) as excinfo:
164+
write_file(temp_path, library, append_middleware=[], prepend_middleware=[])
165+
assert "append_middleware" in str(excinfo.value)
166+
assert "prepend_middleware" in str(excinfo.value)
167+
assert "Use 'prepend_middleware' instead" in str(excinfo.value)
168+
finally:
169+
os.unlink(temp_path)
170+
171+
172+
def test_write_file_unexpected_keyword_argument_raises_error():
173+
"""Test that unexpected keyword arguments raise TypeError."""
174+
library = Library([])
175+
176+
with tempfile.NamedTemporaryFile(mode="w", suffix=".bib", delete=False) as f:
177+
temp_path = f.name
178+
179+
try:
180+
with pytest.raises(TypeError) as excinfo:
181+
write_file(temp_path, library, unknown_param="value")
182+
assert "unexpected keyword arguments" in str(excinfo.value)
183+
assert "unknown_param" in str(excinfo.value)
184+
finally:
185+
os.unlink(temp_path)
186+
187+
188+
def test_write_string_deprecated_parse_stack_parameter():
189+
"""Test that using deprecated 'parse_stack' parameter issues a warning."""
190+
library = Library([])
191+
192+
with warnings.catch_warnings(record=True) as w:
193+
warnings.simplefilter("always")
194+
write_string(library, parse_stack=[])
195+
assert len(w) == 1
196+
assert issubclass(w[0].category, DeprecationWarning)
197+
assert "parse_stack" in str(w[0].message)
198+
assert "unparse_stack" in str(w[0].message)
199+
200+
201+
def test_write_string_deprecated_append_middleware_parameter():
202+
"""Test that using deprecated 'append_middleware' parameter issues a warning."""
203+
library = Library([])
204+
205+
with warnings.catch_warnings(record=True) as w:
206+
warnings.simplefilter("always")
207+
write_string(library, append_middleware=[])
208+
assert len(w) == 1
209+
assert issubclass(w[0].category, DeprecationWarning)
210+
assert "append_middleware" in str(w[0].message)
211+
assert "prepend_middleware" in str(w[0].message)
212+
213+
214+
def test_write_string_both_parse_stack_and_unparse_stack_raises_error():
215+
"""Test that providing both parse_stack and unparse_stack raises ValueError."""
216+
library = Library([])
217+
218+
with pytest.raises(ValueError) as excinfo:
219+
write_string(library, parse_stack=[], unparse_stack=[])
220+
assert "parse_stack" in str(excinfo.value)
221+
assert "unparse_stack" in str(excinfo.value)
222+
assert "Use 'unparse_stack' instead" in str(excinfo.value)
223+
224+
225+
def test_write_string_both_append_and_prepend_middleware_raises_error():
226+
"""Test that providing both append_middleware and prepend_middleware raises ValueError."""
227+
library = Library([])
228+
229+
with pytest.raises(ValueError) as excinfo:
230+
write_string(library, append_middleware=[], prepend_middleware=[])
231+
assert "append_middleware" in str(excinfo.value)
232+
assert "prepend_middleware" in str(excinfo.value)
233+
assert "Use 'prepend_middleware' instead" in str(excinfo.value)
234+
235+
236+
def test_write_string_unexpected_keyword_argument_raises_error():
237+
"""Test that unexpected keyword arguments raise TypeError."""
238+
library = Library([])
239+
240+
with pytest.raises(TypeError) as excinfo:
241+
write_string(library, unknown_param="value")
242+
assert "unexpected keyword arguments" in str(excinfo.value)
243+
assert "unknown_param" in str(excinfo.value)

0 commit comments

Comments
 (0)