fix(arxiv): handle legacy single-file gzipped source (no tar wrapper)

Old arXiv submissions (e.g. legacy math/* papers) are served as a bare gzipped .tex rather than a .tar.gz, which tarfile.open rejected with 'invalid header'. Fall back to gunzipping the body directly when the tar parse fails, so R-C covers those papers too (recovers math/0001176 + math/0306167). Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-18 04:18:18 +02:00
parent 1da81c7b28
commit 121b582f46
2 changed files with 36 additions and 4 deletions

View File

@@ -8,6 +8,7 @@ Provides:
from __future__ import annotations
import gzip
import io
import logging
import tarfile
@@ -157,12 +158,19 @@ def fetch_source(arxiv_id: str) -> str | None:
# Inline \input/\include so multi-file projects yield the full body,
# not just the primary file's skeleton of include directives (R-C).
return flatten_inputs(files[primary_name], files)
except tarfile.TarError as exc:
logger.warning("Failed to open tar archive for %s: %s", arxiv_id, exc)
except tarfile.TarError:
# Old arXiv submissions are served as a single bare gzipped .tex with no
# tar wrapper (e.g. legacy math/* papers) — gunzip the body directly.
try:
single = gzip.decompress(raw).decode("utf-8", errors="replace")
except (OSError, EOFError) as exc:
logger.warning("Failed to read arXiv source for %s: %s", arxiv_id, exc)
return None
if "\\" in single[:5000]: # looks like LaTeX (has backslash commands)
return single
logger.debug("arXiv source for %s is not LaTeX", arxiv_id)
return None
return None # unreachable but satisfies type checker
def fetch_pdf_url(arxiv_id: str) -> str:
"""Return the canonical PDF URL for an arXiv paper.