Reformats imports and long expressions in flows/components/opensearch.py and flows/components/opensearch_multimodel.py for improved readability and maintainability. No functional changes were made; only code style and structure were updated.
172 lines
4.8 KiB
Python
172 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Utility to sync embedded component code inside Langflow JSON files.
|
|
|
|
Given a Python source file (e.g. the OpenSearch component implementation) and
|
|
a target selector, this script updates every flow definition in ``./flows`` so
|
|
that the component's ``template.code.value`` matches the supplied file.
|
|
|
|
Example:
|
|
python scripts/update_flow_components.py \\
|
|
--code-file flows/components/opensearch_multimodel.py \\
|
|
--display-name \"OpenSearch (Multi-Model)\"
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Iterable
|
|
|
|
|
|
def load_code(source_path: Path) -> str:
|
|
try:
|
|
return source_path.read_text(encoding="utf-8")
|
|
except FileNotFoundError as exc:
|
|
raise SystemExit(f"[error] code file not found: {source_path}") from exc
|
|
|
|
|
|
def should_update_component(
|
|
node: dict, *, display_name: str | None, metadata_module: str | None
|
|
) -> bool:
|
|
node_data = node.get("data", {})
|
|
component = node_data.get("node", {})
|
|
|
|
if display_name and component.get("display_name") != display_name:
|
|
return False
|
|
|
|
if metadata_module:
|
|
metadata = component.get("metadata", {})
|
|
module_name = metadata.get("module")
|
|
if module_name != metadata_module:
|
|
return False
|
|
|
|
template = component.get("template", {})
|
|
code_entry = template.get("code")
|
|
return isinstance(code_entry, dict) and "value" in code_entry
|
|
|
|
|
|
def update_flow(
|
|
flow_path: Path,
|
|
code: str,
|
|
*,
|
|
display_name: str | None,
|
|
metadata_module: str | None,
|
|
dry_run: bool,
|
|
) -> bool:
|
|
with flow_path.open(encoding="utf-8") as fh:
|
|
try:
|
|
data = json.load(fh)
|
|
except json.JSONDecodeError as exc:
|
|
raise SystemExit(f"[error] failed to parse {flow_path}: {exc}") from exc
|
|
|
|
changed = False
|
|
|
|
for node in data.get("data", {}).get("nodes", []):
|
|
if not should_update_component(
|
|
node, display_name=display_name, metadata_module=metadata_module
|
|
):
|
|
continue
|
|
|
|
template = node["data"]["node"]["template"]
|
|
if template["code"]["value"] != code:
|
|
if dry_run:
|
|
changed = True
|
|
else:
|
|
template["code"]["value"] = code
|
|
changed = True
|
|
|
|
if changed and not dry_run:
|
|
flow_path.write_text(
|
|
json.dumps(data, indent=2, ensure_ascii=False) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
return changed
|
|
|
|
|
|
def iter_flow_files(flows_dir: Path) -> Iterable[Path]:
|
|
for path in sorted(flows_dir.glob("*.json")):
|
|
if path.is_file():
|
|
yield path
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(
|
|
description="Update embedded component code in Langflow JSON files."
|
|
)
|
|
parser.add_argument(
|
|
"--code-file",
|
|
required=True,
|
|
type=Path,
|
|
help="Path to the Python file containing the component code.",
|
|
)
|
|
parser.add_argument(
|
|
"--flows-dir",
|
|
type=Path,
|
|
default=Path("flows"),
|
|
help="Directory containing Langflow JSON files.",
|
|
)
|
|
parser.add_argument(
|
|
"--display-name",
|
|
help="Component display_name to match (e.g. 'OpenSearch (Multi-Model)').",
|
|
)
|
|
parser.add_argument(
|
|
"--metadata-module", help="Component metadata.module value to match."
|
|
)
|
|
parser.add_argument(
|
|
"--dry-run",
|
|
action="store_true",
|
|
help="Report which files would change without modifying them.",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not args.display_name and not args.metadata_module:
|
|
parser.error(
|
|
"At least one of --display-name or --metadata-module must be provided."
|
|
)
|
|
|
|
return args
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
|
|
flows_dir: Path = args.flows_dir
|
|
if not flows_dir.exists():
|
|
raise SystemExit(f"[error] flows directory not found: {flows_dir}")
|
|
|
|
code = load_code(args.code_file)
|
|
|
|
updated_files = []
|
|
for flow_path in iter_flow_files(flows_dir):
|
|
changed = update_flow(
|
|
flow_path,
|
|
code,
|
|
display_name=args.display_name,
|
|
metadata_module=args.metadata_module,
|
|
dry_run=args.dry_run,
|
|
)
|
|
if changed:
|
|
updated_files.append(flow_path)
|
|
|
|
if args.dry_run:
|
|
if updated_files:
|
|
print("[dry-run] files that would be updated:")
|
|
for path in updated_files:
|
|
print(f" - {path}")
|
|
else:
|
|
print("[dry-run] no files would change.")
|
|
else:
|
|
if updated_files:
|
|
print("Updated component code in:")
|
|
for path in updated_files:
|
|
print(f" - {path}")
|
|
else:
|
|
print("No updates were necessary.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|