Skip to content

Commit b187fcc

Browse files
committed
release breaking change more nicely (backwards compatible)
1 parent fcfb0cb commit b187fcc

2 files changed

Lines changed: 219 additions & 1 deletion

File tree

bibtexparser/entrypoint.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,54 @@ 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(
120+
f"{function_name}() got unexpected keyword arguments: {', '.join(kwargs)}"
121+
)
122+
123+
return unparse_stack, prepend_middleware
124+
125+
78126
def parse_string(
79127
bibtex_str: str,
80128
parse_stack: Optional[Iterable[Middleware]] = None,
@@ -147,6 +195,7 @@ def write_file(
147195
prepend_middleware: Optional[Iterable[Middleware]] = None,
148196
bibtex_format: Optional[BibtexFormat] = None,
149197
encoding: str = "UTF-8",
198+
**kwargs,
150199
) -> None:
151200
"""Write a BibTeX database to a file.
152201
@@ -157,7 +206,16 @@ def write_file(
157206
:param prepend_middleware: List of middleware to prepend to the default stack.
158207
Only applicable if `unparse_stack` is None.
159208
:param bibtex_format: Customized BibTeX format to use (optional).
160-
:param encoding: Encoding of the .bib file. Default encoding is ``"UTF-8"``."""
209+
:param encoding: Encoding of the .bib file. Default encoding is ``"UTF-8"``.
210+
211+
.. deprecated:: (next version)
212+
Parameters 'parse_stack' and 'append_middleware' are deprecated, will be deleted soon.
213+
Use 'unparse_stack' and 'prepend_middleware' instead.
214+
"""
215+
unparse_stack, prepend_middleware = _handle_deprecated_write_params(
216+
unparse_stack, prepend_middleware, kwargs, "write_file"
217+
)
218+
161219
bibtex_str = write_string(
162220
library=library,
163221
unparse_stack=unparse_stack,
@@ -176,6 +234,7 @@ def write_string(
176234
unparse_stack: Optional[Iterable[Middleware]] = None,
177235
prepend_middleware: Optional[Iterable[Middleware]] = None,
178236
bibtex_format: Optional["BibtexFormat"] = None,
237+
**kwargs,
179238
) -> str:
180239
"""Serialize a BibTeX database to a string.
181240
@@ -185,7 +244,15 @@ def write_string(
185244
:param prepend_middleware: List of middleware to prepend to the default stack.
186245
Only applicable if `unparse_stack` is None.
187246
:param bibtex_format: Customized BibTeX format to use (optional).
247+
248+
.. deprecated:: (next version)
249+
Parameters 'parse_stack' and 'append_middleware' are deprecated.
250+
Use 'unparse_stack' and 'prepend_middleware' instead.
188251
"""
252+
unparse_stack, prepend_middleware = _handle_deprecated_write_params(
253+
unparse_stack, prepend_middleware, kwargs, "write_string"
254+
)
255+
189256
middleware: Middleware
190257
for middleware in _build_unparse_stack(unparse_stack, prepend_middleware):
191258
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)