264 lines
8.4 KiB
Python
264 lines
8.4 KiB
Python
"""
|
|
Main API for gallery generation.
|
|
|
|
Provides the primary entry point for programmatic gallery generation.
|
|
"""
|
|
|
|
import shutil
|
|
from pathlib import Path
|
|
from typing import Union, List, Dict, Any
|
|
|
|
from gallery.config import GalleryConfig, GallerySource
|
|
from gallery.builder import get_template, build_gallery, copy_assets
|
|
|
|
|
|
def generate(
|
|
config: Union[GalleryConfig, str, Path] = None,
|
|
web_folder: Union[str, Path] = None,
|
|
sources: List[Union[GallerySource, Dict[str, Any]]] = None,
|
|
clean_first: bool = False,
|
|
verbose: bool = False,
|
|
) -> bool:
|
|
"""
|
|
Generate a scientific gallery from plot sources.
|
|
|
|
Can be called in two ways:
|
|
1. With a GalleryConfig object
|
|
2. With explicit parameters (web_folder and sources)
|
|
|
|
Args:
|
|
config: GalleryConfig object or path to YAML config file.
|
|
If this is provided, other args are ignored.
|
|
web_folder: Output directory for the gallery.
|
|
Required if config is not provided.
|
|
sources: List of GallerySource objects or dicts.
|
|
Required if config is not provided.
|
|
clean_first: If True, removes and recreates the gallery directory
|
|
verbose: If True, prints progress messages
|
|
|
|
Returns:
|
|
True if gallery generation was successful, False otherwise
|
|
|
|
Raises:
|
|
ValueError: If required arguments are missing or invalid
|
|
TypeError: If config type is invalid
|
|
|
|
Example:
|
|
# Using GalleryConfig object
|
|
from gallery import generate, GalleryConfig, GallerySource
|
|
|
|
config = GalleryConfig(
|
|
web_folder="/output/path",
|
|
sources=[
|
|
GallerySource(name="plots", path="/path/to/plots"),
|
|
]
|
|
)
|
|
success = generate(config, verbose=True)
|
|
|
|
# Using explicit parameters
|
|
success = generate(
|
|
web_folder="/output/path",
|
|
sources=[
|
|
{"name": "plots", "path": "/path/to/plots"},
|
|
],
|
|
verbose=True
|
|
)
|
|
|
|
# Loading from YAML config
|
|
success = generate(config="config.yaml", verbose=True)
|
|
"""
|
|
try:
|
|
# Load or create configuration
|
|
if config is not None:
|
|
if isinstance(config, (str, Path)):
|
|
config = GalleryConfig.from_yaml(config)
|
|
elif not isinstance(config, GalleryConfig):
|
|
raise TypeError(
|
|
f"config must be GalleryConfig, str, or Path, "
|
|
f"got {type(config)}"
|
|
)
|
|
else:
|
|
if web_folder is None or sources is None:
|
|
raise ValueError(
|
|
"Either config or both web_folder and sources "
|
|
"must be provided"
|
|
)
|
|
config = GalleryConfig(
|
|
web_folder=web_folder,
|
|
sources=sources or []
|
|
)
|
|
|
|
# Validate configuration
|
|
if not config.sources:
|
|
if verbose:
|
|
print("Warning: No sources configured")
|
|
return False
|
|
|
|
# Check if web_folder is writable
|
|
web_folder_path = Path(config.web_folder)
|
|
if not _is_writable(web_folder_path):
|
|
if verbose:
|
|
print(
|
|
f"Error: Cannot write to web_folder: "
|
|
f"{config.web_folder}"
|
|
)
|
|
return False
|
|
|
|
# Create gallery root directory
|
|
gallery_root = web_folder_path / config.plot_root
|
|
|
|
if clean_first and gallery_root.exists():
|
|
if verbose:
|
|
print(f"Cleaning gallery directory {gallery_root}...")
|
|
try:
|
|
shutil.rmtree(gallery_root)
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Warning: Could not clean directory: {e}")
|
|
return False
|
|
|
|
try:
|
|
gallery_root.mkdir(parents=True, exist_ok=True)
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Error: Could not create gallery directory: {e}")
|
|
return False
|
|
|
|
# Copy assets
|
|
if not copy_assets(config, verbose=verbose):
|
|
if verbose:
|
|
print("Warning: Could not copy assets")
|
|
# Don't fail, continue with generation
|
|
|
|
# Get template
|
|
try:
|
|
template = get_template()
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Error: Could not load template: {e}")
|
|
return False
|
|
|
|
# Process sources
|
|
source_subdirs = []
|
|
for source in config.sources:
|
|
try:
|
|
source_path = Path(source.path).resolve()
|
|
|
|
# Validate source exists
|
|
if not source_path.exists():
|
|
if verbose:
|
|
print(
|
|
f"Warning: Source {source.path} does not exist. "
|
|
f"Skipping."
|
|
)
|
|
continue
|
|
|
|
source_web_dir = gallery_root / source.name
|
|
try:
|
|
source_web_dir.mkdir(parents=True, exist_ok=True)
|
|
except Exception as e:
|
|
if verbose:
|
|
print(
|
|
f"Warning: Could not create directory "
|
|
f"{source_web_dir}: {e}"
|
|
)
|
|
continue
|
|
|
|
source_subdirs.append(source.name)
|
|
|
|
# Process source
|
|
if source_path.is_file() and source_path.suffix == '.pdf':
|
|
# Single PDF file
|
|
from gallery.utils.processing import process_plot_files
|
|
item = process_plot_files(
|
|
config=config,
|
|
plot_file=source_path,
|
|
web_dir=source_web_dir,
|
|
)
|
|
from gallery.utils.processing import render_gallery_page
|
|
render_gallery_page(
|
|
config=config,
|
|
template=template,
|
|
web_dir=source_web_dir,
|
|
items=[item],
|
|
subdirs=[],
|
|
relative_path=Path(source.name)
|
|
)
|
|
elif source_path.is_dir():
|
|
# Directory of plots
|
|
build_gallery(
|
|
config,
|
|
source_path,
|
|
source_web_dir,
|
|
template,
|
|
Path(source.name)
|
|
)
|
|
else:
|
|
if verbose:
|
|
print(
|
|
f"Warning: Source {source.path} is neither a "
|
|
f"directory nor a PDF file. Skipping."
|
|
)
|
|
continue
|
|
|
|
if verbose:
|
|
print(f"Processed {source.name}: {source.path}")
|
|
|
|
except Exception as e:
|
|
if verbose:
|
|
print(
|
|
f"Warning: Error processing source "
|
|
f"{source.name}: {e}"
|
|
)
|
|
continue
|
|
|
|
# Render gallery root index
|
|
try:
|
|
from gallery.utils.processing import render_gallery_page
|
|
render_gallery_page(
|
|
config=config,
|
|
template=template,
|
|
web_dir=gallery_root,
|
|
items=[],
|
|
subdirs=source_subdirs,
|
|
relative_path=Path("."),
|
|
title="Gallery Root"
|
|
)
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Warning: Could not render gallery root: {e}")
|
|
# Don't fail, gallery is still usable
|
|
|
|
if verbose:
|
|
print(f"✓ Gallery generated successfully at {gallery_root}")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
if verbose:
|
|
print(f"Error: Gallery generation failed: {e}")
|
|
return False
|
|
|
|
|
|
def _is_writable(path: Path) -> bool:
|
|
"""
|
|
Check if a path is writable.
|
|
|
|
Creates the directory if it doesn't exist.
|
|
|
|
Args:
|
|
path: Path to check
|
|
|
|
Returns:
|
|
True if writable, False otherwise
|
|
"""
|
|
try:
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
# Try to create a test file
|
|
test_file = path / ".gallery_test"
|
|
test_file.touch()
|
|
test_file.unlink()
|
|
return True
|
|
except Exception:
|
|
return False
|