acl-api / tests /sync /test_anthology_source.py
ivykopal's picture
feat: add pdf_url field to paper metadata and update related functionality
cbd62a3
Raw
History Blame Contribute Delete
5.53 kB
from unittest.mock import MagicMock
from sync.anthology_source import iter_papers
def _make_fake_paper(full_id, title, abstract, authors, venue, year, url, bibtex="", pdf_url=""):
parent = MagicMock()
parent.venue_acronym = venue
pdf = MagicMock()
pdf.url = pdf_url
paper = MagicMock()
paper.full_id = full_id
paper.parent = parent
paper.title = title
paper.abstract = abstract
paper.authors = authors
paper.year = year
paper.web_url = url
paper.to_bibtex.return_value = bibtex
paper.pdf = pdf
return paper
class FakeMarkupText:
"""Stand-in for acl_anthology.text.MarkupText, which exposes .as_text()."""
def __init__(self, text):
self._text = text
def as_text(self):
return self._text
class FakeName:
"""Stand-in for acl_anthology.people.Name, exposing .as_first_last()."""
def __init__(self, first, last):
self.first = first
self.last = last
def as_first_last(self):
if not self.first:
return self.last
return f"{self.first} {self.last}"
class FakeNameSpecification:
"""Stand-in for acl_anthology.people.NameSpecification, exposing .name."""
def __init__(self, name):
self.name = name
def test_iter_papers_maps_fields(monkeypatch):
fake_anthology = MagicMock()
fake_anthology.papers.return_value = [
_make_fake_paper("2023.acl-long.1", "Title One", "Abstract one", ["Alice", "Bob"], "ACL", "2023", "http://x/p1", "@inproceedings{one,\n title = \"Title One\"}", "http://x/p1.pdf"),
_make_fake_paper("2022.emnlp-main.2", "Title Two", None, [], "EMNLP", "2022", "http://x/p2"),
]
monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)
results = list(iter_papers("/fake/repo"))
assert results[0] == {
"id": "2023.acl-long.1", "title": "Title One", "abstract": "Abstract one",
"authors": "Alice, Bob", "venue": "ACL", "year": 2023, "url": "http://x/p1",
"bibtex": "@inproceedings{one,\n title = \"Title One\"}", "pdf_url": "http://x/p1.pdf",
}
assert results[1]["abstract"] == ""
assert results[1]["authors"] == ""
assert results[1]["year"] == 2022
assert results[1]["bibtex"] == ""
assert results[1]["pdf_url"] == ""
def test_iter_papers_handles_real_markup_text_and_name_objects(monkeypatch):
"""The real acl_anthology package (verified against installed 1.2.0) has
Paper.title/abstract as MarkupText objects (.as_text()) and Paper.authors
as a tuple of NameSpecification objects exposing `.name.as_first_last()`.
"""
fake_anthology = MagicMock()
fake_anthology.papers.return_value = [
_make_fake_paper(
"2024.naacl-long.3",
FakeMarkupText("Real Title"),
FakeMarkupText("Real abstract text"),
[FakeNameSpecification(FakeName("Alice", "Smith")), FakeNameSpecification(FakeName(None, "Cher"))],
"NAACL",
"2024",
"http://x/p3",
"@inproceedings{smith-2024-real}",
"http://x/p3.pdf",
),
]
monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)
results = list(iter_papers("/fake/repo"))
assert results[0] == {
"id": "2024.naacl-long.3", "title": "Real Title", "abstract": "Real abstract text",
"authors": "Alice Smith, Cher", "venue": "NAACL", "year": 2024, "url": "http://x/p3",
"bibtex": "@inproceedings{smith-2024-real}", "pdf_url": "http://x/p3.pdf",
}
def test_iter_papers_uses_datadir_subdirectory_of_local_checkout(monkeypatch):
"""anthology_path is the root of a git clone; the library expects the
nested data/ directory, not the checkout root itself, and must not
treat anthology_path as a repo URL to re-clone."""
captured = {}
def fake_anthology_ctor(datadir):
captured["datadir"] = datadir
anthology = MagicMock()
anthology.papers.return_value = []
return anthology
monkeypatch.setattr("sync.anthology_source.Anthology", fake_anthology_ctor)
list(iter_papers("/fake/checkout"))
assert captured["datadir"] == "/fake/checkout/data"
def test_iter_papers_bibtex_falls_back_on_error(monkeypatch):
"""Papers whose bibkey is NO_BIBKEY (e.g. some frontmatter) raise
ValueError from to_bibtex(); the sync must yield bibtex="" for those
rather than crash."""
fake_anthology = MagicMock()
paper = _make_fake_paper("2023.acl-frontmatter.1", "Preface", "", [], "ACL", "2023", "http://x/pf")
paper.to_bibtex.side_effect = ValueError("Cannot generate BibTeX entry without bibkey")
fake_anthology.papers.return_value = [paper]
monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)
results = list(iter_papers("/fake/repo"))
assert results[0]["bibtex"] == ""
def test_iter_papers_pdf_url_falls_back_when_no_pdf(monkeypatch):
"""Frontmatter and some older papers have no PDF reference (Paper.pdf is
None); the sync must yield pdf_url="" for those rather than crash."""
fake_anthology = MagicMock()
paper = _make_fake_paper("2023.acl-frontmatter.1", "Preface", "", [], "ACL", "2023", "http://x/pf")
paper.pdf = None
fake_anthology.papers.return_value = [paper]
monkeypatch.setattr("sync.anthology_source.Anthology", lambda datadir: fake_anthology)
results = list(iter_papers("/fake/repo"))
assert results[0]["pdf_url"] == ""