Files
ETPlot/CLAUDE.md
T

4.5 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What This Project Does

A Python package that generates responsive static HTML galleries from scientific plot collections (PDFs and HTMLs). It converts PDFs to PNGs via ImageMagick, organizes plots hierarchically, propagates YAML/JSON metadata through directory trees, and renders everything via a Jinja2 template into a static website served from a web directory.

Commands

# Install the package (editable)
pip install -e ".[dev]"

# Run all tests
pytest tests/

# Run a single test file
pytest tests/test_generate_gallery.py -v

# Run a single test by name
pytest tests/test_generate_gallery.py::test_needs_update_missing_target -v

# Generate gallery (CLI entry point after install)
gallery --config config.yaml --verbose

# Generate gallery (legacy script)
python generate_gallery.py --verbose

# Incremental update for one source only
gallery --source /path/to/plots --verbose

# Clean regeneration
gallery --clean --verbose

# Serve output locally
python -m http.server 8000 -d /web/kschmidt/public_html/

Code style: black with line-length = 120.

Architecture

Execution Flow

generate() [api.py]
  └── copy_assets()         [builder.py]  — copies assets/ to web output dir
  └── get_template()        [builder.py]  — loads gallery/templates/gallery.html
  └── build_gallery()       [builder.py]  — recursive per-source-directory walk
        └── load_folder_metadata()  [utils/metadata.py]
        └── merge_metadata()        [utils/metadata.py]  — inherits from parent
        └── process_plot_files()    [utils/processing.py]  — PDF→PNG, copy files
        └── save_metadata_cache()   [utils/metadata.py]
        └── render_gallery_page()   [utils/processing.py]  — writes index.html
        └── recurse into subdirs

Key Files

File Role
gallery/api.py generate() — primary public entry point; orchestrates everything
gallery/builder.py build_gallery() — recursive traversal; get_template(), copy_assets()
gallery/config.py GalleryConfig, GallerySource, GalleryDefaults dataclasses; YAML loading
gallery/cli.py CLI (gallery command) wrapping generate()
gallery/utils/processing.py PDF→PNG via ImageMagick subprocess; needs_update() timestamp check; render_gallery_page()
gallery/utils/metadata.py Load/merge/cache YAML+JSON metadata; per-plot metadata resolution
gallery/utils/stats.py Directory size/count statistics
gallery/templates/gallery.html Single Jinja2 template for all gallery pages
gallery/assets/js/ Vanilla JS modules loaded as ES modules; GalleryApp in gallery-app.js orchestrates all managers
gallery/assets/css/ Modular CSS; main.css imports all others via @import
config.yaml Local deployment config (paths are machine-specific)

Config File Format

The YAML config uses a specific structure (not flat — must match GalleryConfig.from_yaml()):

paths:
  web_folder: "/web/user/public_html"   # required
gallery:
  plot_root: "gallery"
  png_dpi: 400
sources:
  - name: "my_plots"
    path: "/path/to/plots"
metadata:
  cache_enabled: true
  inherit_from_parent: true

Incremental Updates

needs_update(source, target) uses a 30-second buffer on mtime comparisons to handle filesystem timing. This is intentional — avoid tightening it.

When source_to_update is passed to generate(), only that source's subdirectory is deleted and rebuilt; all other sources stay intact and the root index is re-rendered to include them.

Metadata Inheritance

metadata.yaml (or .yml/.json) in any source directory is loaded and merged with parent metadata (inherit_from_parent=True by default). Child directories override parent keys. Per-plot overrides can live in <plotname>.yaml files alongside the plot.

Frontend (Static JS/CSS)

The frontend is vanilla ES modules — no build step. assets/js/main.js imports GalleryApp from gallery-app.js, which instantiates all manager classes (ThemeManager, SearchManager, NavigationManager, etc.). Each manager is self-contained. The template embeds gallery data as JSON in the page; JS reads it at runtime.

Deployment

The project ships a Singularity.def / web.sif Apptainer container for HPC environments. CI (.gitlab-ci.yml) builds the container and runs pytest inside it. For local development the .venv is sufficient.