0
# Utilities and Helper Functions
1
2
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.
3
4
## Capabilities
5
6
### String Escaping and Safety
7
8
Control how special characters are handled when converting Python strings to LaTeX.
9
10
```python { .api }
11
class NoEscape(str):
12
"""
13
String class that bypasses LaTeX character escaping.
14
15
When NoEscape strings are combined:
16
- NoEscape + NoEscape → NoEscape
17
- NoEscape + str → str (regular string)
18
19
Parameters:
20
- string: str, content that should not be escaped
21
"""
22
23
def escape_latex(s):
24
"""
25
Escape special LaTeX characters in a string.
26
27
Parameters:
28
- s: str, NoEscape, or convertible to string, input to escape
29
30
Returns:
31
- NoEscape: escaped string safe for LaTeX
32
33
Special characters handled:
34
- & → \\&
35
- % → \\%
36
- $ → \\$
37
- # → \\#
38
- _ → \\_
39
- { → \\{
40
- } → \\}
41
- ~ → \\textasciitilde{}
42
- ^ → \\^{}
43
- \\ → \\textbackslash{}
44
- newline → \\newline%
45
- - → {-}
46
- [ → {[}
47
- ] → {]}
48
"""
49
```
50
51
Usage example:
52
53
```python
54
from pylatex import Document, Section
55
from pylatex.utils import NoEscape, escape_latex
56
57
doc = Document()
58
59
with doc.create(Section('Text Handling')):
60
# Automatic escaping (default behavior)
61
unsafe_text = "Cost: $100, efficiency: 95% (issue #42)"
62
doc.append(escape_latex(unsafe_text))
63
# Produces: Cost: \$100, efficiency: 95\% (issue \#42)
64
65
# Skip escaping with NoEscape
66
latex_command = NoEscape(r'\textbf{Important}')
67
doc.append(latex_command)
68
# Produces: \textbf{Important}
69
70
# Mixed content
71
doc.append('Regular text with ')
72
doc.append(NoEscape(r'\emph{emphasized}'))
73
doc.append(' and special chars: ')
74
doc.append(escape_latex('R&D costs ~$50K'))
75
```
76
77
### File Path Handling
78
79
Utilities for managing file paths in LaTeX-compatible formats.
80
81
```python { .api }
82
def fix_filename(path):
83
"""
84
Fix file paths for LaTeX compatibility.
85
86
Handles issues with:
87
- Multiple dots in filenames
88
- Special characters in paths
89
- Platform-specific path separators
90
- Tilde characters (~) in paths
91
92
Parameters:
93
- path: str, file path to fix
94
95
Returns:
96
- str: LaTeX-compatible file path
97
98
Examples:
99
- 'foo.bar.pdf' → '{foo.bar}.pdf'
100
- '/path/file~name.pdf' → '\\detokenize{/path/file~name.pdf}'
101
"""
102
```
103
104
Usage example:
105
106
```python
107
from pylatex import Document, Section
108
from pylatex.figure import Figure
109
from pylatex.utils import fix_filename
110
111
doc = Document()
112
113
with doc.create(Section('File Examples')):
114
# Problematic filenames
115
problematic_files = [
116
'data.analysis.results.png',
117
'user~documents/report.pdf',
118
'file with spaces & symbols.jpg'
119
]
120
121
for filename in problematic_files:
122
safe_filename = fix_filename(filename)
123
124
with doc.create(Figure()) as fig:
125
fig.add_image(safe_filename)
126
fig.add_caption(f'Fixed filename: {safe_filename}')
127
128
# Cross-platform path handling
129
import os
130
from pylatex.utils import fix_filename
131
132
if os.name == 'posix':
133
# Unix/Linux/Mac paths
134
image_path = '/home/user/data.set.1/results.png'
135
else:
136
# Windows paths
137
image_path = r'C:\Users\Name\data.set.1\results.png'
138
139
safe_path = fix_filename(image_path)
140
```
141
142
### List and Collection Processing
143
144
Convert Python lists and collections to LaTeX-formatted strings.
145
146
```python { .api }
147
def dumps_list(l, *, escape=True, token="%\n", mapper=None, as_content=True):
148
"""
149
Convert a list to LaTeX string representation.
150
151
Parameters:
152
- l: list, collection to convert
153
- escape: bool, whether to escape special LaTeX characters
154
- token: str, separator between list items (default: newline)
155
- mapper: callable or list, functions to apply to each item
156
- as_content: bool, use dumps_as_content() for LatexObjects
157
158
Returns:
159
- NoEscape: formatted LaTeX string
160
"""
161
```
162
163
Usage example:
164
165
```python
166
from pylatex import Document, Section, Command
167
from pylatex.utils import dumps_list, bold, italic
168
169
doc = Document()
170
171
with doc.create(Section('List Processing')):
172
# Basic list conversion
173
items = ['First item', 'Second item', 'Third item']
174
formatted_list = dumps_list(items)
175
doc.append(formatted_list)
176
177
# With custom separator
178
inline_items = ['alpha', 'beta', 'gamma']
179
inline_list = dumps_list(inline_items, token=', ')
180
doc.append('Greek letters: ')
181
doc.append(inline_list)
182
183
# With escaping for special characters
184
special_items = ['Cost: $100', 'Efficiency: 95%', 'Issue #42']
185
safe_list = dumps_list(special_items, escape=True)
186
doc.append(safe_list)
187
188
# With formatting mapper
189
emphasis_items = ['Important', 'Critical', 'Urgent']
190
emphasized = dumps_list(emphasis_items, mapper=bold)
191
doc.append(emphasized)
192
193
# Multiple mappers
194
styled_items = ['Note 1', 'Note 2', 'Note 3']
195
styled_list = dumps_list(styled_items, mapper=[bold, italic])
196
doc.append(styled_list)
197
```
198
199
### Text Formatting Utilities
200
201
Convenience functions for common text formatting operations.
202
203
```python { .api }
204
def bold(s, *, escape=True):
205
"""
206
Format text as bold using \\textbf{}.
207
208
Parameters:
209
- s: str, text to make bold
210
- escape: bool, whether to escape special characters
211
212
Returns:
213
- NoEscape: bold-formatted LaTeX string
214
"""
215
216
def italic(s, *, escape=True):
217
"""
218
Format text as italic using \\textit{}.
219
220
Parameters:
221
- s: str, text to make italic
222
- escape: bool, whether to escape special characters
223
224
Returns:
225
- NoEscape: italic-formatted LaTeX string
226
"""
227
228
def verbatim(s, *, delimiter="|"):
229
"""
230
Format text as verbatim using \\verb.
231
232
Parameters:
233
- s: str, text to format verbatim
234
- delimiter: str, delimiter character (default: |)
235
236
Returns:
237
- NoEscape: verbatim-formatted LaTeX string
238
"""
239
```
240
241
Usage example:
242
243
```python
244
from pylatex import Document, Section
245
from pylatex.utils import bold, italic, verbatim
246
247
doc = Document()
248
249
with doc.create(Section('Text Formatting')):
250
# Basic formatting
251
doc.append(bold('Important notice'))
252
doc.append(' and ')
253
doc.append(italic('emphasized text'))
254
255
# With automatic escaping
256
doc.append(bold('Cost: $1,000 (50% discount)', escape=True))
257
258
# Verbatim code
259
doc.append('Use the command ')
260
doc.append(verbatim(r'\renewcommand{\baselinestretch}{1.5}'))
261
doc.append(' to change line spacing.')
262
263
# Custom verbatim delimiter
264
doc.append('The expression ')
265
doc.append(verbatim('x|y', delimiter='!'))
266
doc.append(' uses a pipe character.')
267
268
# Nested formatting
269
complex_text = bold('Warning: ') + italic('System may be unstable')
270
doc.append(complex_text)
271
```
272
273
### Temporary File Management
274
275
Utilities for managing temporary files during document generation.
276
277
```python { .api }
278
def make_temp_dir():
279
"""
280
Create a temporary directory for document processing.
281
282
Returns:
283
- str: absolute path to temporary directory
284
285
Note: Directory persists until rm_temp_dir() is called or program exits
286
"""
287
288
def rm_temp_dir():
289
"""
290
Remove the temporary directory created by make_temp_dir().
291
292
Cleans up all temporary files and directories created during processing.
293
"""
294
```
295
296
Usage example:
297
298
```python
299
import os
300
from pylatex import Document
301
from pylatex.figure import Figure
302
from pylatex.utils import make_temp_dir, rm_temp_dir
303
import matplotlib.pyplot as plt
304
305
doc = Document()
306
307
# Create temporary directory for plots
308
temp_dir = make_temp_dir()
309
310
try:
311
# Generate and save plots to temp directory
312
plt.figure(figsize=(8, 6))
313
plt.plot([1, 2, 3, 4], [1, 4, 2, 3])
314
plt.title('Sample Plot')
315
316
plot_path = os.path.join(temp_dir, 'sample_plot.png')
317
plt.savefig(plot_path)
318
319
# Use in document
320
with doc.create(Figure()) as fig:
321
fig.add_image(plot_path)
322
fig.add_caption('Generated plot from temporary file')
323
324
# Generate document
325
doc.generate_pdf('document_with_temp_files')
326
327
finally:
328
# Clean up temporary files
329
rm_temp_dir()
330
```
331
332
## Advanced Utilities
333
334
### Custom String Processing
335
336
```python
337
from pylatex import Document, Section
338
from pylatex.utils import NoEscape, escape_latex
339
340
def process_mixed_content(content_list):
341
"""Process list with mixed safe and unsafe content."""
342
processed = []
343
344
for item in content_list:
345
if isinstance(item, dict):
346
if item.get('safe', False):
347
processed.append(NoEscape(item['text']))
348
else:
349
processed.append(escape_latex(item['text']))
350
else:
351
processed.append(escape_latex(str(item)))
352
353
return processed
354
355
doc = Document()
356
357
mixed_content = [
358
{'text': r'\textbf{Safe LaTeX}', 'safe': True},
359
{'text': 'Unsafe: $100 & 50%', 'safe': False},
360
{'text': r'\emph{Another safe command}', 'safe': True}
361
]
362
363
with doc.create(Section('Mixed Content')):
364
for item in process_mixed_content(mixed_content):
365
doc.append(item)
366
doc.append(' ')
367
```
368
369
### File Path Validation
370
371
```python
372
import os
373
from pylatex.utils import fix_filename
374
375
def validate_and_fix_paths(file_paths):
376
"""Validate and fix multiple file paths."""
377
fixed_paths = []
378
379
for path in file_paths:
380
if os.path.exists(path):
381
fixed_path = fix_filename(path)
382
fixed_paths.append(fixed_path)
383
else:
384
print(f"Warning: File not found: {path}")
385
386
return fixed_paths
387
388
# Usage
389
image_files = [
390
'results.data.png',
391
'analysis/summary.report.pdf',
392
'nonexistent.file.jpg'
393
]
394
395
safe_paths = validate_and_fix_paths(image_files)
396
```
397
398
### Batch Text Processing
399
400
```python
401
from pylatex import Document, Section
402
from pylatex.utils import dumps_list, bold, italic, escape_latex
403
404
def format_bibliography_items(references):
405
"""Format a list of references with mixed formatting."""
406
formatted_refs = []
407
408
for ref in references:
409
# Author in bold, title in italic
410
author = bold(ref['author'], escape=True)
411
title = italic(ref['title'], escape=True)
412
year = escape_latex(str(ref['year']))
413
414
formatted_ref = f"{author}. {title}. {year}."
415
formatted_refs.append(NoEscape(formatted_ref))
416
417
return formatted_refs
418
419
doc = Document()
420
421
references = [
422
{'author': 'Smith, J.', 'title': 'Advanced LaTeX Techniques', 'year': 2023},
423
{'author': 'Doe, A. & Brown, B.', 'title': 'Document Processing Methods', 'year': 2022}
424
]
425
426
with doc.create(Section('References')):
427
formatted_refs = format_bibliography_items(references)
428
ref_list = dumps_list(formatted_refs, token='\n\n')
429
doc.append(ref_list)
430
```
431
432
### Content Sanitization
433
434
```python
435
from pylatex.utils import escape_latex, NoEscape
436
import re
437
438
def sanitize_user_input(text, allowed_commands=None):
439
"""Sanitize user input while allowing specific LaTeX commands."""
440
if allowed_commands is None:
441
allowed_commands = []
442
443
# First escape everything
444
safe_text = escape_latex(text)
445
446
# Then selectively unescape allowed commands
447
for command in allowed_commands:
448
pattern = re.escape(escape_latex(command))
449
safe_text = safe_text.replace(pattern, command)
450
451
return NoEscape(safe_text)
452
453
# Usage
454
user_text = r"Use \textbf{bold} text but avoid \dangerous{commands}"
455
allowed = [r'\textbf', r'\textit', r'\emph']
456
457
sanitized = sanitize_user_input(user_text, allowed)
458
# Result: "Use \textbf{bold} text but avoid \\dangerous\{commands\}"
459
```
460
461
## Error Handling and Debugging
462
463
### Safe Operations
464
465
```python
466
from pylatex.utils import escape_latex, NoEscape
467
468
def safe_append(container, content, escape_by_default=True):
469
"""Safely append content with error handling."""
470
try:
471
if isinstance(content, str) and escape_by_default:
472
container.append(escape_latex(content))
473
else:
474
container.append(content)
475
except Exception as e:
476
print(f"Error appending content: {e}")
477
container.append(f"[Content error: {str(e)}]")
478
479
# Usage with error recovery
480
doc = Document()
481
482
contents = [
483
"Normal text",
484
NoEscape(r"\textbf{Bold}"),
485
None, # This will cause an error
486
"More normal text"
487
]
488
489
for content in contents:
490
safe_append(doc, content)
491
```
492
493
### Debug Utilities
494
495
```python
496
from pylatex.utils import dumps_list, escape_latex
497
498
def debug_latex_output(items, show_escaping=True):
499
"""Debug utility to show how items will be processed."""
500
print("LaTeX Processing Debug:")
501
print("-" * 40)
502
503
for i, item in enumerate(items):
504
print(f"Item {i}: {repr(item)}")
505
506
if show_escaping and isinstance(item, str):
507
escaped = escape_latex(item)
508
print(f" Escaped: {escaped}")
509
510
try:
511
if hasattr(item, 'dumps'):
512
output = item.dumps()
513
else:
514
output = str(item)
515
print(f" Output: {output}")
516
except Exception as e:
517
print(f" Error: {e}")
518
519
print()
520
521
# Usage for debugging
522
debug_items = [
523
"Normal text with $pecial char$",
524
NoEscape(r"\textbf{Bold command}"),
525
42,
526
["nested", "list"]
527
]
528
529
debug_latex_output(debug_items)
530
```
531
532
## Best Practices
533
534
### Consistent Escaping Strategy
535
536
```python
537
from pylatex import Document
538
from pylatex.utils import NoEscape, escape_latex
539
540
# Define clear policies for different content types
541
def add_user_content(doc, content):
542
"""Always escape user-provided content."""
543
doc.append(escape_latex(content))
544
545
def add_template_content(doc, content):
546
"""Template content is pre-verified as safe."""
547
doc.append(NoEscape(content))
548
549
def add_mixed_content(doc, content, is_safe=False):
550
"""Mixed content with explicit safety flag."""
551
if is_safe:
552
doc.append(NoEscape(content))
553
else:
554
doc.append(escape_latex(content))
555
```
556
557
### Resource Management
558
559
```python
560
import contextlib
561
from pylatex.utils import make_temp_dir, rm_temp_dir
562
563
@contextlib.contextmanager
564
def temp_directory():
565
"""Context manager for temporary directory handling."""
566
temp_dir = make_temp_dir()
567
try:
568
yield temp_dir
569
finally:
570
rm_temp_dir()
571
572
# Usage
573
with temp_directory() as temp_dir:
574
# Use temp_dir for file operations
575
# Cleanup happens automatically
576
pass
577
```
578
579
The 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.