Clean up unittest attempt.
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
Metadata Management for Scientific Gallery Generator
|
||||
|
||||
This module handles loading, parsing, and caching of metadata for plots
|
||||
and folders in the gallery system. Supports YAML and JSON formats with
|
||||
hierarchical inheritance.
|
||||
|
||||
Features:
|
||||
- Load metadata from YAML/JSON files
|
||||
- Hierarchical metadata inheritance from parent folders
|
||||
- Plot-specific metadata overrides
|
||||
- Metadata caching for performance
|
||||
"""
|
||||
|
||||
import json
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
def load_metadata_file(metadata_path: Path) -> Dict[str, Any]:
|
||||
"""
|
||||
Load metadata from a YAML or JSON file.
|
||||
|
||||
Args:
|
||||
metadata_path: Path to the metadata file
|
||||
|
||||
Returns:
|
||||
Dictionary containing the metadata, empty dict if file doesn't exist
|
||||
or can't be parsed
|
||||
"""
|
||||
if not metadata_path.exists():
|
||||
return {}
|
||||
|
||||
try:
|
||||
with metadata_path.open('r', encoding='utf-8') as f:
|
||||
suffix_lower = metadata_path.suffix.lower()
|
||||
if suffix_lower == '.yaml' or suffix_lower == '.yml':
|
||||
return yaml.safe_load(f) or {}
|
||||
elif metadata_path.suffix.lower() == '.json':
|
||||
return json.load(f) or {}
|
||||
else:
|
||||
print(f"Warning: Unknown metadata file format: "
|
||||
f"{metadata_path}")
|
||||
return {}
|
||||
except (yaml.YAMLError, json.JSONDecodeError, IOError) as e:
|
||||
print(f"Warning: Could not parse metadata file {metadata_path}: {e}")
|
||||
raise e
|
||||
|
||||
|
||||
def load_folder_metadata(folder_path: Path) -> Dict[str, Any]:
|
||||
"""
|
||||
Load folder-level metadata from metadata.yaml, metadata.yml, or metadata.json.
|
||||
|
||||
Args:
|
||||
folder_path: Path to the folder to check for metadata
|
||||
|
||||
Returns:
|
||||
Dictionary containing the folder metadata
|
||||
"""
|
||||
# Try YAML first, then JSON for backwards compatibility
|
||||
for filename in ['metadata.yaml', 'metadata.yml', 'metadata.json']:
|
||||
metadata_path = folder_path / filename
|
||||
if metadata_path.exists():
|
||||
return load_metadata_file(metadata_path)
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def get_metadata_file_path(folder_path: Path) -> str:
|
||||
"""
|
||||
Get the metadata file path for a folder. Returns existing file if found,
|
||||
otherwise suggests metadata.yaml (preferred format).
|
||||
|
||||
Args:
|
||||
folder_path: Path to the folder to check for metadata
|
||||
|
||||
Returns:
|
||||
String path to the metadata file (existing or suggested)
|
||||
"""
|
||||
# Preferred order: YAML first, then JSON
|
||||
preferred_files = ['metadata.yaml', 'metadata.yml', 'metadata.json']
|
||||
|
||||
for filename in preferred_files:
|
||||
metadata_path = folder_path / filename
|
||||
if metadata_path.exists():
|
||||
return str(metadata_path)
|
||||
|
||||
# If no file exists, suggest metadata.yaml (preferred format)
|
||||
return str(folder_path / 'metadata.yaml')
|
||||
|
||||
|
||||
def merge_metadata(
|
||||
parent_metadata: Dict[str, Any],
|
||||
child_metadata: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Merge parent and child metadata, with child values overriding parent
|
||||
values.
|
||||
|
||||
Args:
|
||||
parent_metadata: Metadata from parent folder
|
||||
child_metadata: Metadata from current folder
|
||||
|
||||
Returns:
|
||||
Merged metadata dictionary
|
||||
"""
|
||||
merged = parent_metadata.copy()
|
||||
merged.update(child_metadata)
|
||||
return merged
|
||||
|
||||
|
||||
def resolve_metadata_for_plot(
|
||||
plot_path: Path,
|
||||
inherited_metadata: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Resolve metadata for a specific plot by merging inherited metadata
|
||||
with plot-specific metadata.
|
||||
|
||||
Args:
|
||||
plot_path: Path to the plot file (PDF)
|
||||
inherited_metadata: Metadata inherited from folder hierarchy
|
||||
|
||||
Returns:
|
||||
Final merged metadata for the plot
|
||||
"""
|
||||
plot_stem = plot_path.stem
|
||||
plot_dir = plot_path.parent
|
||||
|
||||
# Check for plot-specific metadata files
|
||||
for suffix in ['.yaml', '.yml', '.json']:
|
||||
plot_metadata_path = plot_dir / f"{plot_stem}{suffix}"
|
||||
if plot_metadata_path.exists():
|
||||
plot_metadata = load_metadata_file(plot_metadata_path)
|
||||
return merge_metadata(inherited_metadata, plot_metadata)
|
||||
|
||||
# No plot-specific metadata found, return inherited metadata
|
||||
return inherited_metadata.copy()
|
||||
|
||||
|
||||
def save_metadata_cache(
|
||||
web_dir: Path,
|
||||
plot_metadata_cache: Dict[str, Dict[str, Any]]
|
||||
) -> None:
|
||||
"""
|
||||
Save plot metadata cache to meta_cache.json in the web directory.
|
||||
|
||||
Args:
|
||||
web_dir: Web directory where the cache file should be saved
|
||||
plot_metadata_cache: Dictionary mapping plot names to their metadata
|
||||
"""
|
||||
cache_path = web_dir / "meta_cache.json"
|
||||
try:
|
||||
with cache_path.open('w', encoding='utf-8') as f:
|
||||
json.dump(plot_metadata_cache, f, indent=2, ensure_ascii=False)
|
||||
print(f"Saved metadata cache: {cache_path}")
|
||||
except IOError as e:
|
||||
print(f"Warning: Could not save metadata cache {cache_path}: {e}")
|
||||
Reference in New Issue
Block a user