A minimalist Python CLI tool for compiling LaTeX files to PDF with structured error reporting. This tool acts as a "core compilation brain" that can be embedded into larger systems (IDEs, web backends, pipelines, etc.).
- Multiple engine support: Works with Tectonic and LaTeXmk
- Structured error reporting: Extracts meaningful diagnostics from LaTeX compilation logs
- Fix recommendations: Provides actionable suggestions for common LaTeX errors
- JSON output: Machine-readable output for programmatic consumption
- Timeout protection: Prevents compilation from hanging indefinitely
- Clean API: Simple programmatic interface for integration into other tools
This tool requires one of the following LaTeX engines to be installed and available in your PATH:
-
Tectonic (preferred): Modern, self-contained LaTeX engine
- Installation:
cargo install tectonicor download from tectonic-typesetting.github.io
- Installation:
-
LaTeXmk (alternative): Traditional LaTeX build tool (requires TeX Live or MiKTeX)
- Installation: Usually included with TeX Live distributions
- macOS:
brew install --cask mactexorbrew install basictex - Linux:
sudo apt-get install texlive-latex-base latexmk
- Python 3.10 or higher
- See
requirements.txtfor Python dependencies
-
Clone this repository:
git clone <repository-url> cd tex2pdf
python3 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
python3 -m pip install --upgrade pip
python3 -m pip install .python3 -m venv .venv
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
python -m pip install -e .
python -m pip install -r requirements-dev.txtOptional: Install exactly the pinned runtime dependencies (not needed if you already ran pip install .):
python -m pip install -r requirements.txttex2pdf INPUT_FILE.tex [OPTIONS]Bare filenames are resolved under the input/ folder by default.
--outdir,-o PATH: Output directory for generated files (default:./output)--engine,-e {tectonic,latexmk}: LaTeX engine to use (default: auto-detect)--json: Output result as JSON for machine consumption--timeout,-t SECONDS: Maximum compilation time in seconds (default: 120)--help: Show help message
# Compile a LaTeX file using the default engine (from input/)
tex2pdf document.tex
# Compile the example document in the input folder
tex2pdf latex_literature_review.tex
# Specify output directory
tex2pdf document.tex --outdir=./output
# Use a specific engine
tex2pdf document.tex --engine=latexmk# 1) Compile the example LaTeX document from input/
tex2pdf latex_literature_review.tex
# 2) Open the result at:
# output/latex_literature_review.pdf# Get machine-readable output
tex2pdf document.tex --jsonThe JSON output includes:
success: Boolean indicating compilation successpdf_path: Path to generated PDF (if successful)log: Full compilation logdiagnostics: Array of diagnostic objects with error codes, messages, and fix recommendationsengine: Engine used for compilationreturn_code: Exit code from the LaTeX engine
# Set a 60-second timeout
tex2pdf document.tex --timeout=60You can also use tex2pdf as a Python library:
from pathlib import Path
from tex2pdf import compile_tex, EngineConfig
# Compile a LaTeX file
result = compile_tex(
tex_path=Path("document.tex"),
outdir=Path("./output"),
engine=EngineConfig(name="tectonic"),
timeout=120
)
if result.success:
print(f"PDF generated at: {result.pdf_path}")
else:
print("Compilation failed!")
for diagnostic in result.diagnostics:
print(f"{diagnostic.level}: {diagnostic.message}")The tool provides structured diagnostics for common LaTeX errors:
Detects undefined LaTeX commands:
ERROR [undefined-control-sequence]: Undefined control sequence '\foo'.
Check for typos or missing `\usepackage`/`\newcommand`.
Identifies missing .sty files:
ERROR [missing-package]: Missing package file 'missingpackage.sty'.
Install the appropriate LaTeX package or adjust your preamble.
Detects unclosed braces or environments:
ERROR [runaway-argument]: Runaway argument.
Likely an unclosed brace or environment; check for missing '}' or \end{...} above.
Fallback for other LaTeX errors:
ERROR [latex-error]: LaTeX reported an error. See raw for details.
0: Compilation succeeded, PDF produced1: CLI error (invalid arguments, missing file, engine not found)2: Compilation failed (but CLI behaved correctly)
The tool currently detects:
- Undefined control sequences: Missing commands or packages
- Missing packages:
.styfiles not found - Runaway arguments: Unclosed braces or environments
- Generic LaTeX errors: Other compilation errors (via
!markers)
The diagnostic system is extensible - new error patterns can be easily added by extending the rule engine in tex2pdf/analysis.py.
tex2pdf/
├── pyproject.toml # Package configuration
├── requirements.txt # Runtime dependencies
├── requirements-dev.txt # Development dependencies
├── input/
│ └── latex_literature_review.tex # Example input document
├── output/ # Default output directory
├── src/
│ └── tex2pdf/
│ ├── __init__.py # Package exports
│ ├── models.py # Data models (CompileResult, Diagnostic, EngineConfig)
│ ├── analysis.py # Log analysis with regex-based rule engine
│ ├── core.py # Core compilation logic
│ └── cli.py # Typer-based CLI interface
└── tests/
├── test_analysis.py # Tests for log analysis
└── test_core.py # Tests for core compilation (with mocking)
# Run all tests
pytest
# Run with coverage
pytest --cov=tex2pdf
# Run with verbose output
pytest -vTo add support for new error patterns, extend the LogAnalyzer class in tex2pdf/analysis.py:
def _handle_new_error_type(self, match: re.Match[str]) -> list[Diagnostic]:
"""Handle a new type of LaTeX error."""
raw = match.group(0)
return [
Diagnostic(
level="error",
code="new-error-code",
message="Descriptive message with fix recommendation",
raw=raw.strip(),
)
]
# Register the rule
analyzer.add_rule(
re.compile(r"Your error pattern here", re.MULTILINE),
analyzer._handle_new_error_type,
)To add support for a new LaTeX engine:
- Add a new
_run_engine_name()function intex2pdf/core.py - Update the
compile_tex()function to handle the new engine - Add the engine name to
EngineConfigtype hints
This tool is intentionally minimal and focused on core compilation:
- Not an editor: No syntax highlighting or editing features
- No project management: Single-file compilation only (no multi-file project support)
- No watch mode: Does not monitor files for changes
- No cloud features: Local compilation only
This design makes it ideal for embedding into larger systems where these features are provided by the host application.
MIT License
Contributions are welcome! Please ensure:
- All tests pass (
pytest) - Code follows type hints and includes docstrings
- New features include appropriate tests