parser

.bib file parsing and reformatted output.

bib_checker.parser

Parse a .bib file into BibEntry objects using bibtexparser v2.

parse_bib_file

parse_bib_file(path)

Parse a .bib file and return a list of BibEntry objects.

Parameters:
  • path (str or Path) –

    Path to the .bib file to parse.

Returns:
  • entries( list[BibEntry] ) –

    Parsed entries in document order.

Raises:
  • FileNotFoundError –

    Raised if path does not exist.

Source code in src/bib_checker/parser.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def parse_bib_file(path: str | Path) -> list[BibEntry]:
    """Parse a .bib file and return a list of BibEntry objects.

    Parameters
    ----------
    path : str or Path
        Path to the .bib file to parse.

    Returns
    -------
    entries : list[BibEntry]
        Parsed entries in document order.

    Raises
    ------
    FileNotFoundError
        Raised if *path* does not exist.
    """
    path = Path(path)
    if not path.exists():
        raise FileNotFoundError(f"Bib file not found: {path}")

    library = bibtexparser.parse_file(str(path))

    entries: list[BibEntry] = []
    for entry in library.entries:
        fields: dict[str, str] = {k: _field_to_str(v) for k, v in entry.fields_dict.items()}
        entries.append(
            BibEntry(
                key=entry.key,
                entry_type=entry.entry_type,
                fields=fields,
            )
        )

    return entries

write_reformatted_bib

write_reformatted_bib(
    source_path, flagged_keys, output_path
)

Write a reformatted .bib file with flagged entries moved to the end.

OK entries are written first, followed by a separator comment block, then the flagged (missing/mismatch) entries. If there are no flagged entries the separator is omitted and the file is a straight copy.

Parameters:
  • source_path (str or Path) –

    Original .bib file to read from.

  • flagged_keys (set[str]) –

    Citation keys that need attention (missing or mismatch).

  • output_path (str or Path) –

    Path to write the reformatted .bib file to.

Returns:
  • n_ok( int ) –

    Number of entries written before the separator.

  • n_flagged( int ) –

    Number of entries written after the separator.

Raises:
  • FileNotFoundError –

    Raised if source_path does not exist.

Source code in src/bib_checker/parser.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def write_reformatted_bib(
    source_path: str | Path,
    flagged_keys: set[str],
    output_path: str | Path,
) -> tuple[int, int]:
    """Write a reformatted .bib file with flagged entries moved to the end.

    OK entries are written first, followed by a separator comment block, then
    the flagged (missing/mismatch) entries.  If there are no flagged entries
    the separator is omitted and the file is a straight copy.

    Parameters
    ----------
    source_path : str or Path
        Original .bib file to read from.
    flagged_keys : set[str]
        Citation keys that need attention (missing or mismatch).
    output_path : str or Path
        Path to write the reformatted .bib file to.

    Returns
    -------
    n_ok : int
        Number of entries written before the separator.
    n_flagged : int
        Number of entries written after the separator.

    Raises
    ------
    FileNotFoundError
        Raised if *source_path* does not exist.
    """
    source_path = Path(source_path)
    output_path = Path(output_path)

    if not source_path.exists():
        raise FileNotFoundError(f"Bib file not found: {source_path}")

    library = bibtexparser.parse_file(str(source_path))

    ok_entries = [e for e in library.entries if e.key not in flagged_keys]
    bad_entries = [e for e in library.entries if e.key in flagged_keys]

    ok_lib = bibtexparser.Library()
    ok_lib.add(ok_entries)

    ok_text = bibtexparser.write_string(ok_lib).rstrip("\n")

    if bad_entries:
        bad_lib = bibtexparser.Library()
        bad_lib.add(bad_entries)
        bad_text = bibtexparser.write_string(bad_lib)
        full_text = ok_text + "\n\n" + _SEPARATOR + "\n" + bad_text
    else:
        full_text = ok_text + "\n"

    output_path.write_text(full_text, encoding="utf-8")

    return len(ok_entries), len(bad_entries)