scoop-latex-packer
scoop-latex-packer takes a top-level .tex file, resolves its dependencies, and packs them into a .zip suitable for submission to a publisher or to arXiv.
It also validates the resulting archive by re-compiling it in a sterile environment, so you find out before submission whether anything is missing.
Installation
pip install scoop-latex-packer
This installs the slp command (with scoop-latex-packer available as a longer-form alias). The examples below use slp.
Requirements
- Python 3.11 or newer.
latexmkandkpsewhichonPATH. Both ship with every standard TeX distribution (TeX Live, MiKTeX, MacTeX).
Usage
The CLI has three subcommands: pack builds a submission archive, analyze prints what pack would include without writing the archive, and validate verifies that an archive compiles in isolation.
Run slp with no arguments to see the top-level help.
The top-level .tex file argument to pack is optional: if you omit it, slp looks for a unique .tex file containing \documentclass in the current directory and uses that.
With several top-level files in one directory, the top-level config key (see below) saves naming the file on every call.
If the argument carries a directory component (e.g. papers/preprint.tex or /abs/path/preprint.tex), slp changes into that directory before packing, so all output files — including the resulting .zip — land beside the source.
# Pack the only top-level .tex file in the current directory.
slp pack
# Pack a specific top-level .tex file.
slp pack preprint.tex
# Pack a paper that lives in another directory — slp changes
# into that directory first, so the resulting .zip lands beside the source.
slp pack papers/preprint.tex
slp pack ~/Work/papers/preprint.tex
# Pack for arXiv submission (currently the same as --freeze-minted).
slp pack --arxiv preprint.tex
# Include extra data files that the recorder doesn't detect (repeat for multiple).
slp pack --extra-file data/run1.csv --extra-file data/run2.csv preprint.tex
# Show what pack would include in the archive without actually writing it.
# Accepts the same flags as `pack` (e.g. --arxiv to preview the prepends).
slp analyze preprint.tex
slp analyze --arxiv preprint.tex
# Verify that the resulting archive compiles with no help from your local
# TEXINPUTS/BIBINPUTS/BSTINPUTS environment.
slp validate preprint.zip
# Keep the extraction directory around for poking at after a failure.
slp validate --keep-tmpdir preprint.zip
slp <subcommand> --help (or scoop-latex-packer <subcommand> --help) lists every option for that subcommand.
Project-local config
A slp.toml file next to the top-level .tex is auto-loaded; CLI flags always win over config values, which in turn win over the built-in defaults.
pack and analyze share the [pack] section; validate reads [validate].
[pack]
top-level = "preprint.tex"
arxiv = true
extra-files = ["data/run1.csv", "data/run2.csv"]
[validate]
no-open = true
You can keep several configs side-by-side in the same directory (arxiv.toml, journal-x.toml, …) and pick one with -c / --config:
slp pack -c arxiv.toml preprint.tex
slp pack -c journal-x.toml preprint.tex
Config keys mirror the CLI flag names with hyphens (e.g. freeze-minted = true); top-level stands in for the positional argument and must be a bare filename next to the config file; the lone exception to the mirroring is include-bibfiles = false, the positive form of --exclude-bibfiles.
Unknown keys produce a warning so typos surface immediately.
A reference examples/slp.toml ships in the development repository (not in the PyPI wheel) with every supported key set to its default value — copy it as a starting point.
Features
- Works with
bibtexandbiber/biblatexbibliographies. - Auto-detects the top-level
.texfile from the presence of\documentclass. - Finds dependent files on
TEXINPUTS,BIBINPUTS, andBSTINPUTS. - Ships bibliography sources (
.bib/.bst) by default and drops the generated.bbl(as well as.toc/.lof/.lot); the recipient regenerates them. This avoids the arXiv TeX Live 2025.bblversion-mismatch error, and matches arXiv's current recommendation to upload.bibfiles. A publisher that wants the.bblanyway gets it via--extra-file preprint.bbl. --freeze-mintedmakes the archive compile without--shell-escape, which arXiv disables, by prepending\PassOptionsToPackage{frozencache}{minted}to the top-level file and shipping themintedcache.--arxivis currently an alias for--freeze-minted; see minted and arXiv below.validatere-compiles the archive in an isolated temp directory with theTEXINPUTS/BIBINPUTS/BSTINPUTSvariables stripped, catching missing dependencies before you submit.
minted and arXiv
arXiv compiles without --shell-escape, so minted must read every snippet from a cache shipped inside the archive.
How that cache is produced depends on the minted version, which slp detects via kpsewhich minted.sty:
minted |
Discovery run | Cache shipped | Top-level prepend |
|---|---|---|---|
| v2 | with \PassOptionsToPackage{finalizecache}{minted} injected via latexmk -usepretex |
_minted-<jobname>/ with listingN.pygtex files |
frozencache |
| v3 | plain --shell-escape run |
_minted/ with content-addressed *.highlight.minted files |
frozencache |
The minted cache files are picked up like any other dependency, through the latexmk -recorder file, so no special handling is needed to include them.
arXiv's default TeX Live 2025 compiler uses minted v3, while its optional TeX Live 2023 compiler uses minted v2.9.
A v2 cache is useless to minted v3 and vice versa, so pack under the TeX Live generation you will select at arXiv, e.g. in a texlive/texlive:TL2025-historic container.
Limitations
- Files included via relative paths outside the current directory (e.g.
\includegraphics{../somedir/result.pdf}) cannot be packed: the archive layout assumes everything lives at or below the project root.pack(andanalyze) detect these and abort with a non-zero exit and a message naming every offending file, rather than silently producing a broken archive. Move such files under the project directory (and update the reference in your.tex) before packing. - A bibliography resource named with a subdirectory (e.g.
\addbibresource{shared/refs.bib}) that lives outside the project — found through an absoluteBIBINPUTS/BSTINPUTSsearch path — is packed under its bare filename at the archive root, so theshared/part of the reference no longer resolves. Keep such resources under the project directory.validatecatches this case by failing the sterile recompile.
Development
The development repository lives at https://gitlab.com/scoopgroup-public/scoop-latex-packer and contains a tests/ directory with sample .tex and .bib fixtures.
The tests/ directory is excluded from the PyPI wheel and sdist, so end users never see it.
git clone https://gitlab.com/scoopgroup-public/scoop-latex-packer
cd scoop-latex-packer
python -m venv .venv && source .venv/bin/activate
pip install -e .
# Now run pack/validate against the fixtures in tests/.
License
MIT — see LICENSE.
Metadata
Release files for scoop-latex-packer 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| scoop_latex_packer-0.1.3.tar.gz | 28.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| scoop_latex_packer-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.9 kB
Release files / scoop_latex_packer-0.1.3.tar.gz
| Download URL | scoop_latex_packer-0.1.3.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
817ce8d51bbe4feb0f28f2b40549854c769992511c0ca1e7dbbe36a4c6dc1390
|
|
BLAKE2b-256 checksum How to use checksums |
d89ff587862c2b843602cec5a3e16b34ac63a6560b97d8d2676da3faa8f0f21c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / scoop_latex_packer-0.1.3-py3-none-any.whl
| Download URL | scoop_latex_packer-0.1.3-py3-none-any.whl |
|---|---|
| Size | 29.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44c3ecb385e5971478e760dffbf5f50c84c3b36fd6d471c0d78e68d9361418c5
|
|
BLAKE2b-256 checksum How to use checksums |
ddd846e914698f4c05655fa9608938db5abb0aefb6a2dc5185833854d207e59b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|