Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ A Python tool to parse BibTeX entries and run (custom) checks on them.
> bibtex_linter refs.bib

Entry 'SomeBook' of type 'BOOK' failed verification:
❌ Invariant Violations:
- Entry 'SomeBook' misses the following required fields: [publisher]
- Entry 'SomeBook' has fields present that would be omitted in the compiled document: [url]. This could lead to a loss of information.
❌ Misses the following required fields: [publisher]
❌ Has fields present that would be omitted in the compiled document: [url]. This could lead to a loss of information.

Found 2 invariant violations in 17 entries.
```
Expand Down Expand Up @@ -83,7 +82,7 @@ def check_article(entry: BibTeXEntry) -> List[str]:
:return: A list of string descriptions of rule violations for this entry.
"""
if not entry.fields.get("author"):
return [f"Entry '{entry.name}' misses the required field author!"]
return ["Misses the required field [author]."]
return []
```

Expand Down
12 changes: 6 additions & 6 deletions bibtex_linter/ieeetr_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def check_online(entry: BibTeXEntry) -> List[str]:
"url",
}
if "note" not in entry.fields.keys():
invariant_violations.append(f"Entry '{entry.name}' is of type 'online' and needs a field 'note' with the URL.")
invariant_violations.append("Is of type 'online' and needs a field 'note' with the URL.")
# Todo: In the future, we could actually check that it contains an URL
invariant_violations.extend(check_required_fields(entry, required_fields))
invariant_violations.extend(check_omitted_fields(entry, omitted_fields))
Expand Down Expand Up @@ -145,8 +145,8 @@ def check_in_book(entry: BibTeXEntry) -> List[str]:
"url",
}
if "chapter" not in entry.fields.keys() or "pages" not in entry.fields.keys():
invariant_violations.append(f"Entry {entry.name} needs to contain one of the "
f"following fields: [chapter, pages].")
invariant_violations.append("Needs to contain one of the "
"following fields: [chapter, pages].")
invariant_violations.extend(check_required_fields(entry, required_fields))
invariant_violations.extend(check_omitted_fields(entry, omitted_fields))
return invariant_violations
Expand Down Expand Up @@ -233,9 +233,9 @@ def check_tech_report(entry: BibTeXEntry) -> List[str]:
"url",
}
if "howpublished" in entry.fields.keys():
invariant_violations.append(f"Entry {entry.name} is of type 'techreport', which does not render field "
f"'howpublished'. Either use field 'institution' instead, or switch to a different "
f"entry type completely.")
invariant_violations.append("Is of type 'techreport', which does not render field "
"'howpublished'. Either use field 'institution' instead, or switch to a different "
"entry type completely.")
invariant_violations.extend(check_required_fields(entry, required_fields))
invariant_violations.extend(check_omitted_fields(entry, omitted_fields))
return invariant_violations
Expand Down
18 changes: 9 additions & 9 deletions bibtex_linter/ieeetran_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ def check_url_field(entry: BibTeXEntry) -> List[str]:
invariant_violations: List[str] = []
if "url" in entry.fields.keys():
invariant_violations.append(
f"Entry '{entry.name}' contains the non-allowed field: [url]. "
f"Move the content of the field into the [note] field."
"Contains the non-allowed field: [url]. "
"Move the content of the field into the [note] field."
)
if "note" in entry.fields.keys():
note_content: str = entry.fields["note"]
pattern = r"^\[ONLINE\]\. Available: \\url\{(.+?)\}, Accessed: (\d{4}-\d{2}-\d{2})$"
match = re.match(pattern, note_content)
if not match:
invariant_violations.append(
f"Entry '{entry.name}' contains a malformed field [note]. "
"Contains a malformed field [note]. "
"Make sure the [note] field follows the following pattern: '[ONLINE]. Available: \\url{...}, "
"Accessed: YYYY-mmm-dd'"
)
Expand Down Expand Up @@ -103,7 +103,7 @@ def check_conference(entry: BibTeXEntry) -> List[str]:
))
if entry.fields.get("organization") == entry.fields.get("publisher"):
invariant_violations.append(
f"Entry '{entry.name}' fields [organization] and [publisher] are the same. Remove field [organization]."
"Fields [organization] and [publisher] are the same. Remove field [organization]."
)
return invariant_violations

Expand Down Expand Up @@ -134,7 +134,7 @@ def check_online(entry: BibTeXEntry) -> List[str]:
))
if entry.fields.get("organization") == entry.fields.get("author"):
invariant_violations.append(
f"Entry '{entry.name}' fields [organization] and [author] are the same. Remove field [organization]."
"Fields [organization] and [author] are the same. Remove field [organization]."
)
return invariant_violations

Expand All @@ -160,7 +160,7 @@ def check_book(entry: BibTeXEntry) -> List[str]:
))
if entry.fields.get("publisher") == entry.fields.get("editor"):
invariant_violations.append(
f"Entry '{entry.name}' fields [publisher] and [editor] are the same. Remove field [editor]."
"Fields [publisher] and [editor] are the same. Remove field [editor]."
)
return invariant_violations

