Repository: sciunto-org/python-bibtexparser

Issue:
Improve duplicate entry (or in general block) handling
**Is your feature request related to a problem? Please describe.**
Right now, when adding something to the library, it seems to always silently deal with duplicate keys.

Doing this silently is not that perfect.

Right now, it might also cause another issue when actually trying to write such a library: #400 

**Describe the solution you'd like**
Ideally, the handling can be improved (like adding some suffix to the key, as typical for such cases in BibTeX).

**Use cases**
Sometimes one does just want to add a valid entry and doesn't want to deal with making sure that it could be added successfully.

**Describe alternatives you've considered**
Manually checking whether the entry has been successfully added after *every* addition of an entry (or at the end).

**Remaining Questions (Optional)**
Please tick all that apply:

- [ ] I would be willing to to contribute a PR to fix this issue.
- [ ] This issue is a blocker, I'd be greatful for an early fix.


Discussion:

Patch:
diff --git a/bibtexparser/library.py b/bibtexparser/library.py
index db01748..2f6a425 100644
--- a/bibtexparser/library.py
+++ b/bibtexparser/library.py
@@ -24,7 +24,9 @@ class Library:
         if blocks is not None:
             self.add(blocks)
 
-    def add(self, blocks: Union[List[Block], Block]):
+    def add(
+        self, blocks: Union[List[Block], Block], fail_on_duplicate_key: bool = False
+    ):
         """Add blocks to library.
 
         The adding is key-safe, i.e., it is made sure that no duplicate keys are added.
@@ -32,14 +34,30 @@ class Library:
         a DuplicateKeyBlock.
 
         :param blocks: Block or list of blocks to add.
+        :param fail_on_duplicate_key: If True, raises ValueError if a block was replaced with a DuplicateKeyBlock.
         """
         if isinstance(blocks, Block):
             blocks = [blocks]
 
+        _added_blocks = []
         for block in blocks:
             # This may replace block with a DuplicateEntryKeyBlock
             block = self._add_to_dicts(block)
             self._blocks.append(block)
+            _added_blocks.append(block)
+
+        if fail_on_duplicate_key:
+            duplicate_keys = []
+            for original, added in zip(blocks, _added_blocks):
+                if not original is added and isinstance(added, DuplicateBlockKeyBlock):
+                    duplicate_keys.append(added.key)
+
+            if len(duplicate_keys) > 0:
+                raise ValueError(
+                    f"Duplicate keys found: {duplicate_keys}. "
+                    f"Duplicate entries have been added to the library as DuplicateBlockKeyBlock."
+                    f"Use `library.failed_blocks` to access them. "
+                )
 
     def remove(self, blocks: Union[List[Block], Block]):
         """Remove blocks from library.


Test patch:
diff --git a/tests/test_library.py b/tests/test_library.py
index 239f76f..e02597e 100644
--- a/tests/test_library.py
+++ b/tests/test_library.py
@@ -64,3 +64,12 @@ def test_replace_fail_on_duplicate():
     assert len(library.failed_blocks) == 0
     assert library.entries[0].key == "Just a regular entry, to be replaced"
     assert library.entries[1].key == "duplicateKey"
+
+
+def test_fail_on_duplicate_add():
+    library = Library()
+    library.add(get_dummy_entry())
+    with pytest.raises(ValueError):
+        library.add(get_dummy_entry(), fail_on_duplicate_key=True)
+    assert len(library.blocks) == 2
+    assert len(library.failed_blocks) == 1