* Avoid DeprecationWarning from pyparsing. OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-bibtexparser?expand=0&rev=23
341 lines
15 KiB
Diff
341 lines
15 KiB
Diff
From f7d86562b0885ae1725a199fdcbc61fe5ee78a68 Mon Sep 17 00:00:00 2001
|
||
From: Jennifer Richards <jennifer@staff.ietf.org>
|
||
Date: Sat, 17 Jan 2026 15:10:16 -0400
|
||
Subject: [PATCH 1/3] Use modern names for pyparsing methods
|
||
|
||
---
|
||
bibtexparser/bibtexexpression.py | 50 ++++++++++-----------
|
||
bibtexparser/bparser.py | 12 ++---
|
||
bibtexparser/tests/test_bibtexexpression.py | 42 ++++++++---------
|
||
3 files changed, 52 insertions(+), 52 deletions(-)
|
||
|
||
diff --git a/bibtexparser/bibtexexpression.py b/bibtexparser/bibtexexpression.py
|
||
index 855d2e8f..ceace6df 100644
|
||
--- a/bibtexparser/bibtexexpression.py
|
||
+++ b/bibtexparser/bibtexexpression.py
|
||
@@ -29,7 +29,7 @@ def add_logger_parse_action(expr, log_func):
|
||
"""Register a callback on expression parsing with the adequate message."""
|
||
def action(s, l, t):
|
||
log_func("Found {}: {}".format(expr.resultsName, t))
|
||
- expr.addParseAction(action)
|
||
+ expr.add_parse_action(action)
|
||
|
||
|
||
# Parse action helpers
|
||
@@ -111,7 +111,7 @@ def __init__(self):
|
||
# String names
|
||
string_name = pp.Word(pp.alphanums + '_-:')('StringName')
|
||
self.set_string_name_parse_action(lambda s, l, t: None)
|
||
- string_name.addParseAction(self._string_name_parse_action)
|
||
+ string_name.add_parse_action(self._string_name_parse_action)
|
||
|
||
# Values inside bibtex fields
|
||
# Values can be integer or string expressions. The latter may use
|
||
@@ -123,27 +123,27 @@ def __init__(self):
|
||
# Braced values: braced values can contain nested (but balanced) braces
|
||
braced_value_content = pp.CharsNotIn('{}')
|
||
braced_value = pp.Forward() # Recursive definition for nested braces
|
||
- braced_value <<= pp.originalTextFor(
|
||
+ braced_value <<= pp.original_text_for(
|
||
'{' + pp.ZeroOrMore(braced_value | braced_value_content) + '}'
|
||
)('BracedValue')
|
||
- braced_value.setParseAction(remove_braces)
|
||
+ braced_value.set_parse_action(remove_braces)
|
||
# TODO add ignore for "\}" and "\{" ?
|
||
# TODO @ are not parsed by bibtex in braces
|
||
|
||
# Quoted values: may contain braced content with balanced braces
|
||
- brace_in_quoted = pp.nestedExpr('{', '}', ignoreExpr=None)
|
||
+ brace_in_quoted = pp.nested_expr('{', '}', ignore_expr=None)
|
||
text_in_quoted = pp.CharsNotIn('"{}')
|
||
# (quotes should be escaped by braces in quoted value)
|
||
- quoted_value = pp.originalTextFor(
|
||
+ quoted_value = pp.original_text_for(
|
||
'"' + pp.ZeroOrMore(text_in_quoted | brace_in_quoted) + '"'
|
||
)('QuotedValue')
|
||
- quoted_value.addParseAction(pp.removeQuotes)
|
||
+ quoted_value.add_parse_action(pp.remove_quotes)
|
||
|
||
# String expressions
|
||
- string_expr = pp.delimitedList(
|
||
+ string_expr = pp.DelimitedList(
|
||
(quoted_value | braced_value | string_name), delim='#'
|
||
)('StringExpression')
|
||
- string_expr.addParseAction(self._string_expr_parse_action)
|
||
+ string_expr.add_parse_action(self._string_expr_parse_action)
|
||
|
||
value = (integer | string_expr)('Value')
|
||
|
||
@@ -151,7 +151,7 @@ def __init__(self):
|
||
|
||
# @EntryType { ...
|
||
entry_type = (pp.Suppress('@') + pp.Word(pp.alphas))('EntryType')
|
||
- entry_type.setParseAction(first_token)
|
||
+ entry_type.set_parse_action(first_token)
|
||
|
||
# Entry key: any character up to a ',' without leading and trailing
|
||
# spaces. Also exclude spaces and prevent it from being empty.
|
||
@@ -175,20 +175,20 @@ def citekeyParseAction(string_, location, token):
|
||
msg="Whitespace not allowed in citekeys.")
|
||
return key
|
||
|
||
- key.setParseAction(citekeyParseAction)
|
||
+ key.set_parse_action(citekeyParseAction)
|
||
|
||
# Field name: word of letters, digits, dashes and underscores
|
||
field_name = pp.Word(pp.alphanums + '_-().+')('FieldName')
|
||
- field_name.setParseAction(first_token)
|
||
+ field_name.set_parse_action(first_token)
|
||
|
||
# Field: field_name = value
|
||
field = pp.Group(field_name + pp.Suppress('=') + value)('Field')
|
||
- field.setParseAction(field_to_pair)
|
||
+ field.set_parse_action(field_to_pair)
|
||
|
||
# List of fields: comma separeted fields
|
||
- field_list = (pp.delimitedList(field) + pp.Suppress(pp.Optional(','))
|
||
+ field_list = (pp.DelimitedList(field) + pp.Suppress(pp.Optional(','))
|
||
)('Fields')
|
||
- field_list.setParseAction(
|
||
+ field_list.set_parse_action(
|
||
lambda s, l, t: {k: v for (k, v) in reversed(t.get('Fields'))})
|
||
|
||
# Entry: type, key, and fields
|
||
@@ -204,10 +204,10 @@ def citekeyParseAction(string_, location, token):
|
||
) | pp.StringEnd()
|
||
self.explicit_comment = (
|
||
pp.Suppress(comment_line_start) +
|
||
- pp.originalTextFor(pp.SkipTo(not_an_implicit_comment),
|
||
- asString=True))('ExplicitComment')
|
||
- self.explicit_comment.addParseAction(remove_trailing_newlines)
|
||
- self.explicit_comment.addParseAction(remove_braces)
|
||
+ pp.original_text_for(pp.SkipTo(not_an_implicit_comment),
|
||
+ as_string=True))('ExplicitComment')
|
||
+ self.explicit_comment.add_parse_action(remove_trailing_newlines)
|
||
+ self.explicit_comment.add_parse_action(remove_braces)
|
||
# Previous implementation included comment until next '}'.
|
||
# This is however not inline with bibtex behavior that is to only
|
||
# ignore until EOL. Brace stipping is arbitrary here but avoids
|
||
@@ -219,10 +219,10 @@ def mustNotBeEmpty(t):
|
||
raise pp.ParseException("Match must not be empty.")
|
||
|
||
# Implicit comments: not anything else
|
||
- self.implicit_comment = pp.originalTextFor(
|
||
- pp.SkipTo(not_an_implicit_comment).setParseAction(mustNotBeEmpty),
|
||
- asString=True)('ImplicitComment')
|
||
- self.implicit_comment.addParseAction(remove_trailing_newlines)
|
||
+ self.implicit_comment = pp.original_text_for(
|
||
+ pp.SkipTo(not_an_implicit_comment).set_parse_action(mustNotBeEmpty),
|
||
+ as_string=True)('ImplicitComment')
|
||
+ self.implicit_comment.add_parse_action(remove_trailing_newlines)
|
||
|
||
# String definition
|
||
self.string_def = (pp.Suppress(string_def_start) + in_braces_or_pars(
|
||
@@ -274,5 +274,5 @@ def _string_name_parse_action(self, s, l, t):
|
||
def _string_expr_parse_action(self, s, l, t):
|
||
return BibDataStringExpression.expression_if_needed(t)
|
||
|
||
- def parseFile(self, file_obj):
|
||
- return self.main_expression.parseFile(file_obj, parseAll=True)
|
||
+ def parse_file(self, file_obj):
|
||
+ return self.main_expression.parse_file(file_obj, parse_all=True)
|
||
diff --git a/bibtexparser/bparser.py b/bibtexparser/bparser.py
|
||
index cbb1dbae..811f25c8 100644
|
||
--- a/bibtexparser/bparser.py
|
||
+++ b/bibtexparser/bparser.py
|
||
@@ -159,7 +159,7 @@ def parse(self, bibtex_str, partial=False):
|
||
|
||
bibtex_file_obj = self._bibtex_file_obj(bibtex_str)
|
||
try:
|
||
- self._expr.parseFile(bibtex_file_obj)
|
||
+ self._expr.parse_file(bibtex_file_obj)
|
||
except self._expr.ParseException as exc:
|
||
logger.error("Could not parse properly, starting at %s", exc.line)
|
||
if not partial:
|
||
@@ -198,20 +198,20 @@ def _init_expressions(self):
|
||
self._expr.add_log_function(logger.debug)
|
||
|
||
# Set actions
|
||
- self._expr.entry.addParseAction(
|
||
+ self._expr.entry.add_parse_action(
|
||
lambda s, l, t: self._add_entry(
|
||
t.get('EntryType'), t.get('Key'), t.get('Fields'))
|
||
)
|
||
- self._expr.implicit_comment.addParseAction(
|
||
+ self._expr.implicit_comment.add_parse_action(
|
||
lambda s, l, t: self._add_comment(t[0])
|
||
)
|
||
- self._expr.explicit_comment.addParseAction(
|
||
+ self._expr.explicit_comment.add_parse_action(
|
||
lambda s, l, t: self._add_comment(t[0])
|
||
)
|
||
- self._expr.preamble_decl.addParseAction(
|
||
+ self._expr.preamble_decl.add_parse_action(
|
||
lambda s, l, t: self._add_preamble(t[0])
|
||
)
|
||
- self._expr.string_def.addParseAction(
|
||
+ self._expr.string_def.add_parse_action(
|
||
lambda s, l, t: self._add_string(t['StringName'].name,
|
||
t['StringValue'])
|
||
)
|
||
diff --git a/bibtexparser/tests/test_bibtexexpression.py b/bibtexparser/tests/test_bibtexexpression.py
|
||
index 1bcab434..e2e878fd 100644
|
||
--- a/bibtexparser/tests/test_bibtexexpression.py
|
||
+++ b/bibtexparser/tests/test_bibtexexpression.py
|
||
@@ -14,90 +14,90 @@ def setUp(self):
|
||
self.expr = BibtexExpression()
|
||
|
||
def test_minimal(self):
|
||
- result = self.expr.entry.parseString('@journal{key, name = 123 }')
|
||
+ result = self.expr.entry.parse_string('@journal{key, name = 123 }')
|
||
self.assertEqual(result.get('EntryType'), 'journal')
|
||
self.assertEqual(result.get('Key'), 'key')
|
||
self.assertEqual(result.get('Fields'), {'name': '123'})
|
||
|
||
def test_capital_type(self):
|
||
- result = self.expr.entry.parseString('@JOURNAL{key, name = 123 }')
|
||
+ result = self.expr.entry.parse_string('@JOURNAL{key, name = 123 }')
|
||
self.assertEqual(result.get('EntryType'), 'JOURNAL')
|
||
|
||
def test_capital_key(self):
|
||
- result = self.expr.entry.parseString('@journal{KEY, name = 123 }')
|
||
+ result = self.expr.entry.parse_string('@journal{KEY, name = 123 }')
|
||
self.assertEqual(result.get('Key'), 'KEY')
|
||
|
||
def test_braced(self):
|
||
- result = self.expr.entry.parseString('@journal{key, name = {abc} }')
|
||
+ result = self.expr.entry.parse_string('@journal{key, name = {abc} }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'abc'})
|
||
|
||
def test_braced_with_new_line(self):
|
||
- result = self.expr.entry.parseString(
|
||
+ result = self.expr.entry.parse_string(
|
||
'@journal{key, name = {abc\ndef} }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'abc\ndef'})
|
||
|
||
def test_braced_unicode(self):
|
||
- result = self.expr.entry.parseString(
|
||
+ result = self.expr.entry.parse_string(
|
||
'@journal{key, name = {àbcđéf} }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'àbcđéf'})
|
||
|
||
def test_quoted(self):
|
||
- result = self.expr.entry.parseString('@journal{key, name = "abc" }')
|
||
+ result = self.expr.entry.parse_string('@journal{key, name = "abc" }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'abc'})
|
||
|
||
def test_quoted_with_new_line(self):
|
||
- result = self.expr.entry.parseString(
|
||
+ result = self.expr.entry.parse_string(
|
||
'@journal{key, name = "abc\ndef" }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'abc\ndef'})
|
||
|
||
def test_quoted_with_unicode(self):
|
||
- result = self.expr.entry.parseString(
|
||
+ result = self.expr.entry.parse_string(
|
||
'@journal{key, name = "àbcđéf" }')
|
||
self.assertEqual(result.get('Fields'), {'name': 'àbcđéf'})
|
||
|
||
def test_entry_declaration_after_space(self):
|
||
- self.expr.entry.parseString(' @journal{key, name = {abcd}}')
|
||
+ self.expr.entry.parse_string(' @journal{key, name = {abcd}}')
|
||
|
||
def test_entry_declaration_no_key(self):
|
||
with self.assertRaises(self.expr.ParseException):
|
||
- self.expr.entry.parseString('@misc{name = {abcd}}')
|
||
+ self.expr.entry.parse_string('@misc{name = {abcd}}')
|
||
|
||
def test_entry_declaration_no_key_new_line(self):
|
||
with self.assertRaises(self.expr.ParseException):
|
||
- self.expr.entry.parseString('@misc{\n name = {abcd}}')
|
||
+ self.expr.entry.parse_string('@misc{\n name = {abcd}}')
|
||
|
||
def test_entry_declaration_no_key_comma(self):
|
||
with self.assertRaises(self.expr.ParseException):
|
||
- self.expr.entry.parseString('@misc{, \nname = {abcd}}')
|
||
+ self.expr.entry.parse_string('@misc{, \nname = {abcd}}')
|
||
|
||
def test_entry_declaration_no_key_keyvalue_without_space(self):
|
||
with self.assertRaises(self.expr.ParseException):
|
||
- self.expr.entry.parseString('@misc{\nname=aaa}')
|
||
+ self.expr.entry.parse_string('@misc{\nname=aaa}')
|
||
|
||
def test_entry_declaration_key_with_whitespace(self):
|
||
with self.assertRaises(self.expr.ParseException):
|
||
- self.expr.entry.parseString('@misc{ xx yy, \n name = aaa}')
|
||
+ self.expr.entry.parse_string('@misc{ xx yy, \n name = aaa}')
|
||
|
||
def test_string_declaration_after_space(self):
|
||
- self.expr.string_def.parseString(' @string{ name = {abcd}}')
|
||
+ self.expr.string_def.parse_string(' @string{ name = {abcd}}')
|
||
|
||
def test_preamble_declaration_after_space(self):
|
||
- self.expr.preamble_decl.parseString(' @preamble{ "blah blah " }')
|
||
+ self.expr.preamble_decl.parse_string(' @preamble{ "blah blah " }')
|
||
|
||
def test_declaration_after_space(self):
|
||
keys = []
|
||
- self.expr.entry.addParseAction(
|
||
+ self.expr.entry.add_parse_action(
|
||
lambda s, l, t: keys.append(t.get('Key'))
|
||
)
|
||
- self.expr.main_expression.parseString(' @journal{key, name = {abcd}}')
|
||
+ self.expr.main_expression.parse_string(' @journal{key, name = {abcd}}')
|
||
self.assertEqual(keys, ['key'])
|
||
|
||
def test_declaration_after_space_and_comment(self):
|
||
keys = []
|
||
- self.expr.entry.addParseAction(
|
||
+ self.expr.entry.add_parse_action(
|
||
lambda s, l, t: keys.append(t.get('Key'))
|
||
)
|
||
- self.expr.main_expression.parseString(
|
||
+ self.expr.main_expression.parse_string(
|
||
'% Implicit comment\n @article{key, name={abcd}}'
|
||
)
|
||
self.assertEqual(keys, ['key'])
|
||
|
||
From ed312f7825296b20339319913e9dc3b33df8cab1 Mon Sep 17 00:00:00 2001
|
||
From: Jennifer Richards <jennifer@staff.ietf.org>
|
||
Date: Sat, 17 Jan 2026 15:11:11 -0400
|
||
Subject: [PATCH 2/3] Update pyparsing requirement
|
||
|
||
---
|
||
requirements.txt | 2 +-
|
||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||
|
||
diff --git a/requirements.txt b/requirements.txt
|
||
index e7c21d1a..f83eb78c 100644
|
||
--- a/requirements.txt
|
||
+++ b/requirements.txt
|
||
@@ -1 +1 @@
|
||
-pyparsing>=2.0.3
|
||
+pyparsing>=3.0.0
|
||
|
||
From 808cb4d54517e8378234f2cd56853c018ecb086c Mon Sep 17 00:00:00 2001
|
||
From: Jennifer Richards <jennifer@staff.ietf.org>
|
||
Date: Sat, 17 Jan 2026 19:04:57 -0400
|
||
Subject: [PATCH 3/3] Alias method for backward compatibility
|
||
|
||
---
|
||
bibtexparser/bibtexexpression.py | 8 ++++++++
|
||
1 file changed, 8 insertions(+)
|
||
|
||
diff --git a/bibtexparser/bibtexexpression.py b/bibtexparser/bibtexexpression.py
|
||
index ceace6df..779a40aa 100644
|
||
--- a/bibtexparser/bibtexexpression.py
|
||
+++ b/bibtexparser/bibtexexpression.py
|
||
@@ -275,4 +275,12 @@ def _string_expr_parse_action(self, s, l, t):
|
||
return BibDataStringExpression.expression_if_needed(t)
|
||
|
||
def parse_file(self, file_obj):
|
||
+ """Execute parse expression on a file object"""
|
||
return self.main_expression.parse_file(file_obj, parse_all=True)
|
||
+
|
||
+ def parseFile(self, file_obj):
|
||
+ """Execute parse expression on a file object
|
||
+
|
||
+ Alias for parse_file()
|
||
+ """
|
||
+ return self.parse_file(file_obj)
|