Expand Down Expand Up @@ -225,7 +225,7 @@ def check_in_collection(entry: BibTeXEntry) -> List[str]:
))
if entry.fields.get("editor") == entry.fields.get("publisher"):
invariant_violations.append(
f"Entry '{entry.name}' fields [editor] and [publisher] are the same. Remove field [editor]."
"Fields [editor] and [publisher] are the same. Remove field [editor]."
)
return invariant_violations

Expand Down Expand Up @@ -263,7 +263,7 @@ def check_standard(entry: BibTeXEntry) -> List[str]:
))
if entry.fields.get("author") == entry.fields.get("organization"):
invariant_violations.append(
f"Entry '{entry.name}' fields [author] and [organization] are the same. Remove field [author]."
"Fields [author] and [organization] are the same. Remove field [author]."
)
return invariant_violations

Expand All @@ -276,7 +276,7 @@ def check_tech_report(entry: BibTeXEntry) -> List[str]:
:param entry: The BibTeXEntry
:return: A list of string descriptions of rule violations for this entry.
"""
return [f"Entry '{entry.name}' is of type 'TECHREPORT'. Please use a different entry type, such as 'STANDARD'."]
return ["Is of type 'TECHREPORT'. Please use a different entry type, such as 'STANDARD'."]


@linter_rule(entry_type="misc")
Expand Down
3 changes: 1 addition & 2 deletions bibtex_linter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ def main() -> None:
if violations:
had_violations = True
print(f"\nEntry '{entry.name}' of type '{entry.entry_type}' failed verification:")
print(" ❌ Invariant Violations:")
for issue in violations:
print(f" - {issue}")
print(f" ❌ {issue}")

print(f"\n\nFound {total_number_of_violations} invariant violation(s) in {len(entries)} entries.")

Expand Down
10 changes: 5 additions & 5 deletions bibtex_linter/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def check_required_fields(entry: BibTeXEntry, fields: Set[str]) -> List[str]:
existing_fields: Set[str] = set(entry.fields.keys())
if not fields.issubset(entry.fields):
missing = fields - existing_fields
return [f"Entry '{entry.name}' misses the following required fields: [{', '.join(sorted(missing))}]"]
return [f"Misses the following required fields: [{', '.join(sorted(missing))}]"]
return []


Expand All @@ -49,7 +49,7 @@ def check_required_field(entry: BibTeXEntry, field: str, explanation: str) -> Li
out the required field.
"""
if field not in entry.fields.keys():
return [f"Entry '{entry.name}' misses required field [{field}]. {explanation}"]
return [f"Misses required field [{field}]. {explanation}"]
return []


Expand All @@ -61,7 +61,7 @@ def check_omitted_fields(entry: BibTeXEntry, fields: Set[str]) -> List[str]:
omitted_fields_present = fields & existing_fields

if omitted_fields_present:
return [f"Entry '{entry.name}' has fields present that would be omitted in the compiled document: "
return ["Has fields present that would be omitted in the compiled document: "
f"[{', '.join(sorted(omitted_fields_present))}]. This could lead to a loss of information."]
return []

Expand All @@ -74,7 +74,7 @@ def check_disallowed_fields(entry: BibTeXEntry, fields: Set[str]) -> List[str]:
disallowed_fields_present = fields & existing_fields

if disallowed_fields_present:
return [f"Entry '{entry.name}' has fields present that would be omitted in the compiled document: "
return ["Has fields present that would be omitted in the compiled document: "
f"[{', '.join(sorted(disallowed_fields_present))}]."]
return []

Expand All @@ -86,7 +86,7 @@ def check_disallowed_field(entry: BibTeXEntry, field: str, explanation: str) ->
why it is disallowed.
"""
if field in entry.fields.keys():
return [f"Entry '{entry.name}' contains disallowed field [{field}]. {explanation}"]
return [f"Contains disallowed field [{field}]. {explanation}"]
return []


Expand Down
8 changes: 4 additions & 4 deletions test/test_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_check_required_fields_missing(self) -> None:
name="missing_fields",
fields={"author": "Jane"}
)
expected = ["Entry 'missing_fields' misses the following required fields: [howpublished, title, year]"]
expected = ["Misses the following required fields: [howpublished, title, year]"]
actual = check_required_fields(entry, {"author", "title", "howpublished", "year"})
self.assertEqual(expected, actual)

Expand All @@ -41,7 +41,7 @@ def test_check_omitted_fields_present(self) -> None:
fields={"author": "Jane", "language": "en", "url": "example.com"}
)
expected = [
"Entry 'omit_test' has fields present that would be omitted in the compiled document: "
"Has fields present that would be omitted in the compiled document: "
"[language, url]. This could lead to a loss of information."
]
actual = check_omitted_fields(entry, {"language", "organization", "address", "pages", "url"})
Expand All @@ -62,8 +62,8 @@ def test_verify_combined_rule(self) -> None:
fields={"author": "Jane", "url": "http://example.org"}
)
expected = [
"Entry 'bad_entry' misses the following required fields: [howpublished, title, year]",
"Entry 'bad_entry' has fields present that would be omitted in the compiled document: [url]. "
"Misses the following required fields: [howpublished, title, year]",
"Has fields present that would be omitted in the compiled document: [url]. "
"This could lead to a loss of information."
]
actual = verify(entry)
Expand Down
Loading