A comprehensive Python library for programmatically creating and compiling LaTeX documents and snippets.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Utility functions for LaTeX escaping, file handling, and string manipulation to support document generation workflows. PyLaTeX provides essential utilities for handling special characters, file paths, text formatting, and temporary file management to ensure robust document generation.
Control how special characters are handled when converting Python strings to LaTeX.
class NoEscape(str):
"""
String class that bypasses LaTeX character escaping.
When NoEscape strings are combined:
- NoEscape + NoEscape → NoEscape
- NoEscape + str → str (regular string)
Parameters:
- string: str, content that should not be escaped
"""
def escape_latex(s):
"""
Escape special LaTeX characters in a string.
Parameters:
- s: str, NoEscape, or convertible to string, input to escape
Returns:
- NoEscape: escaped string safe for LaTeX
Special characters handled:
- & → \\&
- % → \\%
- $ → \\$
- # → \\#
- _ → \\_
- { → \\{
- } → \\}
- ~ → \\textasciitilde{}
- ^ → \\^{}
- \\ → \\textbackslash{}
- newline → \\newline%
- - → {-}
- [ → {[}
- ] → {]}
"""Usage example:
from pylatex import Document, Section
from pylatex.utils import NoEscape, escape_latex
doc = Document()
with doc.create(Section('Text Handling')):
# Automatic escaping (default behavior)
unsafe_text = "Cost: $100, efficiency: 95% (issue #42)"
doc.append(escape_latex(unsafe_text))
# Produces: Cost: \$100, efficiency: 95\% (issue \#42)
# Skip escaping with NoEscape
latex_command = NoEscape(r'\textbf{Important}')
doc.append(latex_command)
# Produces: \textbf{Important}
# Mixed content
doc.append('Regular text with ')
doc.append(NoEscape(r'\emph{emphasized}'))
doc.append(' and special chars: ')
doc.append(escape_latex('R&D costs ~$50K'))Utilities for managing file paths in LaTeX-compatible formats.
def fix_filename(path):
"""
Fix file paths for LaTeX compatibility.
Handles issues with:
- Multiple dots in filenames
- Special characters in paths
- Platform-specific path separators
- Tilde characters (~) in paths
Parameters:
- path: str, file path to fix
Returns:
- str: LaTeX-compatible file path
Examples:
- 'foo.bar.pdf' → '{foo.bar}.pdf'
- '/path/file~name.pdf' → '\\detokenize{/path/file~name.pdf}'
"""Usage example:
from pylatex import Document, Section
from pylatex.figure import Figure
from pylatex.utils import fix_filename
doc = Document()
with doc.create(Section('File Examples')):
# Problematic filenames
problematic_files = [
'data.analysis.results.png',
'user~documents/report.pdf',
'file with spaces & symbols.jpg'
]
for filename in problematic_files:
safe_filename = fix_filename(filename)
with doc.create(Figure()) as fig:
fig.add_image(safe_filename)
fig.add_caption(f'Fixed filename: {safe_filename}')
# Cross-platform path handling
import os
from pylatex.utils import fix_filename
if os.name == 'posix':
# Unix/Linux/Mac paths
image_path = '/home/user/data.set.1/results.png'
else:
# Windows paths
image_path = r'C:\Users\Name\data.set.1\results.png'
safe_path = fix_filename(image_path)Convert Python lists and collections to LaTeX-formatted strings.
def dumps_list(l, *, escape=True, token="%\n", mapper=None, as_content=True):
"""
Convert a list to LaTeX string representation.
Parameters:
- l: list, collection to convert
- escape: bool, whether to escape special LaTeX characters
- token: str, separator between list items (default: newline)
- mapper: callable or list, functions to apply to each item
- as_content: bool, use dumps_as_content() for LatexObjects
Returns:
- NoEscape: formatted LaTeX string
"""Usage example:
from pylatex import Document, Section, Command
from pylatex.utils import dumps_list, bold, italic
doc = Document()
with doc.create(Section('List Processing')):
# Basic list conversion
items = ['First item', 'Second item', 'Third item']
formatted_list = dumps_list(items)
doc.append(formatted_list)
# With custom separator
inline_items = ['alpha', 'beta', 'gamma']
inline_list = dumps_list(inline_items, token=', ')
doc.append('Greek letters: ')
doc.append(inline_list)
# With escaping for special characters
special_items = ['Cost: $100', 'Efficiency: 95%', 'Issue #42']
safe_list = dumps_list(special_items, escape=True)
doc.append(safe_list)
# With formatting mapper
emphasis_items = ['Important', 'Critical', 'Urgent']
emphasized = dumps_list(emphasis_items, mapper=bold)
doc.append(emphasized)
# Multiple mappers
styled_items = ['Note 1', 'Note 2', 'Note 3']
styled_list = dumps_list(styled_items, mapper=[bold, italic])
doc.append(styled_list)Convenience functions for common text formatting operations.
def bold(s, *, escape=True):
"""
Format text as bold using \\textbf{}.
Parameters:
- s: str, text to make bold
- escape: bool, whether to escape special characters
Returns:
- NoEscape: bold-formatted LaTeX string
"""
def italic(s, *, escape=True):
"""
Format text as italic using \\textit{}.
Parameters:
- s: str, text to make italic
- escape: bool, whether to escape special characters
Returns:
- NoEscape: italic-formatted LaTeX string
"""
def verbatim(s, *, delimiter="|"):
"""
Format text as verbatim using \\verb.
Parameters:
- s: str, text to format verbatim
- delimiter: str, delimiter character (default: |)
Returns:
- NoEscape: verbatim-formatted LaTeX string
"""Usage example:
from pylatex import Document, Section
from pylatex.utils import bold, italic, verbatim
doc = Document()
with doc.create(Section('Text Formatting')):
# Basic formatting
doc.append(bold('Important notice'))
doc.append(' and ')
doc.append(italic('emphasized text'))
# With automatic escaping
doc.append(bold('Cost: $1,000 (50% discount)', escape=True))
# Verbatim code
doc.append('Use the command ')
doc.append(verbatim(r'\renewcommand{\baselinestretch}{1.5}'))
doc.append(' to change line spacing.')
# Custom verbatim delimiter
doc.append('The expression ')
doc.append(verbatim('x|y', delimiter='!'))
doc.append(' uses a pipe character.')
# Nested formatting
complex_text = bold('Warning: ') + italic('System may be unstable')
doc.append(complex_text)Utilities for managing temporary files during document generation.
def make_temp_dir():
"""
Create a temporary directory for document processing.
Returns:
- str: absolute path to temporary directory
Note: Directory persists until rm_temp_dir() is called or program exits
"""
def rm_temp_dir():
"""
Remove the temporary directory created by make_temp_dir().
Cleans up all temporary files and directories created during processing.
"""Usage example:
import os
from pylatex import Document
from pylatex.figure import Figure
from pylatex.utils import make_temp_dir, rm_temp_dir
import matplotlib.pyplot as plt
doc = Document()
# Create temporary directory for plots
temp_dir = make_temp_dir()
try:
# Generate and save plots to temp directory
plt.figure(figsize=(8, 6))
plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
plt.title('Sample Plot')
plot_path = os.path.join(temp_dir, 'sample_plot.png')
plt.savefig(plot_path)
# Use in document
with doc.create(Figure()) as fig:
fig.add_image(plot_path)
fig.add_caption('Generated plot from temporary file')
# Generate document
doc.generate_pdf('document_with_temp_files')
finally:
# Clean up temporary files
rm_temp_dir()from pylatex import Document, Section
from pylatex.utils import NoEscape, escape_latex
def process_mixed_content(content_list):
"""Process list with mixed safe and unsafe content."""
processed = []
for item in content_list:
if isinstance(item, dict):
if item.get('safe', False):
processed.append(NoEscape(item['text']))
else:
processed.append(escape_latex(item['text']))
else:
processed.append(escape_latex(str(item)))
return processed
doc = Document()
mixed_content = [
{'text': r'\textbf{Safe LaTeX}', 'safe': True},
{'text': 'Unsafe: $100 & 50%', 'safe': False},
{'text': r'\emph{Another safe command}', 'safe': True}
]
with doc.create(Section('Mixed Content')):
for item in process_mixed_content(mixed_content):
doc.append(item)
doc.append(' ')import os
from pylatex.utils import fix_filename
def validate_and_fix_paths(file_paths):
"""Validate and fix multiple file paths."""
fixed_paths = []
for path in file_paths:
if os.path.exists(path):
fixed_path = fix_filename(path)
fixed_paths.append(fixed_path)
else:
print(f"Warning: File not found: {path}")
return fixed_paths
# Usage
image_files = [
'results.data.png',
'analysis/summary.report.pdf',
'nonexistent.file.jpg'
]
safe_paths = validate_and_fix_paths(image_files)from pylatex import Document, Section
from pylatex.utils import dumps_list, bold, italic, escape_latex
def format_bibliography_items(references):
"""Format a list of references with mixed formatting."""
formatted_refs = []
for ref in references:
# Author in bold, title in italic
author = bold(ref['author'], escape=True)
title = italic(ref['title'], escape=True)
year = escape_latex(str(ref['year']))
formatted_ref = f"{author}. {title}. {year}."
formatted_refs.append(NoEscape(formatted_ref))
return formatted_refs
doc = Document()
references = [
{'author': 'Smith, J.', 'title': 'Advanced LaTeX Techniques', 'year': 2023},
{'author': 'Doe, A. & Brown, B.', 'title': 'Document Processing Methods', 'year': 2022}
]
with doc.create(Section('References')):
formatted_refs = format_bibliography_items(references)
ref_list = dumps_list(formatted_refs, token='\n\n')
doc.append(ref_list)from pylatex.utils import escape_latex, NoEscape
import re
def sanitize_user_input(text, allowed_commands=None):
"""Sanitize user input while allowing specific LaTeX commands."""
if allowed_commands is None:
allowed_commands = []
# First escape everything
safe_text = escape_latex(text)
# Then selectively unescape allowed commands
for command in allowed_commands:
pattern = re.escape(escape_latex(command))
safe_text = safe_text.replace(pattern, command)
return NoEscape(safe_text)
# Usage
user_text = r"Use \textbf{bold} text but avoid \dangerous{commands}"
allowed = [r'\textbf', r'\textit', r'\emph']
sanitized = sanitize_user_input(user_text, allowed)
# Result: "Use \textbf{bold} text but avoid \\dangerous\{commands\}"from pylatex.utils import escape_latex, NoEscape
def safe_append(container, content, escape_by_default=True):
"""Safely append content with error handling."""
try:
if isinstance(content, str) and escape_by_default:
container.append(escape_latex(content))
else:
container.append(content)
except Exception as e:
print(f"Error appending content: {e}")
container.append(f"[Content error: {str(e)}]")
# Usage with error recovery
doc = Document()
contents = [
"Normal text",
NoEscape(r"\textbf{Bold}"),
None, # This will cause an error
"More normal text"
]
for content in contents:
safe_append(doc, content)from pylatex.utils import dumps_list, escape_latex
def debug_latex_output(items, show_escaping=True):
"""Debug utility to show how items will be processed."""
print("LaTeX Processing Debug:")
print("-" * 40)
for i, item in enumerate(items):
print(f"Item {i}: {repr(item)}")
if show_escaping and isinstance(item, str):
escaped = escape_latex(item)
print(f" Escaped: {escaped}")
try:
if hasattr(item, 'dumps'):
output = item.dumps()
else:
output = str(item)
print(f" Output: {output}")
except Exception as e:
print(f" Error: {e}")
print()
# Usage for debugging
debug_items = [
"Normal text with $pecial char$",
NoEscape(r"\textbf{Bold command}"),
42,
["nested", "list"]
]
debug_latex_output(debug_items)from pylatex import Document
from pylatex.utils import NoEscape, escape_latex
# Define clear policies for different content types
def add_user_content(doc, content):
"""Always escape user-provided content."""
doc.append(escape_latex(content))
def add_template_content(doc, content):
"""Template content is pre-verified as safe."""
doc.append(NoEscape(content))
def add_mixed_content(doc, content, is_safe=False):
"""Mixed content with explicit safety flag."""
if is_safe:
doc.append(NoEscape(content))
else:
doc.append(escape_latex(content))import contextlib
from pylatex.utils import make_temp_dir, rm_temp_dir
@contextlib.contextmanager
def temp_directory():
"""Context manager for temporary directory handling."""
temp_dir = make_temp_dir()
try:
yield temp_dir
finally:
rm_temp_dir()
# Usage
with temp_directory() as temp_dir:
# Use temp_dir for file operations
# Cleanup happens automatically
passThe utilities system in PyLaTeX provides essential tools for safe and robust document generation, handling the complexities of LaTeX character escaping, file path management, and content processing while maintaining code clarity and preventing common LaTeX compilation errors.
Install with Tessl CLI
npx tessl i tessl/pypi-pylatex