Repository: sciunto-org/python-bibtexparser

Issue:
`@CONTROL{REVTEX41Control}` statement ignored
The [AIP LaTeX template](https://www.overleaf.com/latex/templates/template-for-submission-to-aip-publishing-journals/xhsskcchtbxf) produces an extra bib file, typically named `articleNotes.bib` (when the main tex file is `article.tex`). It contains the following two lines:

```bibtex
@CONTROL{REVTEX41Control}
@CONTROL{aip41Control,pages="1",title="0"}
```

The first line seems to be ignored by python-bibtexparser, while `bibtex` can properly handle it.

Minimal example to reproduce the issue:

```python
import bibtexparser
btp = bibtexparser.bparser.BibTexParser(ignore_nonstandard_types=False)
print(bibtexparser.load(open("articleNotes.bib"), btp).entries)
```

This only prints out the entry corresponding to the second control line:

```python
[{'title': '0', 'pages': '1', 'ENTRYTYPE': 'control', 'ID': 'aip41Control'}]
```

Discussion:

Patch:
diff --git a/bibtexparser/splitter.py b/bibtexparser/splitter.py
index 712e0fe..ce2e55f 100644
--- a/bibtexparser/splitter.py
+++ b/bibtexparser/splitter.py
@@ -348,16 +348,24 @@ class Splitter:
                 "but no closing bracket was found."
             )
         comma_mark = self._next_mark(accept_eof=False)
-        if comma_mark.group(0) != ",":
+        if comma_mark.group(0) == "}":
+            # This is an entry without any comma after the key, and with no fields
+            #   Used e.g. by RefTeX (see issue #384)
+            key = self.bibstr[m.end() + 1 : comma_mark.start()].strip()
+            fields, end_index, duplicate_keys = [], comma_mark.end(), []
+        elif comma_mark.group(0) != ",":
             self._unaccepted_mark = comma_mark
             raise BlockAbortedException(
                 abort_reason="Expected comma after entry key,"
                 f" but found {comma_mark.group(0)}",
                 end_index=comma_mark.end(),
             )
-        self._open_brackets += 1
-        key = self.bibstr[m.end() + 1 : comma_mark.start()].strip()
-        fields, end_index, duplicate_keys = self._move_to_end_of_entry(comma_mark.end())
+        else:
+            self._open_brackets += 1
+            key = self.bibstr[m.end() + 1 : comma_mark.start()].strip()
+            fields, end_index, duplicate_keys = self._move_to_end_of_entry(
+                comma_mark.end()
+            )
 
         entry = Entry(
             start_line=start_line,


Test patch:
diff --git a/tests/splitter_tests/test_splitter_entry.py b/tests/splitter_tests/test_splitter_entry.py
index 4fa6443..c0f26db 100644
--- a/tests/splitter_tests/test_splitter_entry.py
+++ b/tests/splitter_tests/test_splitter_entry.py
@@ -173,3 +173,26 @@ def test_multiple_identical_field_keys():
     journal_field = [f for f in block.ignore_error_block.fields if f.key == "journal"]
     assert len(journal_field) == 1
     assert journal_field[0].value == "{Some journal}"
+
+
+@pytest.mark.parametrize(
+    "entry_without_fields",
+    [
+        # common in revtex, see issue #384
+        pytest.param("@article{articleTestKey}", id="without comma"),
+        pytest.param("@article{articleTestKey,}", id="with comma"),
+    ],
+)
+def test_entry_without_fields(entry_without_fields: str):
+    """For motivation why we need this, please see issue #384"""
+    subsequent_article = "@Article{subsequentArticle, title = {Some title}}"
+    full_bibtex = f"{entry_without_fields}\n\n{subsequent_article}"
+    library: Library = Splitter(full_bibtex).split()
+    assert len(library.entries) == 2
+    assert len(library.failed_blocks) == 0
+
+    assert library.entries[0].key == "articleTestKey"
+    assert len(library.entries[0].fields) == 0
+
+    assert library.entries[1].key == "subsequentArticle"
+    assert len(library.entries[1].fields) == 1