Files
tono/backend/nodes/save.py

105 lines
3.4 KiB
Python

from __future__ import annotations
import tempfile
from pathlib import Path
from backend.node_registry import register_node
from backend.execution_context import emit_warning, emit_file_download
from backend.exporters import (
available_formats,
get_exporter,
resolve_path,
type_name_for_value,
)
DOWNLOAD_DIR = Path(tempfile.gettempdir()) / "tono-downloads"
def _choices_by_source_type() -> dict[str, list[str]]:
"""Build the format dropdown's source-type map from the exporter registry.
Centralising this here means adding a new exporter module (or a new format
inside an existing one) automatically surfaces in the UI — no parallel
list to keep in sync.
"""
return {
"DATA_FIELD": available_formats("DATA_FIELD"),
"IMAGE": available_formats("IMAGE"),
"ANNOTATION_SOURCE": available_formats("ANNOTATION_SOURCE"),
"LINE": available_formats("LINE"),
"RECORD_TABLE": available_formats("RECORD_TABLE"),
"DATA_TABLE": available_formats("DATA_TABLE"),
"FLOAT": available_formats("FLOAT"),
"MESH_MODEL": available_formats("MESH_MODEL"),
}
@register_node(display_name="Save")
class Save:
@classmethod
def INPUT_TYPES(cls):
choices = _choices_by_source_type()
return {
"required": {
"filename": ("STRING", {
"default": "",
"placeholder": "filename",
"placement": "top",
}),
"value": ("DATA_FIELD", {
"label": "value",
"accepted_types": [
"IMAGE",
"ANNOTATION_SOURCE",
"LINE",
"RECORD_TABLE",
"DATA_TABLE",
"MESH_MODEL",
"FLOAT",
],
}),
"format": ("STRING", {
"default": choices["DATA_FIELD"][0] if choices["DATA_FIELD"] else "",
"choices_by_source_type": choices,
"source_type_input": "value",
}),
},
"optional": {
"plot_title": ("STRING", {
"default": "",
"placeholder": "plot title (optional)",
"label": "title",
"show_when_source_type": {"value": ["LINE"]},
}),
},
}
OUTPUTS = ()
FUNCTION = "save"
OUTPUT_NODE = True
MANUAL_TRIGGER = True
DESCRIPTION = (
"Save a single graph value to disk. Supports fields, images, lines, tables, scalars, "
"and 3D meshes. Use 'GWY' or 'TIFF (data)' for DataFields you want to re-open later "
"with their physical units preserved."
)
KEYWORDS = ("export", "write", "download", "png", "tiff", "csv", "json", "npz", "obj", "stl", "gwy")
def save(
self,
filename: str,
format: str,
value,
plot_title: str = "",
):
type_name = type_name_for_value(value)
module, spec = get_exporter(type_name, format)
path = resolve_path(filename, spec, DOWNLOAD_DIR)
module.save(path, value, format, plot_title=plot_title)
emit_warning(f"Saved to {path.name}")
emit_file_download(str(path))
return ()