A Sphinx extension that builds an HTML gallery of examples from any set of Python scripts.
Helper functions for image processing, file operations, and common tasks used throughout Sphinx-Gallery. These utilities provide core functionality for image manipulation, file handling, and system operations.
Function for scaling images while maintaining aspect ratio.
def scale_image(in_fname, out_fname, max_width, max_height):
"""
Scales images while maintaining aspect ratio.
Resizes an image to fit within the specified maximum dimensions
while preserving the original aspect ratio. Uses high-quality
resampling for optimal results.
Parameters:
- in_fname: str, input image filename
- out_fname: str, output image filename
- max_width: int, maximum width in pixels
- max_height: int, maximum height in pixels
Returns:
None
"""from sphinx_gallery.utils import scale_image
# Scale image to fit within 200x200 pixels
scale_image(
'original_plot.png',
'thumbnail_plot.png',
200,
200
)
# Create multiple sizes
scale_image('plot.png', 'plot_small.png', 150, 150)
scale_image('plot.png', 'plot_medium.png', 300, 300)
scale_image('plot.png', 'plot_large.png', 600, 600)Functions for computing file hashes and checksums.
def md5sum_file(filename):
"""
Calculate MD5 hash of a file.
Computes the MD5 checksum of a file for content verification
and change detection.
Parameters:
- filename: str, path to file
Returns:
str: MD5 hash as hexadecimal string
"""
def get_md5sum(src_file, mode='md5'):
"""
Get file hash using specified algorithm.
Parameters:
- src_file: str, path to source file
- mode: str, hash algorithm ('md5', 'sha1', 'sha256')
Returns:
str: File hash as hexadecimal string
"""from sphinx_gallery.utils import md5sum_file, get_md5sum
# Check if file has changed
old_hash = md5sum_file('example.py')
# ... file potentially modified ...
new_hash = md5sum_file('example.py')
if old_hash != new_hash:
print("File has been modified")
# Use different hash algorithms
md5_hash = get_md5sum('data.txt', 'md5')
sha256_hash = get_md5sum('data.txt', 'sha256')Functions for manipulating file paths and extensions.
def replace_py_ipynb(fname):
"""
Replace .py extension with .ipynb.
Converts Python script filename to Jupyter notebook filename.
Parameters:
- fname: str, filename with .py extension
Returns:
str: Filename with .ipynb extension
"""from sphinx_gallery.utils import replace_py_ipynb
# Convert script name to notebook name
script_name = 'plot_example.py'
notebook_name = replace_py_ipynb(script_name)
# Result: 'plot_example.ipynb'
# Handle paths
script_path = '/examples/advanced/plot_demo.py'
notebook_path = replace_py_ipynb(script_path)
# Result: '/examples/advanced/plot_demo.ipynb'Functions for processing text and string content.
def _complete_chunk(chunk_lines, lang):
"""
Complete and validate code chunks.
Parameters:
- chunk_lines: list, lines of code
- lang: str, programming language
Returns:
str: Completed code chunk
"""
def _get_docstring_and_rest(filename):
"""
Extract docstring and remaining code from Python file.
Parameters:
- filename: str, path to Python file
Returns:
tuple: (docstring, remaining_code)
"""Functions for monitoring memory usage and performance.
def _get_memory_usage():
"""
Get current memory usage.
Returns:
float: Memory usage in MB
"""
def optipng(fname, args=None):
"""
Optimize PNG image using optipng.
Parameters:
- fname: str, PNG filename to optimize
- args: list, additional optipng arguments
Returns:
None
"""Functions for interacting with the system and external tools.
def _get_image_ext(image_path):
"""
Get image file extension.
Parameters:
- image_path: str, path to image file
Returns:
str: File extension (e.g., '.png', '.jpg')
"""
def _has_optipng():
"""
Check if optipng is available on the system.
Returns:
bool: True if optipng is available
"""from sphinx_gallery.utils import scale_image
from PIL import Image
import os
def create_responsive_images(src_image, base_name, sizes):
"""
Create multiple sizes of an image for responsive display.
Parameters:
- src_image: str, source image path
- base_name: str, base name for output files
- sizes: list, list of (width, height) tuples
"""
for i, (width, height) in enumerate(sizes):
suffix = f"_{width}x{height}" if i > 0 else ""
output_name = f"{base_name}{suffix}.png"
scale_image(src_image, output_name, width, height)
# Usage
create_responsive_images(
'plot_large.png',
'plot',
[(200, 200), (400, 400), (800, 800)]
)from sphinx_gallery.utils import md5sum_file
import os
import json
def create_file_manifest(directory):
"""
Create manifest of all files with their hashes.
Parameters:
- directory: str, directory to process
Returns:
dict: Mapping of filenames to MD5 hashes
"""
manifest = {}
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(('.py', '.png', '.jpg')):
filepath = os.path.join(root, file)
relative_path = os.path.relpath(filepath, directory)
manifest[relative_path] = md5sum_file(filepath)
return manifest
# Usage
manifest = create_file_manifest('examples/')
with open('file_manifest.json', 'w') as f:
json.dump(manifest, f, indent=2)from sphinx_gallery.utils import scale_image, optipng, _has_optipng
import os
def optimize_gallery_images(image_dir, thumbnail_size=(200, 200)):
"""
Optimize all images in gallery directory.
Parameters:
- image_dir: str, directory containing images
- thumbnail_size: tuple, maximum thumbnail dimensions
"""
for filename in os.listdir(image_dir):
if filename.endswith('.png'):
filepath = os.path.join(image_dir, filename)
# Create thumbnail
thumb_name = filename.replace('.png', '_thumb.png')
thumb_path = os.path.join(image_dir, thumb_name)
scale_image(filepath, thumb_path, *thumbnail_size)
# Optimize with optipng if available
if _has_optipng():
optipng(filepath)
optipng(thumb_path)
print(f"Processed {filename}")
# Usage
optimize_gallery_images('_build/html/_images/')from sphinx_gallery.utils import md5sum_file
import pickle
import os
class FileChangeTracker:
"""Track file changes using MD5 hashes."""
def __init__(self, cache_file='.file_hashes.pkl'):
self.cache_file = cache_file
self.hashes = self._load_hashes()
def _load_hashes(self):
"""Load cached hashes from file."""
if os.path.exists(self.cache_file):
with open(self.cache_file, 'rb') as f:
return pickle.load(f)
return {}
def _save_hashes(self):
"""Save hashes to cache file."""
with open(self.cache_file, 'wb') as f:
pickle.dump(self.hashes, f)
def has_changed(self, filepath):
"""Check if file has changed since last check."""
current_hash = md5sum_file(filepath)
old_hash = self.hashes.get(filepath)
changed = old_hash != current_hash
self.hashes[filepath] = current_hash
return changed
def save(self):
"""Save current state to disk."""
self._save_hashes()
# Usage
tracker = FileChangeTracker()
for example_file in os.listdir('examples/'):
if example_file.endswith('.py'):
filepath = os.path.join('examples/', example_file)
if tracker.has_changed(filepath):
print(f"File changed: {example_file}")
tracker.save()import functools
import logging
def safe_image_operation(operation_name):
"""
Decorator for safe image operations with error handling.
Parameters:
- operation_name: str, name of the operation for logging
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
logging.warning(f"{operation_name} failed: {e}")
return None
return wrapper
return decorator
@safe_image_operation("Image scaling")
def safe_scale_image(in_fname, out_fname, max_width, max_height):
"""Safe wrapper around scale_image."""
from sphinx_gallery.utils import scale_image
return scale_image(in_fname, out_fname, max_width, max_height)
# Usage
result = safe_scale_image('input.png', 'output.png', 200, 200)
if result is None:
print("Image scaling failed")def process_images_during_build(app, env, updated_docs, updated_assets):
"""Process images during Sphinx build."""
from sphinx_gallery.utils import scale_image
image_dir = os.path.join(app.outdir, '_images')
if os.path.exists(image_dir):
for image_file in os.listdir(image_dir):
if image_file.endswith('.png'):
# Create thumbnail version
base_name = image_file.replace('.png', '')
thumb_file = f"{base_name}_thumb.png"
scale_image(
os.path.join(image_dir, image_file),
os.path.join(image_dir, thumb_file),
150, 150
)
# In conf.py
def setup(app):
app.connect('env-updated', process_images_during_build)from sphinx_gallery.utils import _get_memory_usage
import time
import functools
def monitor_performance(func):
"""Decorator to monitor function performance."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
start_memory = _get_memory_usage()
result = func(*args, **kwargs)
end_time = time.time()
end_memory = _get_memory_usage()
print(f"{func.__name__}:")
print(f" Time: {end_time - start_time:.2f}s")
print(f" Memory: {end_memory - start_memory:.1f}MB")
return result
return wrapper
@monitor_performance
def process_large_gallery():
"""Example of monitored function."""
# Gallery processing code here
passInstall with Tessl CLI
npx tessl i tessl/pypi-sphinx-gallery