diff --git a/conjurer_librarian/conjurer_librarian.py b/conjurer_librarian/conjurer_librarian.py index 0b2c666..7dc7f79 100644 --- a/conjurer_librarian/conjurer_librarian.py +++ b/conjurer_librarian/conjurer_librarian.py @@ -212,6 +212,9 @@ class Librarian(object): - search_result_from_cr: A dictionary to store the search results from Crossref. - done: A flag indicating if the search is done. """ + # Crossref only needs a contact mailto. It can come from + # CONJURER_CROSSREF_MAILTO (the usual container setup) OR from a + # "crossref" entry in the netrc; netrc takes precedence when present. mailto_contact: Optional[str] = os.getenv("CONJURER_CROSSREF_MAILTO") if netrc: try: @@ -219,10 +222,22 @@ class Librarian(object): auth_tokens = netrc_mod.authenticators("crossref") if auth_tokens: mailto_contact = auth_tokens[0] - except (FileNotFoundError, netrc.NetrcParseError): - logging.getLogger("conjurer_librarian").warning( - "Crossref credentials missing in netrc %s", NETRC_FILE - ) + except (FileNotFoundError, netrc.NetrcParseError) as exc: + # A missing/unreadable netrc is NORMAL when the mailto is set via + # env - don't cry wolf on every single search. Only warn when we + # genuinely have no contact from either source. + _log = logging.getLogger("conjurer_librarian") + if mailto_contact: + _log.debug( + "netrc %s not used (%s) - using CONJURER_CROSSREF_MAILTO", + NETRC_FILE, exc, + ) + else: + _log.warning( + "Crossref contact not configured: netrc %s unreadable (%s) " + "and CONJURER_CROSSREF_MAILTO unset", + NETRC_FILE, exc, + ) if not mailto_contact: raise RuntimeError( "Crossref credentials not configured. Set CONJURER_CROSSREF_MAILTO or add to netrc." diff --git a/tests/integration/test_librarian_crossref_config.py b/tests/integration/test_librarian_crossref_config.py new file mode 100644 index 0000000..cc588f8 --- /dev/null +++ b/tests/integration/test_librarian_crossref_config.py @@ -0,0 +1,52 @@ +"""Integration: the librarian's Crossref-contact resolution. + +CONJURER_CROSSREF_MAILTO alone is a valid, complete configuration. A missing +netrc must NOT produce a "credentials missing" warning in that case - the old +code warned on every single search even though the env var was set and used. +Only a genuine absence of any contact should warn (and then raise). +""" +import logging +import sys +import types + +import pytest + +if "habanero" not in sys.modules: + _habanero = types.ModuleType("habanero") + _habanero.Crossref = object + sys.modules["habanero"] = _habanero + +import conjurer_librarian as lib # noqa: E402 + + +class _DummyCrossref: + """Accepts the kwargs the real Crossref does, so Librarian() can construct.""" + + def __init__(self, **kwargs): + self.kwargs = kwargs + + +@pytest.fixture(autouse=True) +def _crossref_and_missing_netrc(monkeypatch): + # Build with a harmless Crossref, and force the netrc read to miss so the + # env-var path is what's exercised. + monkeypatch.setattr(lib, "Crossref", _DummyCrossref) + monkeypatch.setattr(lib, "NETRC_FILE", "/nonexistent/conjurer/.netrc") + + +def test_env_mailto_alone_does_not_warn(monkeypatch, caplog): + monkeypatch.setenv("CONJURER_CROSSREF_MAILTO", "mtuszowski@example.com") + with caplog.at_level(logging.WARNING, logger="conjurer_librarian"): + librarian = lib.Librarian(lib.app, "kwas foliowy", "uuid-1", False) + assert librarian.uuid == "uuid-1" # constructed fine + assert not any( + "credentials missing" in r.getMessage().lower() + or "not configured" in r.getMessage().lower() + for r in caplog.records + ), "a missing netrc must not warn when CONJURER_CROSSREF_MAILTO is set" + + +def test_no_contact_anywhere_raises(monkeypatch): + monkeypatch.delenv("CONJURER_CROSSREF_MAILTO", raising=False) + with pytest.raises(RuntimeError): + lib.Librarian(lib.app, "kwas foliowy", "uuid-2", False)