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
23 changes: 22 additions & 1 deletion tests/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import textwrap
from dataclasses import dataclass

from wenxian.reference import Author, Reference
from wenxian.reference import Author, BibtexType, Reference


@dataclass
Expand Down Expand Up @@ -453,4 +453,25 @@ class ReferenceCase:
applications in drug development and beyond.},
}""").strip(),
),
# chapter
ReferenceCase(
reference=Reference(
author=[Author(first="James Patton", last="Jones")],
title="PBS: Portable Batch System",
year=2001,
pages=(369, 390),
doi="10.7551/mitpress/1556.003.0021",
journal="Beowulf Cluster Computing with Linux",
type=BibtexType.inbook,
),
expected_bibtex=textwrap.dedent(r"""
@Inbook{Jones_BeowulfClustComputLinux_2001_p369,
author = {James Patton Jones},
title = {{PBS: Portable Batch System}},
year = 2001,
pages = {369--390},
doi = {10.7551/mitpress/1556.003.0021},
booktitle ={Beowulf Cluster Computing with Linux},
}""").strip(),
),
]
45 changes: 44 additions & 1 deletion wenxian/feeder/crossref.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from wenxian.feeder.feeder import Feeder
from wenxian.feeder.session import SESSION
from wenxian.reference import Author, Reference
from wenxian.reference import Author, BibtexType, Reference


class Crossref(Feeder):
Expand Down Expand Up @@ -64,8 +64,50 @@ def from_doi(self, doi: str) -> Reference | None:
# while not documented, the journal might be HTML escaped, e.g., Journal of Materials Science & Technology
# https://api.crossref.org/works/10.1016/j.jmst.2023.09.059
journal = html.unescape(journal)
elif m.get("container-title"):
journal = m["container-title"][0]
journal = html.unescape(journal)
else:
journal = None
# journal-article
# journal-issue
# journal-volume
# journal
# proceedings-article
# proceedings
# dataset
# component
# report
# report-series
# standard
# standard-series
# edited-book
# monograph
# reference-book
# book
# book-series
# book-set
# book-chapter
# book-section
# book-part
# book-track
# reference-entry
# dissertation
# posted-content
# peer-review
# other
cr_type = m.get("type")
if cr_type in (
"book-series",
"book-set",
"book-chapter",
"book-section",
"book-part",
"book-track",
):
ref_type = BibtexType.inbook
else:
ref_type = BibtexType.article
return Reference(
author=author,
title=title,
Expand All @@ -76,4 +118,5 @@ def from_doi(self, doi: str) -> Reference | None:
pages=self._pages(page),
annote=abstract,
doi=doi,
type=ref_type,
)
28 changes: 27 additions & 1 deletion wenxian/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re
import textwrap
from dataclasses import dataclass
from enum import IntEnum

import unidecode
from pyiso4.ltwa import Abbreviate
Expand Down Expand Up @@ -52,6 +53,25 @@ def __str__(self) -> str:
return f"{self.first} {self.last}"


class BibtexType(IntEnum):
"""BibTeX entry types."""

article = 0
book = 1
booklet = 2
conference = 3
inbook = 4
incollection = 5
inproceedings = 6
manual = 7
mastersthesis = 8
misc = 9
phdthesis = 10
proceedings = 11
techreport = 12
unpublished = 13


@dataclass
class Reference:
"""A reference to a scholarly article."""
Expand All @@ -65,6 +85,7 @@ class Reference:
pages: tuple[int] | tuple[int, int] | str | None = None
annote: str | None = None
doi: str | None = None
type: BibtexType = BibtexType.article

@property
def journal_abbr(self) -> str | None:
Expand Down Expand Up @@ -153,7 +174,11 @@ def bibtex(self) -> str:
"doi": self.doi,
"abstract": self.annote,
}
start = f"@Article{{{self.key},"
if self.type in (BibtexType.inbook,):
data.pop("journal")
# usually book title should not use abbr
data["booktitle"] = self.journal
start = f"@{self.type.name.capitalize()}{{{self.key},"
end = "}\n"
items = [start]
for key, value in data.items():
Expand Down Expand Up @@ -202,6 +227,7 @@ def __or__(self, other: Reference | None) -> Reference:
pages=self.pages or other.pages,
annote=self.annote or other.annote,
doi=self.doi or other.doi,
type=self.type or other.type,
)

def is_empty(self) -> bool:
Expand Down