bibtexparser 2.0.0b4__tar.gz → 2.0.0b5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/PKG-INFO +2 -2
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/README.md +1 -1
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/__init__.py +2 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/library.py +25 -5
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/names.py +10 -4
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser.egg-info/PKG-INFO +2 -2
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser.egg-info/SOURCES.txt +1 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/setup.py +3 -1
- bibtexparser-2.0.0b5/tests/test_library.py +75 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/LICENSE +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/entrypoint.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/exceptions.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/__init__.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/enclosing.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/interpolate.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/latex_encoding.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/middleware.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/month.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/parsestack.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/sorting_blocks.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/sorting_entry_fields.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/model.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/splitter.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/writer.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser.egg-info/dependency_links.txt +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser.egg-info/requires.txt +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser.egg-info/top_level.txt +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/setup.cfg +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/tests/test_entrypoint.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/tests/test_model.py +0 -0
- {bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/tests/test_writer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bibtexparser
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0b5
|
|
4
4
|
Summary: Bibtex parser for python 3
|
|
5
5
|
Home-page: https://github.com/sciunto-org/python-bibtexparser
|
|
6
6
|
Author: Michael Weiss and other contributors
|
|
@@ -35,7 +35,7 @@ Welcome to python-bibtexparser, a parser for `.bib` files with a long history an
|
|
|
35
35
|
Bibtexparser is available in two versions: V1 and V2. For new projects, we recommend using v2 which, in the long run, will provide an overall more robust and faster experience. **For now, however, note that v2 is an early beta, and does not contain all features of v1**. Install v2 using pip:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
pip install
|
|
38
|
+
pip install bibtexparser --pre
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Or you can install the latest development version directly from the main branch:
|
|
@@ -5,7 +5,7 @@ Welcome to python-bibtexparser, a parser for `.bib` files with a long history an
|
|
|
5
5
|
Bibtexparser is available in two versions: V1 and V2. For new projects, we recommend using v2 which, in the long run, will provide an overall more robust and faster experience. **For now, however, note that v2 is an early beta, and does not contain all features of v1**. Install v2 using pip:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
pip install
|
|
8
|
+
pip install bibtexparser --pre
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Or you can install the latest development version directly from the main branch:
|
|
@@ -24,7 +24,9 @@ class Library:
|
|
|
24
24
|
if blocks is not None:
|
|
25
25
|
self.add(blocks)
|
|
26
26
|
|
|
27
|
-
def add(
|
|
27
|
+
def add(
|
|
28
|
+
self, blocks: Union[List[Block], Block], fail_on_duplicate_key: bool = False
|
|
29
|
+
):
|
|
28
30
|
"""Add blocks to library.
|
|
29
31
|
|
|
30
32
|
The adding is key-safe, i.e., it is made sure that no duplicate keys are added.
|
|
@@ -32,14 +34,30 @@ class Library:
|
|
|
32
34
|
a DuplicateKeyBlock.
|
|
33
35
|
|
|
34
36
|
:param blocks: Block or list of blocks to add.
|
|
37
|
+
:param fail_on_duplicate_key: If True, raises ValueError if a block was replaced with a DuplicateKeyBlock.
|
|
35
38
|
"""
|
|
36
39
|
if isinstance(blocks, Block):
|
|
37
40
|
blocks = [blocks]
|
|
38
41
|
|
|
42
|
+
_added_blocks = []
|
|
39
43
|
for block in blocks:
|
|
40
44
|
# This may replace block with a DuplicateEntryKeyBlock
|
|
41
45
|
block = self._add_to_dicts(block)
|
|
42
46
|
self._blocks.append(block)
|
|
47
|
+
_added_blocks.append(block)
|
|
48
|
+
|
|
49
|
+
if fail_on_duplicate_key:
|
|
50
|
+
duplicate_keys = []
|
|
51
|
+
for original, added in zip(blocks, _added_blocks):
|
|
52
|
+
if not original is added and isinstance(added, DuplicateBlockKeyBlock):
|
|
53
|
+
duplicate_keys.append(added.key)
|
|
54
|
+
|
|
55
|
+
if len(duplicate_keys) > 0:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
f"Duplicate keys found: {duplicate_keys}. "
|
|
58
|
+
f"Duplicate entries have been added to the library as DuplicateBlockKeyBlock."
|
|
59
|
+
f"Use `library.failed_blocks` to access them. "
|
|
60
|
+
)
|
|
43
61
|
|
|
44
62
|
def remove(self, blocks: Union[List[Block], Block]):
|
|
45
63
|
"""Remove blocks from library.
|
|
@@ -73,19 +91,19 @@ class Library:
|
|
|
73
91
|
except ValueError:
|
|
74
92
|
raise ValueError("Block to replace is not in library.")
|
|
75
93
|
|
|
76
|
-
self._blocks.insert(index, new_block)
|
|
77
94
|
block_after_add = self._add_to_dicts(new_block)
|
|
95
|
+
self._blocks.insert(index, block_after_add)
|
|
78
96
|
|
|
79
97
|
if (
|
|
80
98
|
new_block is not block_after_add
|
|
81
|
-
and isinstance(
|
|
99
|
+
and isinstance(block_after_add, DuplicateBlockKeyBlock)
|
|
82
100
|
and fail_on_duplicate_key
|
|
83
101
|
):
|
|
84
102
|
# Revert changes to old_block
|
|
85
103
|
# Don't fail on duplicate key, as this would lead to an infinite recursion
|
|
86
104
|
# (should never happen for a clean library, but could happen if the user
|
|
87
105
|
# tampered with the internals of the library).
|
|
88
|
-
self.replace(
|
|
106
|
+
self.replace(block_after_add, old_block, fail_on_duplicate_key=False)
|
|
89
107
|
raise ValueError("Duplicate key found.")
|
|
90
108
|
|
|
91
109
|
@staticmethod
|
|
@@ -160,7 +178,9 @@ class Library:
|
|
|
160
178
|
@property
|
|
161
179
|
def entries(self) -> List[Entry]:
|
|
162
180
|
"""All entry (@article, ...) blocks in the library, preserving order of insertion."""
|
|
163
|
-
|
|
181
|
+
# Note: Taking this from the entries dict would be faster, but does not preserve order
|
|
182
|
+
# e.g. in cases where `replace` has been called.
|
|
183
|
+
return [b for b in self._blocks if isinstance(b, Entry)]
|
|
164
184
|
|
|
165
185
|
@property
|
|
166
186
|
def entries_dict(self) -> Dict[str, Entry]:
|
|
@@ -424,11 +424,17 @@ def parse_single_name_into_parts(name, strict=True):
|
|
|
424
424
|
else:
|
|
425
425
|
lcases = cases[0]
|
|
426
426
|
|
|
427
|
-
|
|
427
|
+
def rindex(l, x, default):
|
|
428
|
+
"""Returns the index of the rightmost occurence of x in l."""
|
|
429
|
+
for i in range(len(l) - 1, -1, -1):
|
|
430
|
+
if l[i] == x:
|
|
431
|
+
return i
|
|
432
|
+
return default
|
|
433
|
+
|
|
434
|
+
# Check if at least one of the words is lowercase
|
|
428
435
|
if 0 in lcases:
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
split = 0 # Last cannot be empty.
|
|
436
|
+
# Excluding the last word, find the index of the last lower word
|
|
437
|
+
split = rindex(lcases[:-1], 0, -1) + 1
|
|
432
438
|
parts.von = sections[0][:split]
|
|
433
439
|
parts.last = sections[0][split:]
|
|
434
440
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bibtexparser
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0b5
|
|
4
4
|
Summary: Bibtex parser for python 3
|
|
5
5
|
Home-page: https://github.com/sciunto-org/python-bibtexparser
|
|
6
6
|
Author: Michael Weiss and other contributors
|
|
@@ -35,7 +35,7 @@ Welcome to python-bibtexparser, a parser for `.bib` files with a long history an
|
|
|
35
35
|
Bibtexparser is available in two versions: V1 and V2. For new projects, we recommend using v2 which, in the long run, will provide an overall more robust and faster experience. **For now, however, note that v2 is an early beta, and does not contain all features of v1**. Install v2 using pip:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
pip install
|
|
38
|
+
pip install bibtexparser --pre
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
Or you can install the latest development version directly from the main branch:
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
import setuptools
|
|
3
3
|
|
|
4
|
-
version =
|
|
4
|
+
version = None
|
|
5
5
|
|
|
6
6
|
with open("bibtexparser/__init__.py") as fh:
|
|
7
7
|
for line in fh:
|
|
8
8
|
if line.startswith("__version__"):
|
|
9
9
|
version = line.strip().split()[-1][1:-1]
|
|
10
10
|
break
|
|
11
|
+
if not version:
|
|
12
|
+
raise RuntimeError("Could not determine version")
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def load_readme():
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from copy import deepcopy
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from bibtexparser import Library
|
|
6
|
+
from bibtexparser.model import Entry, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_dummy_entry():
|
|
10
|
+
return Entry(
|
|
11
|
+
entry_type="article",
|
|
12
|
+
key="duplicateKey",
|
|
13
|
+
fields=[
|
|
14
|
+
Field(key="title", value="A title"),
|
|
15
|
+
Field(key="author", value="An author"),
|
|
16
|
+
],
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_replace_with_duplicates():
|
|
21
|
+
"""Test that replace() works when there are duplicate values. See issue 404."""
|
|
22
|
+
library = Library()
|
|
23
|
+
library.add(get_dummy_entry())
|
|
24
|
+
library.add(get_dummy_entry())
|
|
25
|
+
# Test precondition
|
|
26
|
+
assert len(library.blocks) == 2
|
|
27
|
+
assert len(library.failed_blocks) == 1
|
|
28
|
+
|
|
29
|
+
replacement_entry = get_dummy_entry()
|
|
30
|
+
replacement_entry.fields_dict["title"].value = "A new title"
|
|
31
|
+
|
|
32
|
+
library.replace(
|
|
33
|
+
library.failed_blocks[0], replacement_entry, fail_on_duplicate_key=False
|
|
34
|
+
)
|
|
35
|
+
assert len(library.blocks) == 2
|
|
36
|
+
assert len(library.failed_blocks) == 1
|
|
37
|
+
assert library.failed_blocks[0].ignore_error_block["title"] == "A new title"
|
|
38
|
+
|
|
39
|
+
replacement_entry_2 = get_dummy_entry()
|
|
40
|
+
replacement_entry_2.fields_dict["title"].value = "Another new title"
|
|
41
|
+
|
|
42
|
+
library.replace(
|
|
43
|
+
library.entries[0], replacement_entry_2, fail_on_duplicate_key=False
|
|
44
|
+
)
|
|
45
|
+
assert len(library.blocks) == 2
|
|
46
|
+
assert len(library.failed_blocks) == 1
|
|
47
|
+
# The new block replaces the previous "non-duplicate" and should thus not become a duplicate itself
|
|
48
|
+
assert library.entries[0].fields_dict["title"].value == "Another new title"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_replace_fail_on_duplicate():
|
|
52
|
+
library = Library()
|
|
53
|
+
replaceable_entry = get_dummy_entry()
|
|
54
|
+
replaceable_entry.key = "Just a regular entry, to be replaced"
|
|
55
|
+
future_duplicate_entry = get_dummy_entry()
|
|
56
|
+
library.add([replaceable_entry, future_duplicate_entry])
|
|
57
|
+
|
|
58
|
+
with pytest.raises(ValueError):
|
|
59
|
+
library.replace(
|
|
60
|
+
replaceable_entry, get_dummy_entry(), fail_on_duplicate_key=True
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
assert len(library.blocks) == 2
|
|
64
|
+
assert len(library.failed_blocks) == 0
|
|
65
|
+
assert library.entries[0].key == "Just a regular entry, to be replaced"
|
|
66
|
+
assert library.entries[1].key == "duplicateKey"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_fail_on_duplicate_add():
|
|
70
|
+
library = Library()
|
|
71
|
+
library.add(get_dummy_entry())
|
|
72
|
+
with pytest.raises(ValueError):
|
|
73
|
+
library.add(get_dummy_entry(), fail_on_duplicate_key=True)
|
|
74
|
+
assert len(library.blocks) == 2
|
|
75
|
+
assert len(library.failed_blocks) == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bibtexparser-2.0.0b4 → bibtexparser-2.0.0b5}/bibtexparser/middlewares/sorting_entry_fields.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|