4660 lines
240 KiB
HTML
4660 lines
240 KiB
HTML
|
|
<!doctype html>
|
|
<html lang="en" class="no-js">
|
|
<head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
|
|
|
|
|
|
<link rel="prev" href="../circuit_breaker/">
|
|
|
|
|
|
<link rel="next" href="../ollama/">
|
|
|
|
|
|
<link rel="icon" href="../../../assets/images/favicon.png">
|
|
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.9">
|
|
|
|
|
|
|
|
<title>format_string - ComfyPPT</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../../assets/stylesheets/main.4af4bdda.min.css">
|
|
|
|
|
|
<link rel="stylesheet" href="../../../assets/stylesheets/palette.06af60db.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
|
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../../../assets/_mkdocstrings.css">
|
|
|
|
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="deep-purple" data-md-color-accent="indigo">
|
|
|
|
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
|
<label class="md-overlay" for="__drawer"></label>
|
|
<div data-md-component="skip">
|
|
|
|
|
|
<a href="#comfydv.format_string" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
</div>
|
|
<div data-md-component="announce">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<header class="md-header md-header--shadow" data-md-component="header">
|
|
<nav class="md-header__inner md-grid" aria-label="Header">
|
|
<a href="../../.." title="ComfyPPT" class="md-header__button md-logo" aria-label="ComfyPPT" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
|
|
|
</a>
|
|
<label class="md-header__button md-icon" for="__drawer">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
|
|
</label>
|
|
<div class="md-header__title" data-md-component="header-title">
|
|
<div class="md-header__ellipsis">
|
|
<div class="md-header__topic">
|
|
<span class="md-ellipsis">
|
|
ComfyPPT
|
|
</span>
|
|
</div>
|
|
<div class="md-header__topic" data-md-component="header-topic">
|
|
<span class="md-ellipsis">
|
|
|
|
format_string
|
|
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-header__button md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
</label>
|
|
<div class="md-search" data-md-component="search" role="dialog">
|
|
<label class="md-search__overlay" for="__search"></label>
|
|
<div class="md-search__inner" role="search">
|
|
<form class="md-search__form" name="search">
|
|
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
|
<label class="md-search__icon md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
|
|
</label>
|
|
<nav class="md-search__options" aria-label="Search">
|
|
|
|
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
|
</button>
|
|
</nav>
|
|
|
|
</form>
|
|
<div class="md-search__output">
|
|
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
|
<div class="md-search-result" data-md-component="search-result">
|
|
<div class="md-search-result__meta">
|
|
Initializing search
|
|
</div>
|
|
<ol class="md-search-result__list" role="presentation"></ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</nav>
|
|
|
|
</header>
|
|
|
|
<div class="md-container" data-md-component="container">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<main class="md-main" data-md-component="main">
|
|
<div class="md-main__inner md-grid">
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
|
<label class="md-nav__title" for="__drawer">
|
|
<a href="../../.." title="ComfyPPT" class="md-nav__button md-logo" aria-label="ComfyPPT" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
|
|
|
|
</a>
|
|
ComfyPPT
|
|
</label>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../../.." class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Home
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Code Reference
|
|
|
|
</span>
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
|
|
<label class="md-nav__title" for="__nav_2">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Code Reference
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1" checked>
|
|
|
|
|
|
|
|
<div class="md-nav__link md-nav__container">
|
|
<a href="../" class="md-nav__link ">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
comfydv
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
<label class="md-nav__link " for="__nav_2_1" id="__nav_2_1_label" tabindex="0">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
</div>
|
|
|
|
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_1_label" aria-expanded="true">
|
|
<label class="md-nav__title" for="__nav_2_1">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
comfydv
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1_1" >
|
|
|
|
|
|
|
|
<div class="md-nav__link md-nav__container">
|
|
<a href="../_llm/" class="md-nav__link ">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
_llm
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
<label class="md-nav__link " for="__nav_2_1_1" id="__nav_2_1_1_label" tabindex="0">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
</div>
|
|
|
|
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_1_1_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_2_1_1">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
_llm
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../_llm/chat/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
chat
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../_llm/ollama_provider/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
ollama_provider
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../_llm/provider/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
provider
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../circuit_breaker/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
circuit_breaker
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active">
|
|
|
|
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
|
|
|
|
|
|
|
<label class="md-nav__link md-nav__link--active" for="__toc">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
|
|
</span>
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<a href="./" class="md-nav__link md-nav__link--active">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
FormatString
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="FormatString">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.INPUT_TYPES" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
INPUT_TYPES
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.IS_CHANGED" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
IS_CHANGED
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.format_string" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.get_node_config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
get_node_config
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.load_node_state" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
load_node_state
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.time_now" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
time_now
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.update_widget" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
update_widget
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.get_format_string_node_config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
get_format_string_node_config
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.load_format_string_node" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
load_format_string_node
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.update_format_string_node" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
update_format_string_node
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../ollama/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
ollama
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../random_choice/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
random_choice
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../utils/" class="md-nav__link">
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
utils
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
FormatString
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="FormatString">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.INPUT_TYPES" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
INPUT_TYPES
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.IS_CHANGED" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
IS_CHANGED
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.format_string" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
format_string
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.get_node_config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
get_node_config
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.load_node_state" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
load_node_state
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.time_now" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
time_now
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.FormatString.update_widget" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
update_widget
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.get_format_string_node_config" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
get_format_string_node_config
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.load_format_string_node" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
load_format_string_node
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#comfydv.format_string.update_format_string_node" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
update_format_string_node
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-content" data-md-component="content">
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
|
|
|
|
|
|
<h1>format_string</h1>
|
|
|
|
<div class="doc doc-object doc-module">
|
|
|
|
|
|
|
|
<a id="comfydv.format_string"></a>
|
|
<div class="doc doc-contents first">
|
|
|
|
<p>FormatString module for ComfyUI.</p>
|
|
<p>This module provides a custom node for ComfyUI that allows formatting strings
|
|
using either simple Python formatting or Jinja2 templates. It can also save
|
|
formatted templates to disk for later reuse.</p>
|
|
<p>The node dynamically updates its inputs and outputs based on the variables
|
|
detected in the template, making it highly flexible for various text generation
|
|
and parameter formatting needs in ComfyUI workflows.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="doc doc-children">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="doc doc-object doc-class">
|
|
|
|
|
|
|
|
<h2 id="comfydv.format_string.FormatString" class="doc doc-heading">
|
|
<code>FormatString</code>
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
|
|
<p>A ComfyUI node for string formatting using Python's format syntax or Jinja2 templates.</p>
|
|
<p>This node dynamically adapts its inputs and outputs based on the variables detected
|
|
in the provided template. It supports saving template state to disk and loading it back.
|
|
The node can operate in two modes:
|
|
1. Simple: Uses Python's str.format() method
|
|
2. Jinja2: Uses Jinja2 templating engine with sandbox protection</p>
|
|
<p>Additional context variables like datetime, random, and math functions are available
|
|
in Jinja2 mode.</p>
|
|
|
|
|
|
<details class="outputs" open>
|
|
<summary>Outputs</summary>
|
|
<p>The node always returns formatted_string and saved_file_path as the first two outputs
|
|
(positions 0 and 1), followed by any variable values extracted from the template in
|
|
subsequent positions. This ensures the primary outputs are in fixed, predictable positions.</p>
|
|
</details>
|
|
|
|
<p><span class="doc-section-title">Attributes:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.CATEGORY">CATEGORY</span></code></td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The category of the node in ComfyUI's node menu.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.FUNCTION">FUNCTION</span></code></td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The main function to be called when the node is executed.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.RETURN_TYPES">RETURN_TYPES</span></code></td>
|
|
<td>
|
|
<code><span title="tuple">tuple</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Types of the returned outputs (dynamically updated).</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.RETURN_NAMES">RETURN_NAMES</span></code></td>
|
|
<td>
|
|
<code><span title="tuple">tuple</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Names of the returned outputs (dynamically updated).</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.node_configs">node_configs</span></code></td>
|
|
<td>
|
|
<code><span title="dict">dict</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Storage for configurations of node instances.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.jinja_env">jinja_env</span></code></td>
|
|
<td>
|
|
<code><span title="SandboxedEnvironment">SandboxedEnvironment</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Sandboxed Jinja2 environment for secure template rendering.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td><code><span title="comfydv.format_string.FormatString.additional_context">additional_context</span></code></td>
|
|
<td>
|
|
<code><span title="dict">dict</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Extra context variables available in Jinja2 templates.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"> 38</span>
|
|
<span class="normal"> 39</span>
|
|
<span class="normal"> 40</span>
|
|
<span class="normal"> 41</span>
|
|
<span class="normal"> 42</span>
|
|
<span class="normal"> 43</span>
|
|
<span class="normal"> 44</span>
|
|
<span class="normal"> 45</span>
|
|
<span class="normal"> 46</span>
|
|
<span class="normal"> 47</span>
|
|
<span class="normal"> 48</span>
|
|
<span class="normal"> 49</span>
|
|
<span class="normal"> 50</span>
|
|
<span class="normal"> 51</span>
|
|
<span class="normal"> 52</span>
|
|
<span class="normal"> 53</span>
|
|
<span class="normal"> 54</span>
|
|
<span class="normal"> 55</span>
|
|
<span class="normal"> 56</span>
|
|
<span class="normal"> 57</span>
|
|
<span class="normal"> 58</span>
|
|
<span class="normal"> 59</span>
|
|
<span class="normal"> 60</span>
|
|
<span class="normal"> 61</span>
|
|
<span class="normal"> 62</span>
|
|
<span class="normal"> 63</span>
|
|
<span class="normal"> 64</span>
|
|
<span class="normal"> 65</span>
|
|
<span class="normal"> 66</span>
|
|
<span class="normal"> 67</span>
|
|
<span class="normal"> 68</span>
|
|
<span class="normal"> 69</span>
|
|
<span class="normal"> 70</span>
|
|
<span class="normal"> 71</span>
|
|
<span class="normal"> 72</span>
|
|
<span class="normal"> 73</span>
|
|
<span class="normal"> 74</span>
|
|
<span class="normal"> 75</span>
|
|
<span class="normal"> 76</span>
|
|
<span class="normal"> 77</span>
|
|
<span class="normal"> 78</span>
|
|
<span class="normal"> 79</span>
|
|
<span class="normal"> 80</span>
|
|
<span class="normal"> 81</span>
|
|
<span class="normal"> 82</span>
|
|
<span class="normal"> 83</span>
|
|
<span class="normal"> 84</span>
|
|
<span class="normal"> 85</span>
|
|
<span class="normal"> 86</span>
|
|
<span class="normal"> 87</span>
|
|
<span class="normal"> 88</span>
|
|
<span class="normal"> 89</span>
|
|
<span class="normal"> 90</span>
|
|
<span class="normal"> 91</span>
|
|
<span class="normal"> 92</span>
|
|
<span class="normal"> 93</span>
|
|
<span class="normal"> 94</span>
|
|
<span class="normal"> 95</span>
|
|
<span class="normal"> 96</span>
|
|
<span class="normal"> 97</span>
|
|
<span class="normal"> 98</span>
|
|
<span class="normal"> 99</span>
|
|
<span class="normal">100</span>
|
|
<span class="normal">101</span>
|
|
<span class="normal">102</span>
|
|
<span class="normal">103</span>
|
|
<span class="normal">104</span>
|
|
<span class="normal">105</span>
|
|
<span class="normal">106</span>
|
|
<span class="normal">107</span>
|
|
<span class="normal">108</span>
|
|
<span class="normal">109</span>
|
|
<span class="normal">110</span>
|
|
<span class="normal">111</span>
|
|
<span class="normal">112</span>
|
|
<span class="normal">113</span>
|
|
<span class="normal">114</span>
|
|
<span class="normal">115</span>
|
|
<span class="normal">116</span>
|
|
<span class="normal">117</span>
|
|
<span class="normal">118</span>
|
|
<span class="normal">119</span>
|
|
<span class="normal">120</span>
|
|
<span class="normal">121</span>
|
|
<span class="normal">122</span>
|
|
<span class="normal">123</span>
|
|
<span class="normal">124</span>
|
|
<span class="normal">125</span>
|
|
<span class="normal">126</span>
|
|
<span class="normal">127</span>
|
|
<span class="normal">128</span>
|
|
<span class="normal">129</span>
|
|
<span class="normal">130</span>
|
|
<span class="normal">131</span>
|
|
<span class="normal">132</span>
|
|
<span class="normal">133</span>
|
|
<span class="normal">134</span>
|
|
<span class="normal">135</span>
|
|
<span class="normal">136</span>
|
|
<span class="normal">137</span>
|
|
<span class="normal">138</span>
|
|
<span class="normal">139</span>
|
|
<span class="normal">140</span>
|
|
<span class="normal">141</span>
|
|
<span class="normal">142</span>
|
|
<span class="normal">143</span>
|
|
<span class="normal">144</span>
|
|
<span class="normal">145</span>
|
|
<span class="normal">146</span>
|
|
<span class="normal">147</span>
|
|
<span class="normal">148</span>
|
|
<span class="normal">149</span>
|
|
<span class="normal">150</span>
|
|
<span class="normal">151</span>
|
|
<span class="normal">152</span>
|
|
<span class="normal">153</span>
|
|
<span class="normal">154</span>
|
|
<span class="normal">155</span>
|
|
<span class="normal">156</span>
|
|
<span class="normal">157</span>
|
|
<span class="normal">158</span>
|
|
<span class="normal">159</span>
|
|
<span class="normal">160</span>
|
|
<span class="normal">161</span>
|
|
<span class="normal">162</span>
|
|
<span class="normal">163</span>
|
|
<span class="normal">164</span>
|
|
<span class="normal">165</span>
|
|
<span class="normal">166</span>
|
|
<span class="normal">167</span>
|
|
<span class="normal">168</span>
|
|
<span class="normal">169</span>
|
|
<span class="normal">170</span>
|
|
<span class="normal">171</span>
|
|
<span class="normal">172</span>
|
|
<span class="normal">173</span>
|
|
<span class="normal">174</span>
|
|
<span class="normal">175</span>
|
|
<span class="normal">176</span>
|
|
<span class="normal">177</span>
|
|
<span class="normal">178</span>
|
|
<span class="normal">179</span>
|
|
<span class="normal">180</span>
|
|
<span class="normal">181</span>
|
|
<span class="normal">182</span>
|
|
<span class="normal">183</span>
|
|
<span class="normal">184</span>
|
|
<span class="normal">185</span>
|
|
<span class="normal">186</span>
|
|
<span class="normal">187</span>
|
|
<span class="normal">188</span>
|
|
<span class="normal">189</span>
|
|
<span class="normal">190</span>
|
|
<span class="normal">191</span>
|
|
<span class="normal">192</span>
|
|
<span class="normal">193</span>
|
|
<span class="normal">194</span>
|
|
<span class="normal">195</span>
|
|
<span class="normal">196</span>
|
|
<span class="normal">197</span>
|
|
<span class="normal">198</span>
|
|
<span class="normal">199</span>
|
|
<span class="normal">200</span>
|
|
<span class="normal">201</span>
|
|
<span class="normal">202</span>
|
|
<span class="normal">203</span>
|
|
<span class="normal">204</span>
|
|
<span class="normal">205</span>
|
|
<span class="normal">206</span>
|
|
<span class="normal">207</span>
|
|
<span class="normal">208</span>
|
|
<span class="normal">209</span>
|
|
<span class="normal">210</span>
|
|
<span class="normal">211</span>
|
|
<span class="normal">212</span>
|
|
<span class="normal">213</span>
|
|
<span class="normal">214</span>
|
|
<span class="normal">215</span>
|
|
<span class="normal">216</span>
|
|
<span class="normal">217</span>
|
|
<span class="normal">218</span>
|
|
<span class="normal">219</span>
|
|
<span class="normal">220</span>
|
|
<span class="normal">221</span>
|
|
<span class="normal">222</span>
|
|
<span class="normal">223</span>
|
|
<span class="normal">224</span>
|
|
<span class="normal">225</span>
|
|
<span class="normal">226</span>
|
|
<span class="normal">227</span>
|
|
<span class="normal">228</span>
|
|
<span class="normal">229</span>
|
|
<span class="normal">230</span>
|
|
<span class="normal">231</span>
|
|
<span class="normal">232</span>
|
|
<span class="normal">233</span>
|
|
<span class="normal">234</span>
|
|
<span class="normal">235</span>
|
|
<span class="normal">236</span>
|
|
<span class="normal">237</span>
|
|
<span class="normal">238</span>
|
|
<span class="normal">239</span>
|
|
<span class="normal">240</span>
|
|
<span class="normal">241</span>
|
|
<span class="normal">242</span>
|
|
<span class="normal">243</span>
|
|
<span class="normal">244</span>
|
|
<span class="normal">245</span>
|
|
<span class="normal">246</span>
|
|
<span class="normal">247</span>
|
|
<span class="normal">248</span>
|
|
<span class="normal">249</span>
|
|
<span class="normal">250</span>
|
|
<span class="normal">251</span>
|
|
<span class="normal">252</span>
|
|
<span class="normal">253</span>
|
|
<span class="normal">254</span>
|
|
<span class="normal">255</span>
|
|
<span class="normal">256</span>
|
|
<span class="normal">257</span>
|
|
<span class="normal">258</span>
|
|
<span class="normal">259</span>
|
|
<span class="normal">260</span>
|
|
<span class="normal">261</span>
|
|
<span class="normal">262</span>
|
|
<span class="normal">263</span>
|
|
<span class="normal">264</span>
|
|
<span class="normal">265</span>
|
|
<span class="normal">266</span>
|
|
<span class="normal">267</span>
|
|
<span class="normal">268</span>
|
|
<span class="normal">269</span>
|
|
<span class="normal">270</span>
|
|
<span class="normal">271</span>
|
|
<span class="normal">272</span>
|
|
<span class="normal">273</span>
|
|
<span class="normal">274</span>
|
|
<span class="normal">275</span>
|
|
<span class="normal">276</span>
|
|
<span class="normal">277</span>
|
|
<span class="normal">278</span>
|
|
<span class="normal">279</span>
|
|
<span class="normal">280</span>
|
|
<span class="normal">281</span>
|
|
<span class="normal">282</span>
|
|
<span class="normal">283</span>
|
|
<span class="normal">284</span>
|
|
<span class="normal">285</span>
|
|
<span class="normal">286</span>
|
|
<span class="normal">287</span>
|
|
<span class="normal">288</span>
|
|
<span class="normal">289</span>
|
|
<span class="normal">290</span>
|
|
<span class="normal">291</span>
|
|
<span class="normal">292</span>
|
|
<span class="normal">293</span>
|
|
<span class="normal">294</span>
|
|
<span class="normal">295</span>
|
|
<span class="normal">296</span>
|
|
<span class="normal">297</span>
|
|
<span class="normal">298</span>
|
|
<span class="normal">299</span>
|
|
<span class="normal">300</span>
|
|
<span class="normal">301</span>
|
|
<span class="normal">302</span>
|
|
<span class="normal">303</span>
|
|
<span class="normal">304</span>
|
|
<span class="normal">305</span>
|
|
<span class="normal">306</span>
|
|
<span class="normal">307</span>
|
|
<span class="normal">308</span>
|
|
<span class="normal">309</span>
|
|
<span class="normal">310</span>
|
|
<span class="normal">311</span>
|
|
<span class="normal">312</span>
|
|
<span class="normal">313</span>
|
|
<span class="normal">314</span>
|
|
<span class="normal">315</span>
|
|
<span class="normal">316</span>
|
|
<span class="normal">317</span>
|
|
<span class="normal">318</span>
|
|
<span class="normal">319</span>
|
|
<span class="normal">320</span>
|
|
<span class="normal">321</span>
|
|
<span class="normal">322</span>
|
|
<span class="normal">323</span>
|
|
<span class="normal">324</span>
|
|
<span class="normal">325</span>
|
|
<span class="normal">326</span>
|
|
<span class="normal">327</span>
|
|
<span class="normal">328</span>
|
|
<span class="normal">329</span>
|
|
<span class="normal">330</span>
|
|
<span class="normal">331</span>
|
|
<span class="normal">332</span>
|
|
<span class="normal">333</span>
|
|
<span class="normal">334</span>
|
|
<span class="normal">335</span>
|
|
<span class="normal">336</span>
|
|
<span class="normal">337</span>
|
|
<span class="normal">338</span>
|
|
<span class="normal">339</span>
|
|
<span class="normal">340</span>
|
|
<span class="normal">341</span>
|
|
<span class="normal">342</span>
|
|
<span class="normal">343</span>
|
|
<span class="normal">344</span>
|
|
<span class="normal">345</span>
|
|
<span class="normal">346</span>
|
|
<span class="normal">347</span>
|
|
<span class="normal">348</span>
|
|
<span class="normal">349</span>
|
|
<span class="normal">350</span>
|
|
<span class="normal">351</span>
|
|
<span class="normal">352</span>
|
|
<span class="normal">353</span>
|
|
<span class="normal">354</span>
|
|
<span class="normal">355</span>
|
|
<span class="normal">356</span>
|
|
<span class="normal">357</span>
|
|
<span class="normal">358</span>
|
|
<span class="normal">359</span>
|
|
<span class="normal">360</span>
|
|
<span class="normal">361</span>
|
|
<span class="normal">362</span>
|
|
<span class="normal">363</span>
|
|
<span class="normal">364</span>
|
|
<span class="normal">365</span>
|
|
<span class="normal">366</span>
|
|
<span class="normal">367</span>
|
|
<span class="normal">368</span>
|
|
<span class="normal">369</span>
|
|
<span class="normal">370</span>
|
|
<span class="normal">371</span>
|
|
<span class="normal">372</span>
|
|
<span class="normal">373</span>
|
|
<span class="normal">374</span>
|
|
<span class="normal">375</span>
|
|
<span class="normal">376</span>
|
|
<span class="normal">377</span>
|
|
<span class="normal">378</span>
|
|
<span class="normal">379</span>
|
|
<span class="normal">380</span>
|
|
<span class="normal">381</span>
|
|
<span class="normal">382</span>
|
|
<span class="normal">383</span>
|
|
<span class="normal">384</span>
|
|
<span class="normal">385</span>
|
|
<span class="normal">386</span>
|
|
<span class="normal">387</span>
|
|
<span class="normal">388</span>
|
|
<span class="normal">389</span>
|
|
<span class="normal">390</span>
|
|
<span class="normal">391</span>
|
|
<span class="normal">392</span>
|
|
<span class="normal">393</span>
|
|
<span class="normal">394</span>
|
|
<span class="normal">395</span>
|
|
<span class="normal">396</span>
|
|
<span class="normal">397</span>
|
|
<span class="normal">398</span>
|
|
<span class="normal">399</span>
|
|
<span class="normal">400</span>
|
|
<span class="normal">401</span>
|
|
<span class="normal">402</span>
|
|
<span class="normal">403</span>
|
|
<span class="normal">404</span>
|
|
<span class="normal">405</span>
|
|
<span class="normal">406</span>
|
|
<span class="normal">407</span>
|
|
<span class="normal">408</span>
|
|
<span class="normal">409</span>
|
|
<span class="normal">410</span>
|
|
<span class="normal">411</span>
|
|
<span class="normal">412</span>
|
|
<span class="normal">413</span>
|
|
<span class="normal">414</span>
|
|
<span class="normal">415</span>
|
|
<span class="normal">416</span>
|
|
<span class="normal">417</span>
|
|
<span class="normal">418</span>
|
|
<span class="normal">419</span>
|
|
<span class="normal">420</span>
|
|
<span class="normal">421</span>
|
|
<span class="normal">422</span>
|
|
<span class="normal">423</span>
|
|
<span class="normal">424</span>
|
|
<span class="normal">425</span>
|
|
<span class="normal">426</span>
|
|
<span class="normal">427</span>
|
|
<span class="normal">428</span>
|
|
<span class="normal">429</span>
|
|
<span class="normal">430</span>
|
|
<span class="normal">431</span>
|
|
<span class="normal">432</span>
|
|
<span class="normal">433</span>
|
|
<span class="normal">434</span>
|
|
<span class="normal">435</span>
|
|
<span class="normal">436</span>
|
|
<span class="normal">437</span>
|
|
<span class="normal">438</span>
|
|
<span class="normal">439</span>
|
|
<span class="normal">440</span>
|
|
<span class="normal">441</span>
|
|
<span class="normal">442</span>
|
|
<span class="normal">443</span>
|
|
<span class="normal">444</span>
|
|
<span class="normal">445</span>
|
|
<span class="normal">446</span>
|
|
<span class="normal">447</span>
|
|
<span class="normal">448</span>
|
|
<span class="normal">449</span>
|
|
<span class="normal">450</span>
|
|
<span class="normal">451</span>
|
|
<span class="normal">452</span>
|
|
<span class="normal">453</span>
|
|
<span class="normal">454</span>
|
|
<span class="normal">455</span>
|
|
<span class="normal">456</span>
|
|
<span class="normal">457</span>
|
|
<span class="normal">458</span>
|
|
<span class="normal">459</span>
|
|
<span class="normal">460</span>
|
|
<span class="normal">461</span>
|
|
<span class="normal">462</span>
|
|
<span class="normal">463</span>
|
|
<span class="normal">464</span>
|
|
<span class="normal">465</span>
|
|
<span class="normal">466</span>
|
|
<span class="normal">467</span>
|
|
<span class="normal">468</span>
|
|
<span class="normal">469</span>
|
|
<span class="normal">470</span>
|
|
<span class="normal">471</span>
|
|
<span class="normal">472</span>
|
|
<span class="normal">473</span>
|
|
<span class="normal">474</span>
|
|
<span class="normal">475</span>
|
|
<span class="normal">476</span>
|
|
<span class="normal">477</span>
|
|
<span class="normal">478</span>
|
|
<span class="normal">479</span>
|
|
<span class="normal">480</span>
|
|
<span class="normal">481</span>
|
|
<span class="normal">482</span>
|
|
<span class="normal">483</span>
|
|
<span class="normal">484</span>
|
|
<span class="normal">485</span>
|
|
<span class="normal">486</span>
|
|
<span class="normal">487</span>
|
|
<span class="normal">488</span>
|
|
<span class="normal">489</span>
|
|
<span class="normal">490</span>
|
|
<span class="normal">491</span>
|
|
<span class="normal">492</span>
|
|
<span class="normal">493</span>
|
|
<span class="normal">494</span>
|
|
<span class="normal">495</span>
|
|
<span class="normal">496</span>
|
|
<span class="normal">497</span>
|
|
<span class="normal">498</span>
|
|
<span class="normal">499</span>
|
|
<span class="normal">500</span>
|
|
<span class="normal">501</span>
|
|
<span class="normal">502</span>
|
|
<span class="normal">503</span>
|
|
<span class="normal">504</span>
|
|
<span class="normal">505</span>
|
|
<span class="normal">506</span>
|
|
<span class="normal">507</span>
|
|
<span class="normal">508</span>
|
|
<span class="normal">509</span>
|
|
<span class="normal">510</span>
|
|
<span class="normal">511</span>
|
|
<span class="normal">512</span>
|
|
<span class="normal">513</span>
|
|
<span class="normal">514</span>
|
|
<span class="normal">515</span>
|
|
<span class="normal">516</span>
|
|
<span class="normal">517</span>
|
|
<span class="normal">518</span>
|
|
<span class="normal">519</span>
|
|
<span class="normal">520</span>
|
|
<span class="normal">521</span>
|
|
<span class="normal">522</span>
|
|
<span class="normal">523</span>
|
|
<span class="normal">524</span>
|
|
<span class="normal">525</span>
|
|
<span class="normal">526</span>
|
|
<span class="normal">527</span>
|
|
<span class="normal">528</span>
|
|
<span class="normal">529</span>
|
|
<span class="normal">530</span>
|
|
<span class="normal">531</span>
|
|
<span class="normal">532</span>
|
|
<span class="normal">533</span>
|
|
<span class="normal">534</span>
|
|
<span class="normal">535</span>
|
|
<span class="normal">536</span>
|
|
<span class="normal">537</span>
|
|
<span class="normal">538</span>
|
|
<span class="normal">539</span>
|
|
<span class="normal">540</span>
|
|
<span class="normal">541</span>
|
|
<span class="normal">542</span>
|
|
<span class="normal">543</span>
|
|
<span class="normal">544</span>
|
|
<span class="normal">545</span>
|
|
<span class="normal">546</span>
|
|
<span class="normal">547</span>
|
|
<span class="normal">548</span>
|
|
<span class="normal">549</span>
|
|
<span class="normal">550</span>
|
|
<span class="normal">551</span>
|
|
<span class="normal">552</span>
|
|
<span class="normal">553</span>
|
|
<span class="normal">554</span>
|
|
<span class="normal">555</span>
|
|
<span class="normal">556</span>
|
|
<span class="normal">557</span>
|
|
<span class="normal">558</span>
|
|
<span class="normal">559</span>
|
|
<span class="normal">560</span>
|
|
<span class="normal">561</span>
|
|
<span class="normal">562</span>
|
|
<span class="normal">563</span>
|
|
<span class="normal">564</span>
|
|
<span class="normal">565</span>
|
|
<span class="normal">566</span>
|
|
<span class="normal">567</span>
|
|
<span class="normal">568</span>
|
|
<span class="normal">569</span>
|
|
<span class="normal">570</span>
|
|
<span class="normal">571</span>
|
|
<span class="normal">572</span>
|
|
<span class="normal">573</span>
|
|
<span class="normal">574</span>
|
|
<span class="normal">575</span>
|
|
<span class="normal">576</span>
|
|
<span class="normal">577</span>
|
|
<span class="normal">578</span>
|
|
<span class="normal">579</span>
|
|
<span class="normal">580</span>
|
|
<span class="normal">581</span>
|
|
<span class="normal">582</span>
|
|
<span class="normal">583</span>
|
|
<span class="normal">584</span>
|
|
<span class="normal">585</span>
|
|
<span class="normal">586</span>
|
|
<span class="normal">587</span>
|
|
<span class="normal">588</span>
|
|
<span class="normal">589</span>
|
|
<span class="normal">590</span>
|
|
<span class="normal">591</span>
|
|
<span class="normal">592</span>
|
|
<span class="normal">593</span>
|
|
<span class="normal">594</span>
|
|
<span class="normal">595</span>
|
|
<span class="normal">596</span>
|
|
<span class="normal">597</span>
|
|
<span class="normal">598</span>
|
|
<span class="normal">599</span>
|
|
<span class="normal">600</span>
|
|
<span class="normal">601</span>
|
|
<span class="normal">602</span>
|
|
<span class="normal">603</span>
|
|
<span class="normal">604</span>
|
|
<span class="normal">605</span>
|
|
<span class="normal">606</span>
|
|
<span class="normal">607</span>
|
|
<span class="normal">608</span>
|
|
<span class="normal">609</span>
|
|
<span class="normal">610</span>
|
|
<span class="normal">611</span>
|
|
<span class="normal">612</span>
|
|
<span class="normal">613</span>
|
|
<span class="normal">614</span>
|
|
<span class="normal">615</span>
|
|
<span class="normal">616</span>
|
|
<span class="normal">617</span>
|
|
<span class="normal">618</span>
|
|
<span class="normal">619</span>
|
|
<span class="normal">620</span>
|
|
<span class="normal">621</span>
|
|
<span class="normal">622</span>
|
|
<span class="normal">623</span>
|
|
<span class="normal">624</span>
|
|
<span class="normal">625</span>
|
|
<span class="normal">626</span>
|
|
<span class="normal">627</span>
|
|
<span class="normal">628</span>
|
|
<span class="normal">629</span>
|
|
<span class="normal">630</span>
|
|
<span class="normal">631</span>
|
|
<span class="normal">632</span>
|
|
<span class="normal">633</span>
|
|
<span class="normal">634</span>
|
|
<span class="normal">635</span>
|
|
<span class="normal">636</span>
|
|
<span class="normal">637</span>
|
|
<span class="normal">638</span>
|
|
<span class="normal">639</span>
|
|
<span class="normal">640</span>
|
|
<span class="normal">641</span>
|
|
<span class="normal">642</span>
|
|
<span class="normal">643</span>
|
|
<span class="normal">644</span>
|
|
<span class="normal">645</span>
|
|
<span class="normal">646</span>
|
|
<span class="normal">647</span>
|
|
<span class="normal">648</span>
|
|
<span class="normal">649</span>
|
|
<span class="normal">650</span>
|
|
<span class="normal">651</span>
|
|
<span class="normal">652</span>
|
|
<span class="normal">653</span>
|
|
<span class="normal">654</span>
|
|
<span class="normal">655</span>
|
|
<span class="normal">656</span>
|
|
<span class="normal">657</span>
|
|
<span class="normal">658</span>
|
|
<span class="normal">659</span>
|
|
<span class="normal">660</span>
|
|
<span class="normal">661</span>
|
|
<span class="normal">662</span>
|
|
<span class="normal">663</span>
|
|
<span class="normal">664</span>
|
|
<span class="normal">665</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="k">class</span><span class="w"> </span><span class="nc">FormatString</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> A ComfyUI node for string formatting using Python's format syntax or Jinja2 templates.</span>
|
|
|
|
<span class="sd"> This node dynamically adapts its inputs and outputs based on the variables detected</span>
|
|
<span class="sd"> in the provided template. It supports saving template state to disk and loading it back.</span>
|
|
<span class="sd"> The node can operate in two modes:</span>
|
|
<span class="sd"> 1. Simple: Uses Python's str.format() method</span>
|
|
<span class="sd"> 2. Jinja2: Uses Jinja2 templating engine with sandbox protection</span>
|
|
|
|
<span class="sd"> Additional context variables like datetime, random, and math functions are available</span>
|
|
<span class="sd"> in Jinja2 mode.</span>
|
|
|
|
<span class="sd"> Outputs:</span>
|
|
<span class="sd"> The node always returns formatted_string and saved_file_path as the first two outputs</span>
|
|
<span class="sd"> (positions 0 and 1), followed by any variable values extracted from the template in</span>
|
|
<span class="sd"> subsequent positions. This ensures the primary outputs are in fixed, predictable positions.</span>
|
|
|
|
<span class="sd"> Attributes:</span>
|
|
<span class="sd"> CATEGORY (str): The category of the node in ComfyUI's node menu.</span>
|
|
<span class="sd"> FUNCTION (str): The main function to be called when the node is executed.</span>
|
|
<span class="sd"> RETURN_TYPES (tuple): Types of the returned outputs (dynamically updated).</span>
|
|
<span class="sd"> RETURN_NAMES (tuple): Names of the returned outputs (dynamically updated).</span>
|
|
<span class="sd"> node_configs (dict): Storage for configurations of node instances.</span>
|
|
<span class="sd"> jinja_env (SandboxedEnvironment): Sandboxed Jinja2 environment for secure template rendering.</span>
|
|
<span class="sd"> additional_context (dict): Extra context variables available in Jinja2 templates.</span>
|
|
<span class="sd"> """</span>
|
|
|
|
<span class="n">CATEGORY</span> <span class="o">=</span> <span class="s2">"dv/string_operations"</span>
|
|
<span class="n">FUNCTION</span> <span class="o">=</span> <span class="s2">"format_string"</span>
|
|
<span class="n">RETURN_TYPES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="s2">"STRING"</span><span class="p">)</span>
|
|
<span class="n">RETURN_NAMES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"formatted_string"</span><span class="p">,</span> <span class="s2">"saved_file_path"</span><span class="p">)</span>
|
|
<span class="n">OUTPUT_IS_LIST</span> <span class="o">=</span> <span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
|
|
<span class="n">OUTPUT_NODE</span> <span class="o">=</span> <span class="kc">True</span>
|
|
|
|
<span class="c1"># Store configurations for each node instance</span>
|
|
<span class="n">node_configs</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
|
|
|
|
<span class="c1"># Create a sandboxed Jinja2 environment for security</span>
|
|
<span class="n">jinja_env</span> <span class="o">=</span> <span class="n">sandbox</span><span class="o">.</span><span class="n">SandboxedEnvironment</span><span class="p">()</span>
|
|
|
|
<span class="c1"># Define additional context</span>
|
|
<span class="nd">@staticmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">time_now</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Get the current time in a formatted string.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> str: Current time formatted as 'YYYYMMDD-HHMMSS'.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> timestamp = FormatString.time_now()</span>
|
|
<span class="sd"> print(timestamp) # Outputs something like: '20240327-153045'</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> from datetime import datetime</span>
|
|
<span class="sd"> >>> timestamp = FormatString.time_now()</span>
|
|
<span class="sd"> >>> assert len(timestamp) == 15 # Format YYYYMMDD-HHMMSS is 15 chars</span>
|
|
<span class="sd"> >>> assert timestamp[8] == '-' # Check format separator</span>
|
|
<span class="sd"> >>> # Verify it's roughly the current time (allowing some seconds of delay)</span>
|
|
<span class="sd"> >>> current = datetime.now().strftime("%Y%m%d-%H%M")</span>
|
|
<span class="sd"> >>> assert timestamp.startswith(current)</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
|
|
|
|
<span class="n">additional_context</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s2">"datetime"</span><span class="p">:</span> <span class="n">datetime</span><span class="p">,</span>
|
|
<span class="s2">"now"</span><span class="p">:</span> <span class="n">time_now</span><span class="p">,</span> <span class="c1"># we name our custom function `time_now` as `now` so inside jinja it's `{{ now() }}`</span>
|
|
<span class="s2">"random"</span><span class="p">:</span> <span class="n">random</span><span class="p">,</span>
|
|
<span class="s2">"math"</span><span class="p">:</span> <span class="n">math</span><span class="p">,</span>
|
|
<span class="c1"># Add more modules or functions as needed</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">INPUT_TYPES</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Define the input types for the FormatString node.</span>
|
|
|
|
<span class="sd"> This method is called by ComfyUI to determine what inputs the node should have.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: Dictionary defining the node's inputs, including template_type,</span>
|
|
<span class="sd"> template, save_path, and a hidden unique_id.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> input_types = FormatString.INPUT_TYPES()</span>
|
|
<span class="sd"> print(input_types["required"]["template_type"]) # Outputs: (["Simple", "Jinja2"],)</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> input_types = FormatString.INPUT_TYPES()</span>
|
|
<span class="sd"> >>> assert "required" in input_types</span>
|
|
<span class="sd"> >>> assert "template_type" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "template" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "save_path" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "hidden" in input_types</span>
|
|
<span class="sd"> >>> assert "unique_id" in input_types["hidden"]</span>
|
|
<span class="sd"> >>> assert input_types["required"]["template_type"] == (["Simple", "Jinja2"],)</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="p">{</span>
|
|
<span class="s2">"required"</span><span class="p">:</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"Simple"</span><span class="p">,</span> <span class="s2">"Jinja2"</span><span class="p">],),</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"multiline"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}),</span>
|
|
<span class="s2">"save_path"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">}),</span>
|
|
<span class="p">},</span>
|
|
<span class="s2">"hidden"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"unique_id"</span><span class="p">:</span> <span class="s2">"UNIQUE_ID"</span><span class="p">},</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">IS_CHANGED</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Determine if the node should be re-executed based on input changes.</span>
|
|
|
|
<span class="sd"> This method is called by ComfyUI to check if the node needs to be re-calculated</span>
|
|
<span class="sd"> due to changes in its inputs. It forces recalculation when Jinja2 templates</span>
|
|
<span class="sd"> contain time-dependent function calls (e.g., datetime.now(), time_now()).</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> **kwargs: Keyword arguments containing the node's current inputs.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Any: A hash of inputs for caching, or a random number to force recalculation</span>
|
|
<span class="sd"> when time-dependent functions are detected.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # This would typically be called by ComfyUI</span>
|
|
<span class="sd"> result = FormatString.IS_CHANGED(template="Hello {name}", template_type="Simple")</span>
|
|
<span class="sd"> # Returns hash of inputs for proper caching</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # Test with Simple template</span>
|
|
<span class="sd"> >>> result = FormatString.IS_CHANGED(template="Hello {name}", template_type="Simple")</span>
|
|
<span class="sd"> >>> assert isinstance(result, dict)</span>
|
|
<span class="sd"> >>> # Test with Jinja2 template containing datetime function call</span>
|
|
<span class="sd"> >>> result = FormatString.IS_CHANGED(template="Time: {{ datetime.now() }}", template_type="Jinja2")</span>
|
|
<span class="sd"> >>> assert isinstance(result, int) # Should return a random int to force recalculation</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">template</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
<span class="n">template_type</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template_type"</span><span class="p">,</span> <span class="s2">"Simple"</span><span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">template</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Empty template, returning kwargs for caching"</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">kwargs</span>
|
|
|
|
<span class="n">template_preview</span> <span class="o">=</span> <span class="n">template</span><span class="p">[:</span><span class="mi">50</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">></span> <span class="mi">50</span> <span class="k">else</span> <span class="n">template</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="sa">f</span><span class="s2">"IS_CHANGED called - template_type: </span><span class="si">{</span><span class="n">template_type</span><span class="si">}</span><span class="s2">, template: </span><span class="si">{</span><span class="n">template_preview</span><span class="si">}</span><span class="s2">..."</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Check for time-dependent function calls in Jinja2 templates</span>
|
|
<span class="k">if</span> <span class="n">template_type</span> <span class="o">==</span> <span class="s2">"Jinja2"</span><span class="p">:</span>
|
|
<span class="c1"># Look for actual function calls like datetime.now(), now(), or time_now()</span>
|
|
<span class="c1"># These are time-dependent and should force recalculation each time</span>
|
|
<span class="n">time_function_pattern</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"\b(datetime\.now|now|time_now)\s*\("</span>
|
|
<span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">time_function_pattern</span><span class="p">,</span> <span class="n">template</span><span class="p">):</span>
|
|
<span class="c1"># Force recalculation for time-dependent templates</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Time-dependent function detected in Jinja2 template, forcing recalculation"</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">random</span><span class="o">.</span><span class="n">randrange</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Return kwargs for proper caching - ComfyUI will hash this</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"No time-dependent functions, using cached result if inputs unchanged"</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">kwargs</span>
|
|
|
|
<span class="nd">@staticmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">_extract_keys</span><span class="p">(</span><span class="n">template</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Extract variable names from a template string.</span>
|
|
|
|
<span class="sd"> This method parses a template string to find all variable names used in it,</span>
|
|
<span class="sd"> supporting both Python's format style {var} and Jinja2's {{ var }} syntax.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> template (str): The template string to parse.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> List[str]: A list of unique variable names found in the template.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> template = "Hello {name}, today is {{ datetime.now() }}"</span>
|
|
<span class="sd"> keys = FormatString._extract_keys(template)</span>
|
|
<span class="sd"> print(keys) # Outputs: ['name']</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # Test simple format</span>
|
|
<span class="sd"> >>> keys = FormatString._extract_keys("Hello {name}, your age is {age}")</span>
|
|
<span class="sd"> >>> assert sorted(keys) == ['age', 'name']</span>
|
|
<span class="sd"> >>> # Test Jinja2 format</span>
|
|
<span class="sd"> >>> keys = FormatString._extract_keys("Hello {{ name }}, {{ greeting | upper }}")</span>
|
|
<span class="sd"> >>> assert sorted(keys) == ['greeting', 'name']</span>
|
|
<span class="sd"> >>> # Test mixed format</span>
|
|
<span class="sd"> >>> keys = FormatString._extract_keys("Hello {name}, today is {{ date }}")</span>
|
|
<span class="sd"> >>> assert sorted(keys) == ['date', 'name']</span>
|
|
<span class="sd"> >>> # Test with additional context (should be excluded)</span>
|
|
<span class="sd"> >>> keys = FormatString._extract_keys("Time: {{ datetime.now() }}")</span>
|
|
<span class="sd"> >>> assert keys == []</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">variables</span> <span class="o">=</span> <span class="p">[]</span>
|
|
<span class="n">seen</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">add_var</span><span class="p">(</span><span class="n">var</span><span class="p">):</span>
|
|
<span class="n">var</span> <span class="o">=</span> <span class="n">var</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"|"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"."</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
|
<span class="k">if</span> <span class="n">var</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">seen</span> <span class="ow">and</span> <span class="n">var</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">additional_context</span><span class="p">:</span>
|
|
<span class="n">seen</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
|
|
<span class="n">variables</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Extract variables from Jinja2 expressions {{ }}</span>
|
|
<span class="k">for</span> <span class="n">match</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span>
|
|
<span class="sa">r</span><span class="s2">"\{\{\s*([\w.]+)(?:\s*\|[\w\s]+)?(?:\.[^\(\)]+\(\))?\s*\}\}"</span><span class="p">,</span> <span class="n">template</span>
|
|
<span class="p">):</span>
|
|
<span class="n">add_var</span><span class="p">(</span><span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
|
|
|
|
<span class="c1"># Extract variables from f-string style { }</span>
|
|
<span class="k">for</span> <span class="n">match</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\{(\w+)\}"</span><span class="p">,</span> <span class="n">template</span><span class="p">):</span>
|
|
<span class="n">add_var</span><span class="p">(</span><span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
|
|
|
|
<span class="c1"># Extract variables from Jinja2 control structures {% %}</span>
|
|
<span class="k">for</span> <span class="n">structure</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\{%.*?%\}"</span><span class="p">,</span> <span class="n">template</span><span class="p">):</span>
|
|
<span class="k">for</span> <span class="n">var</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="sa">r</span><span class="s2">"\b(\w+)\|\b"</span><span class="p">,</span> <span class="n">structure</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">)):</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">var</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"end"</span><span class="p">)</span> <span class="ow">and</span> <span class="n">var</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">{</span>
|
|
<span class="s2">"if"</span><span class="p">,</span>
|
|
<span class="s2">"else"</span><span class="p">,</span>
|
|
<span class="s2">"elif"</span><span class="p">,</span>
|
|
<span class="s2">"for"</span><span class="p">,</span>
|
|
<span class="s2">"in"</span><span class="p">,</span>
|
|
<span class="p">}:</span>
|
|
<span class="n">add_var</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="n">variables</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">format_string</span><span class="p">(</span>
|
|
<span class="bp">cls</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">template</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">save_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">unique_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">""</span><span class="p">,</span>
|
|
<span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
|
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Format a string using the specified template type and variables.</span>
|
|
|
|
<span class="sd"> This is the main method executed by the node. It formats the template using either</span>
|
|
<span class="sd"> Python's str.format() or Jinja2 templating, and optionally saves the state to disk.</span>
|
|
<span class="sd"> The node is OUTPUT_NODE=True so the formatted string also renders as a read-only</span>
|
|
<span class="sd"> text display directly on the node (no separate Show Text node needed).</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> template_type (str): Either "Simple" or "Jinja2" to specify the template engine.</span>
|
|
<span class="sd"> template (str): The template string to format.</span>
|
|
<span class="sd"> save_path (str): Optional path to save the node state. If empty, state is not saved.</span>
|
|
<span class="sd"> unique_id (str): The unique identifier for this node instance (passed by ComfyUI).</span>
|
|
<span class="sd"> **kwargs: Variable keyword arguments that provide values for template variables.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: ``{"ui": {"text": [formatted_string]}, "result": result}`` where</span>
|
|
<span class="sd"> ``result`` is a tuple containing the formatted string, the save path,</span>
|
|
<span class="sd"> followed by the values of input variables (in order).</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Simple template example</span>
|
|
<span class="sd"> ret = FormatString.format_string(</span>
|
|
<span class="sd"> template_type="Simple",</span>
|
|
<span class="sd"> template="Hello {name}, you are {age} years old",</span>
|
|
<span class="sd"> save_path="",</span>
|
|
<span class="sd"> unique_id="123",</span>
|
|
<span class="sd"> name="Alice",</span>
|
|
<span class="sd"> age="30"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(ret["result"]) # Outputs: ('Hello Alice, you are 30 years old', '', 'Alice', '30')</span>
|
|
|
|
<span class="sd"> # Jinja2 template example</span>
|
|
<span class="sd"> ret = FormatString.format_string(</span>
|
|
<span class="sd"> template_type="Jinja2",</span>
|
|
<span class="sd"> template="Hello {{ name }}, today is {{ datetime.now().strftime('%A') }}",</span>
|
|
<span class="sd"> save_path="",</span>
|
|
<span class="sd"> unique_id="124",</span>
|
|
<span class="sd"> name="Bob"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(ret["result"]) # Outputs: ('Hello Bob, today is Wednesday', '', 'Bob')</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # Test simple format</span>
|
|
<span class="sd"> >>> ret = FormatString.format_string(</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}, you are {age} years old",</span>
|
|
<span class="sd"> ... save_path="",</span>
|
|
<span class="sd"> ... name="Alice",</span>
|
|
<span class="sd"> ... age="30"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> result = ret["result"]</span>
|
|
<span class="sd"> >>> assert result[0] == "Hello Alice, you are 30 years old"</span>
|
|
<span class="sd"> >>> assert result[1] == ""</span>
|
|
<span class="sd"> >>> assert result[2] == "Alice"</span>
|
|
<span class="sd"> >>> assert result[3] == "30"</span>
|
|
<span class="sd"> >>> assert ret["ui"]["text"][0] == "Hello Alice, you are 30 years old"</span>
|
|
<span class="sd"> >>></span>
|
|
<span class="sd"> >>> # Test Jinja2 format with datetime (can't test exact output due to time dependency)</span>
|
|
<span class="sd"> >>> ret = FormatString.format_string(</span>
|
|
<span class="sd"> ... template_type="Jinja2",</span>
|
|
<span class="sd"> ... template="Name: {{ name }}",</span>
|
|
<span class="sd"> ... save_path="",</span>
|
|
<span class="sd"> ... name="Bob"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> result = ret["result"]</span>
|
|
<span class="sd"> >>> assert result[0] == "Name: Bob"</span>
|
|
<span class="sd"> >>> assert result[1] == ""</span>
|
|
<span class="sd"> >>> assert result[2] == "Bob"</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Formatting string - type: </span><span class="si">%s</span><span class="s2">, unique_id: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">unique_id</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Template: </span><span class="si">%.100s</span><span class="s2">..."</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
|
|
<span class="n">keys</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_extract_keys</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Extracted variables: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
|
|
<span class="n">input_vals</span> <span class="o">=</span> <span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">=</span><span class="si">{</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="s1">''</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Input values: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">input_vals</span><span class="p">)</span>
|
|
|
|
<span class="c1"># CRITICAL: Update RETURN_TYPES/RETURN_NAMES before execution to ensure they match our return tuple</span>
|
|
<span class="c1"># This is necessary because update_widget might not have been called yet (e.g., on workflow load)</span>
|
|
<span class="k">if</span> <span class="n">unique_id</span><span class="p">:</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">update_widget</span><span class="p">(</span><span class="n">unique_id</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updated RETURN_TYPES for node </span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">unique_id</span><span class="p">,</span> <span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="n">template_type</span> <span class="o">==</span> <span class="s2">"Simple"</span><span class="p">:</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Simple format successful: </span><span class="si">%.50s</span><span class="s2">"</span><span class="p">,</span> <span class="n">formatted_string</span><span class="p">)</span>
|
|
<span class="k">except</span> <span class="ne">KeyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Missing variable in Simple template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="k">raise</span> <span class="c1"># Re-raise for proper error handling</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error in Simple template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error: </span><span class="si">{</span><span class="n">error_msg</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="k">else</span><span class="p">:</span> <span class="c1"># Jinja2</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">jinja_template</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">jinja_env</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="c1"># Combine user-provided kwargs with additional_context</span>
|
|
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="o">**</span><span class="bp">cls</span><span class="o">.</span><span class="n">additional_context</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">}</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">jinja_template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="o">**</span><span class="n">context</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Jinja2 format successful, result length: </span><span class="si">%d</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">formatted_string</span><span class="p">)</span>
|
|
<span class="p">)</span>
|
|
<span class="k">except</span> <span class="n">exceptions</span><span class="o">.</span><span class="n">TemplateSyntaxError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error in Jinja2 template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">error_msg</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error rendering Jinja2 template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">error_msg</span>
|
|
|
|
<span class="c1"># Save the state</span>
|
|
<span class="n">save_data</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="n">template_type</span><span class="p">,</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="n">template</span><span class="p">,</span>
|
|
<span class="s2">"inputs"</span><span class="p">:</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">},</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="s2">""</span>
|
|
<span class="k">if</span> <span class="n">save_path</span><span class="p">:</span>
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
|
<span class="n">folder_paths</span><span class="o">.</span><span class="n">get_output_directory</span><span class="p">(),</span> <span class="n">save_path</span>
|
|
<span class="p">)</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">actual_save_path</span><span class="p">),</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">actual_save_path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">save_data</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Node state saved to: </span><span class="si">{</span><span class="n">actual_save_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Error saving node state: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="s2">""</span> <span class="c1"># Reset save_path if saving failed</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"No save_path provided, skipping state save"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Return formatted_string and saved_file_path FIRST (fixed positions 0,1),</span>
|
|
<span class="c1"># then all input values (for chaining)</span>
|
|
<span class="c1"># The order must match what was set in update_widget's RETURN_TYPES/RETURN_NAMES</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span>
|
|
<span class="n">formatted_string</span><span class="p">,</span>
|
|
<span class="n">actual_save_path</span><span class="p">,</span>
|
|
<span class="p">)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="s2">""</span><span class="p">))</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">)</span>
|
|
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Returning </span><span class="si">%d</span><span class="s2"> outputs: keys=</span><span class="si">%s</span><span class="s2">, save_path=</span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">),</span>
|
|
<span class="n">keys</span><span class="p">,</span>
|
|
<span class="n">actual_save_path</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Full result tuple length: </span><span class="si">%d</span><span class="s2">, expected: </span><span class="si">%d</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">{</span>
|
|
<span class="s2">"ui"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"text"</span><span class="p">:</span> <span class="p">[</span><span class="n">formatted_string</span><span class="p">]},</span>
|
|
<span class="s2">"result"</span><span class="p">:</span> <span class="n">result</span><span class="p">,</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">update_widget</span><span class="p">(</span>
|
|
<span class="bp">cls</span><span class="p">,</span> <span class="n">node_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">template_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">template</span><span class="p">:</span> <span class="nb">str</span>
|
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Update a node's widget configuration based on the template.</span>
|
|
|
|
<span class="sd"> This method is called when a template is changed to dynamically update the</span>
|
|
<span class="sd"> node's inputs and outputs based on the variables detected in the template.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> node_id (str): The unique identifier of the node instance.</span>
|
|
<span class="sd"> template_type (str): The template type ("Simple" or "Jinja2").</span>
|
|
<span class="sd"> template (str): The template string.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: Updated configuration for the node.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Called via ComfyUI's web API when template changes</span>
|
|
<span class="sd"> config = FormatString.update_widget(</span>
|
|
<span class="sd"> node_id="node_123",</span>
|
|
<span class="sd"> template_type="Simple",</span>
|
|
<span class="sd"> template="Hello {name}, you are {age} years old"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(config["inputs"]) # Shows inputs including 'name' and 'age'</span>
|
|
<span class="sd"> print(config["outputs"]) # Shows outputs including extracted variables</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> config = FormatString.update_widget(</span>
|
|
<span class="sd"> ... node_id="test_node",</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}, you are {age} years old"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> assert "name" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert "age" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert len(config["outputs"]) == 4 # formatted_string, saved_file_path, name, age</span>
|
|
<span class="sd"> >>> assert config["outputs"][0]["name"] == "formatted_string"</span>
|
|
<span class="sd"> >>> assert config["outputs"][1]["name"] == "saved_file_path"</span>
|
|
<span class="sd"> >>> assert config["outputs"][2]["name"] == "name"</span>
|
|
<span class="sd"> >>> assert config["outputs"][3]["name"] == "age"</span>
|
|
<span class="sd"> >>> # Check that RETURN_TYPES and RETURN_NAMES are updated</span>
|
|
<span class="sd"> >>> assert len(FormatString.RETURN_TYPES) == 4</span>
|
|
<span class="sd"> >>> assert len(FormatString.RETURN_NAMES) == 4</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[0] == "formatted_string"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[1] == "saved_file_path"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[2] == "name"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[3] == "age"</span>
|
|
<span class="sd"> >>> # Check that node config is stored</span>
|
|
<span class="sd"> >>> assert "test_node" in FormatString.node_configs</span>
|
|
<span class="sd"> >>> assert FormatString.node_configs["test_node"] == config</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updating widget config - node_id: </span><span class="si">%s</span><span class="s2">, template_type: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">node_id</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Template: </span><span class="si">%.100s</span><span class="s2">..."</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
|
|
<span class="n">keys</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_extract_keys</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Extracted </span><span class="si">%d</span><span class="s2"> variables from template: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">),</span> <span class="n">keys</span><span class="p">)</span>
|
|
|
|
<span class="n">config</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s2">"inputs"</span><span class="p">:</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"Simple"</span><span class="p">,</span> <span class="s2">"Jinja2"</span><span class="p">],),</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"multiline"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}),</span>
|
|
<span class="s2">"save_path"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">}),</span>
|
|
<span class="p">},</span>
|
|
<span class="s2">"outputs"</span><span class="p">:</span> <span class="p">[],</span>
|
|
<span class="p">}</span>
|
|
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"inputs"</span><span class="p">][</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">})</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">"name"</span><span class="p">:</span> <span class="n">key</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">})</span>
|
|
|
|
<span class="c1"># Add formatted_string and saved_file_path at the START of outputs (fixed positions)</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
|
|
<span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"formatted_string"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">},</span>
|
|
<span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"saved_file_path"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">},</span>
|
|
<span class="p">]</span> <span class="o">+</span> <span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span>
|
|
|
|
<span class="c1"># Update RETURN_TYPES and RETURN_NAMES dynamically</span>
|
|
<span class="c1"># formatted_string and saved_file_path are ALWAYS first two outputs (positions 0,1)</span>
|
|
<span class="c1"># This allows passing through variable values for chaining</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="s2">"STRING"</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,)</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_NAMES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"formatted_string"</span><span class="p">,</span> <span class="s2">"saved_file_path"</span><span class="p">)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">OUTPUT_IS_LIST</span> <span class="o">=</span> <span class="p">(</span><span class="kc">False</span><span class="p">,)</span> <span class="o">*</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span>
|
|
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updated RETURN_TYPES to </span><span class="si">%d</span><span class="s2"> outputs: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="nb">len</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span><span class="p">),</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_NAMES</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Store the configuration for this specific node</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">node_configs</span><span class="p">[</span><span class="n">node_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Stored config for node </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">node_id</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="n">config</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_node_config</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Get the configuration for a specific node instance.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> node_id (str): The unique identifier of the node instance.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: The configuration for the specified node, or an empty dict if not found.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # After updating a node's configuration</span>
|
|
<span class="sd"> config = FormatString.get_node_config("node_123")</span>
|
|
<span class="sd"> print(config) # Shows the stored configuration for node_123</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # First create a config</span>
|
|
<span class="sd"> >>> _ = FormatString.update_widget(</span>
|
|
<span class="sd"> ... node_id="test_node_2",</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> # Then retrieve it</span>
|
|
<span class="sd"> >>> config = FormatString.get_node_config("test_node_2")</span>
|
|
<span class="sd"> >>> assert "inputs" in config</span>
|
|
<span class="sd"> >>> assert "outputs" in config</span>
|
|
<span class="sd"> >>> assert "name" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert len(config["outputs"]) == 3 # name, formatted_string, saved_file_path</span>
|
|
<span class="sd"> >>> # Test non-existent node</span>
|
|
<span class="sd"> >>> empty_config = FormatString.get_node_config("non_existent_node")</span>
|
|
<span class="sd"> >>> assert empty_config == {}</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">node_configs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">node_id</span><span class="p">,</span> <span class="p">{})</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">load_node_state</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Load a previously saved node state from disk.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> file_path (str): Path to the saved node state JSON file.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: The loaded node state, or an empty dict if loading failed.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Load a previously saved state</span>
|
|
<span class="sd"> state = FormatString.load_node_state("/path/to/saved_state.json")</span>
|
|
<span class="sd"> print(state["template"]) # Shows the saved template</span>
|
|
<span class="sd"> print(state["inputs"]) # Shows the saved input values</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> import tempfile</span>
|
|
<span class="sd"> >>> import json</span>
|
|
<span class="sd"> >>> import os</span>
|
|
<span class="sd"> >>> # Create a temporary file with test data</span>
|
|
<span class="sd"> >>> test_data = {</span>
|
|
<span class="sd"> ... "template_type": "Simple",</span>
|
|
<span class="sd"> ... "template": "Hello {name}",</span>
|
|
<span class="sd"> ... "inputs": {"name": "Alice"}</span>
|
|
<span class="sd"> ... }</span>
|
|
<span class="sd"> >>> with tempfile.NamedTemporaryFile(delete=False, mode="w") as temp:</span>
|
|
<span class="sd"> ... json.dump(test_data, temp)</span>
|
|
<span class="sd"> ... temp_path = temp.name</span>
|
|
<span class="sd"> >>> # Test loading the file</span>
|
|
<span class="sd"> >>> state = FormatString.load_node_state(temp_path)</span>
|
|
<span class="sd"> >>> assert state["template_type"] == "Simple"</span>
|
|
<span class="sd"> >>> assert state["template"] == "Hello {name}"</span>
|
|
<span class="sd"> >>> assert state["inputs"]["name"] == "Alice"</span>
|
|
<span class="sd"> >>> # Clean up</span>
|
|
<span class="sd"> >>> os.unlink(temp_path)</span>
|
|
<span class="sd"> >>> # Test loading non-existent file</span>
|
|
<span class="sd"> >>> empty_state = FormatString.load_node_state("non_existent_file.json")</span>
|
|
<span class="sd"> >>> assert empty_state == {}</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">load_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">load_data</span>
|
|
<span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="p">{}</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Failed to load node state from </span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">file_path</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">{}</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
|
|
|
|
|
|
<div class="doc doc-children">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.INPUT_TYPES" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">INPUT_TYPES</span><span class="p">()</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Define the input types for the FormatString node.</p>
|
|
<p>This method is called by ComfyUI to determine what inputs the node should have.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code><span title="typing.Dict">Dict</span>[<span title="str">str</span>, <span title="typing.Any">Any</span>]</code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Dict[str, Any]: Dictionary defining the node's inputs, including template_type,
|
|
template, save_path, and a hidden unique_id.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="n">input_types</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">INPUT_TYPES</span><span class="p">()</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">input_types</span><span class="p">[</span><span class="s2">"required"</span><span class="p">][</span><span class="s2">"template_type"</span><span class="p">])</span> <span class="c1"># Outputs: (["Simple", "Jinja2"],)</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> input_types = FormatString.INPUT_TYPES()
|
|
>>> assert "required" in input_types
|
|
>>> assert "template_type" in input_types["required"]
|
|
>>> assert "template" in input_types["required"]
|
|
>>> assert "save_path" in input_types["required"]
|
|
>>> assert "hidden" in input_types
|
|
>>> assert "unique_id" in input_types["hidden"]
|
|
>>> assert input_types["required"]["template_type"] == (["Simple", "Jinja2"],)
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">116</span>
|
|
<span class="normal">117</span>
|
|
<span class="normal">118</span>
|
|
<span class="normal">119</span>
|
|
<span class="normal">120</span>
|
|
<span class="normal">121</span>
|
|
<span class="normal">122</span>
|
|
<span class="normal">123</span>
|
|
<span class="normal">124</span>
|
|
<span class="normal">125</span>
|
|
<span class="normal">126</span>
|
|
<span class="normal">127</span>
|
|
<span class="normal">128</span>
|
|
<span class="normal">129</span>
|
|
<span class="normal">130</span>
|
|
<span class="normal">131</span>
|
|
<span class="normal">132</span>
|
|
<span class="normal">133</span>
|
|
<span class="normal">134</span>
|
|
<span class="normal">135</span>
|
|
<span class="normal">136</span>
|
|
<span class="normal">137</span>
|
|
<span class="normal">138</span>
|
|
<span class="normal">139</span>
|
|
<span class="normal">140</span>
|
|
<span class="normal">141</span>
|
|
<span class="normal">142</span>
|
|
<span class="normal">143</span>
|
|
<span class="normal">144</span>
|
|
<span class="normal">145</span>
|
|
<span class="normal">146</span>
|
|
<span class="normal">147</span>
|
|
<span class="normal">148</span>
|
|
<span class="normal">149</span>
|
|
<span class="normal">150</span>
|
|
<span class="normal">151</span>
|
|
<span class="normal">152</span>
|
|
<span class="normal">153</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">INPUT_TYPES</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Define the input types for the FormatString node.</span>
|
|
|
|
<span class="sd"> This method is called by ComfyUI to determine what inputs the node should have.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: Dictionary defining the node's inputs, including template_type,</span>
|
|
<span class="sd"> template, save_path, and a hidden unique_id.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> input_types = FormatString.INPUT_TYPES()</span>
|
|
<span class="sd"> print(input_types["required"]["template_type"]) # Outputs: (["Simple", "Jinja2"],)</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> input_types = FormatString.INPUT_TYPES()</span>
|
|
<span class="sd"> >>> assert "required" in input_types</span>
|
|
<span class="sd"> >>> assert "template_type" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "template" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "save_path" in input_types["required"]</span>
|
|
<span class="sd"> >>> assert "hidden" in input_types</span>
|
|
<span class="sd"> >>> assert "unique_id" in input_types["hidden"]</span>
|
|
<span class="sd"> >>> assert input_types["required"]["template_type"] == (["Simple", "Jinja2"],)</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="p">{</span>
|
|
<span class="s2">"required"</span><span class="p">:</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"Simple"</span><span class="p">,</span> <span class="s2">"Jinja2"</span><span class="p">],),</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"multiline"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}),</span>
|
|
<span class="s2">"save_path"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">}),</span>
|
|
<span class="p">},</span>
|
|
<span class="s2">"hidden"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"unique_id"</span><span class="p">:</span> <span class="s2">"UNIQUE_ID"</span><span class="p">},</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.IS_CHANGED" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">IS_CHANGED</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Determine if the node should be re-executed based on input changes.</p>
|
|
<p>This method is called by ComfyUI to check if the node needs to be re-calculated
|
|
due to changes in its inputs. It forces recalculation when Jinja2 templates
|
|
contain time-dependent function calls (e.g., datetime.now(), time_now()).</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>**kwargs</code>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Keyword arguments containing the node's current inputs.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<code>{}</code>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th> <th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td><code>Any</code></td> <td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>A hash of inputs for caching, or a random number to force recalculation
|
|
when time-dependent functions are detected.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="c1"># This would typically be called by ComfyUI</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">IS_CHANGED</span><span class="p">(</span><span class="n">template</span><span class="o">=</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span><span class="p">,</span> <span class="n">template_type</span><span class="o">=</span><span class="s2">"Simple"</span><span class="p">)</span>
|
|
<span class="c1"># Returns hash of inputs for proper caching</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> # Test with Simple template
|
|
>>> result = FormatString.IS_CHANGED(template="Hello {name}", template_type="Simple")
|
|
>>> assert isinstance(result, dict)
|
|
>>> # Test with Jinja2 template containing datetime function call
|
|
>>> result = FormatString.IS_CHANGED(template="Time: {{ datetime.now() }}", template_type="Jinja2")
|
|
>>> assert isinstance(result, int) # Should return a random int to force recalculation
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">155</span>
|
|
<span class="normal">156</span>
|
|
<span class="normal">157</span>
|
|
<span class="normal">158</span>
|
|
<span class="normal">159</span>
|
|
<span class="normal">160</span>
|
|
<span class="normal">161</span>
|
|
<span class="normal">162</span>
|
|
<span class="normal">163</span>
|
|
<span class="normal">164</span>
|
|
<span class="normal">165</span>
|
|
<span class="normal">166</span>
|
|
<span class="normal">167</span>
|
|
<span class="normal">168</span>
|
|
<span class="normal">169</span>
|
|
<span class="normal">170</span>
|
|
<span class="normal">171</span>
|
|
<span class="normal">172</span>
|
|
<span class="normal">173</span>
|
|
<span class="normal">174</span>
|
|
<span class="normal">175</span>
|
|
<span class="normal">176</span>
|
|
<span class="normal">177</span>
|
|
<span class="normal">178</span>
|
|
<span class="normal">179</span>
|
|
<span class="normal">180</span>
|
|
<span class="normal">181</span>
|
|
<span class="normal">182</span>
|
|
<span class="normal">183</span>
|
|
<span class="normal">184</span>
|
|
<span class="normal">185</span>
|
|
<span class="normal">186</span>
|
|
<span class="normal">187</span>
|
|
<span class="normal">188</span>
|
|
<span class="normal">189</span>
|
|
<span class="normal">190</span>
|
|
<span class="normal">191</span>
|
|
<span class="normal">192</span>
|
|
<span class="normal">193</span>
|
|
<span class="normal">194</span>
|
|
<span class="normal">195</span>
|
|
<span class="normal">196</span>
|
|
<span class="normal">197</span>
|
|
<span class="normal">198</span>
|
|
<span class="normal">199</span>
|
|
<span class="normal">200</span>
|
|
<span class="normal">201</span>
|
|
<span class="normal">202</span>
|
|
<span class="normal">203</span>
|
|
<span class="normal">204</span>
|
|
<span class="normal">205</span>
|
|
<span class="normal">206</span>
|
|
<span class="normal">207</span>
|
|
<span class="normal">208</span>
|
|
<span class="normal">209</span>
|
|
<span class="normal">210</span>
|
|
<span class="normal">211</span>
|
|
<span class="normal">212</span>
|
|
<span class="normal">213</span>
|
|
<span class="normal">214</span>
|
|
<span class="normal">215</span>
|
|
<span class="normal">216</span>
|
|
<span class="normal">217</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">IS_CHANGED</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Determine if the node should be re-executed based on input changes.</span>
|
|
|
|
<span class="sd"> This method is called by ComfyUI to check if the node needs to be re-calculated</span>
|
|
<span class="sd"> due to changes in its inputs. It forces recalculation when Jinja2 templates</span>
|
|
<span class="sd"> contain time-dependent function calls (e.g., datetime.now(), time_now()).</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> **kwargs: Keyword arguments containing the node's current inputs.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Any: A hash of inputs for caching, or a random number to force recalculation</span>
|
|
<span class="sd"> when time-dependent functions are detected.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # This would typically be called by ComfyUI</span>
|
|
<span class="sd"> result = FormatString.IS_CHANGED(template="Hello {name}", template_type="Simple")</span>
|
|
<span class="sd"> # Returns hash of inputs for proper caching</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # Test with Simple template</span>
|
|
<span class="sd"> >>> result = FormatString.IS_CHANGED(template="Hello {name}", template_type="Simple")</span>
|
|
<span class="sd"> >>> assert isinstance(result, dict)</span>
|
|
<span class="sd"> >>> # Test with Jinja2 template containing datetime function call</span>
|
|
<span class="sd"> >>> result = FormatString.IS_CHANGED(template="Time: {{ datetime.now() }}", template_type="Jinja2")</span>
|
|
<span class="sd"> >>> assert isinstance(result, int) # Should return a random int to force recalculation</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">template</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
<span class="n">template_type</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template_type"</span><span class="p">,</span> <span class="s2">"Simple"</span><span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">template</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Empty template, returning kwargs for caching"</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">kwargs</span>
|
|
|
|
<span class="n">template_preview</span> <span class="o">=</span> <span class="n">template</span><span class="p">[:</span><span class="mi">50</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">></span> <span class="mi">50</span> <span class="k">else</span> <span class="n">template</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="sa">f</span><span class="s2">"IS_CHANGED called - template_type: </span><span class="si">{</span><span class="n">template_type</span><span class="si">}</span><span class="s2">, template: </span><span class="si">{</span><span class="n">template_preview</span><span class="si">}</span><span class="s2">..."</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Check for time-dependent function calls in Jinja2 templates</span>
|
|
<span class="k">if</span> <span class="n">template_type</span> <span class="o">==</span> <span class="s2">"Jinja2"</span><span class="p">:</span>
|
|
<span class="c1"># Look for actual function calls like datetime.now(), now(), or time_now()</span>
|
|
<span class="c1"># These are time-dependent and should force recalculation each time</span>
|
|
<span class="n">time_function_pattern</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"\b(datetime\.now|now|time_now)\s*\("</span>
|
|
<span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">time_function_pattern</span><span class="p">,</span> <span class="n">template</span><span class="p">):</span>
|
|
<span class="c1"># Force recalculation for time-dependent templates</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Time-dependent function detected in Jinja2 template, forcing recalculation"</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">random</span><span class="o">.</span><span class="n">randrange</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">maxsize</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Return kwargs for proper caching - ComfyUI will hash this</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"No time-dependent functions, using cached result if inputs unchanged"</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">kwargs</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.format_string" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">format_string</span><span class="p">(</span><span class="n">template_type</span><span class="p">,</span> <span class="n">template</span><span class="p">,</span> <span class="n">save_path</span><span class="p">,</span> <span class="n">unique_id</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Format a string using the specified template type and variables.</p>
|
|
<p>This is the main method executed by the node. It formats the template using either
|
|
Python's str.format() or Jinja2 templating, and optionally saves the state to disk.
|
|
The node is OUTPUT_NODE=True so the formatted string also renders as a read-only
|
|
text display directly on the node (no separate Show Text node needed).</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>template_type</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Either "Simple" or "Jinja2" to specify the template engine.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>template</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The template string to format.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>save_path</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Optional path to save the node state. If empty, state is not saved.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>unique_id</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The unique identifier for this node instance (passed by ComfyUI).</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<code>''</code>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>**kwargs</code>
|
|
</td>
|
|
<td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Variable keyword arguments that provide values for template variables.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<code>{}</code>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code><span title="typing.Dict">Dict</span>[<span title="str">str</span>, <span title="typing.Any">Any</span>]</code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Dict[str, Any]: <code>{"ui": {"text": [formatted_string]}, "result": result}</code> where
|
|
<code>result</code> is a tuple containing the formatted string, the save path,
|
|
followed by the values of input variables (in order).</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="c1"># Simple template example</span>
|
|
<span class="n">ret</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">format_string</span><span class="p">(</span>
|
|
<span class="n">template_type</span><span class="o">=</span><span class="s2">"Simple"</span><span class="p">,</span>
|
|
<span class="n">template</span><span class="o">=</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">, you are </span><span class="si">{age}</span><span class="s2"> years old"</span><span class="p">,</span>
|
|
<span class="n">save_path</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span>
|
|
<span class="n">unique_id</span><span class="o">=</span><span class="s2">"123"</span><span class="p">,</span>
|
|
<span class="n">name</span><span class="o">=</span><span class="s2">"Alice"</span><span class="p">,</span>
|
|
<span class="n">age</span><span class="o">=</span><span class="s2">"30"</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">ret</span><span class="p">[</span><span class="s2">"result"</span><span class="p">])</span> <span class="c1"># Outputs: ('Hello Alice, you are 30 years old', '', 'Alice', '30')</span>
|
|
|
|
<span class="c1"># Jinja2 template example</span>
|
|
<span class="n">ret</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">format_string</span><span class="p">(</span>
|
|
<span class="n">template_type</span><span class="o">=</span><span class="s2">"Jinja2"</span><span class="p">,</span>
|
|
<span class="n">template</span><span class="o">=</span><span class="s2">"Hello {{ name }}, today is {{ datetime.now().strftime('%A') }}"</span><span class="p">,</span>
|
|
<span class="n">save_path</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span>
|
|
<span class="n">unique_id</span><span class="o">=</span><span class="s2">"124"</span><span class="p">,</span>
|
|
<span class="n">name</span><span class="o">=</span><span class="s2">"Bob"</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">ret</span><span class="p">[</span><span class="s2">"result"</span><span class="p">])</span> <span class="c1"># Outputs: ('Hello Bob, today is Wednesday', '', 'Bob')</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> # Test simple format
|
|
>>> ret = FormatString.format_string(
|
|
... template_type="Simple",
|
|
... template="Hello {name}, you are {age} years old",
|
|
... save_path="",
|
|
... name="Alice",
|
|
... age="30"
|
|
... )
|
|
>>> result = ret["result"]
|
|
>>> assert result[0] == "Hello Alice, you are 30 years old"
|
|
>>> assert result[1] == ""
|
|
>>> assert result[2] == "Alice"
|
|
>>> assert result[3] == "30"
|
|
>>> assert ret["ui"]["text"][0] == "Hello Alice, you are 30 years old"
|
|
>>>
|
|
>>> # Test Jinja2 format with datetime (can't test exact output due to time dependency)
|
|
>>> ret = FormatString.format_string(
|
|
... template_type="Jinja2",
|
|
... template="Name: {{ name }}",
|
|
... save_path="",
|
|
... name="Bob"
|
|
... )
|
|
>>> result = ret["result"]
|
|
>>> assert result[0] == "Name: Bob"
|
|
>>> assert result[1] == ""
|
|
>>> assert result[2] == "Bob"
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">290</span>
|
|
<span class="normal">291</span>
|
|
<span class="normal">292</span>
|
|
<span class="normal">293</span>
|
|
<span class="normal">294</span>
|
|
<span class="normal">295</span>
|
|
<span class="normal">296</span>
|
|
<span class="normal">297</span>
|
|
<span class="normal">298</span>
|
|
<span class="normal">299</span>
|
|
<span class="normal">300</span>
|
|
<span class="normal">301</span>
|
|
<span class="normal">302</span>
|
|
<span class="normal">303</span>
|
|
<span class="normal">304</span>
|
|
<span class="normal">305</span>
|
|
<span class="normal">306</span>
|
|
<span class="normal">307</span>
|
|
<span class="normal">308</span>
|
|
<span class="normal">309</span>
|
|
<span class="normal">310</span>
|
|
<span class="normal">311</span>
|
|
<span class="normal">312</span>
|
|
<span class="normal">313</span>
|
|
<span class="normal">314</span>
|
|
<span class="normal">315</span>
|
|
<span class="normal">316</span>
|
|
<span class="normal">317</span>
|
|
<span class="normal">318</span>
|
|
<span class="normal">319</span>
|
|
<span class="normal">320</span>
|
|
<span class="normal">321</span>
|
|
<span class="normal">322</span>
|
|
<span class="normal">323</span>
|
|
<span class="normal">324</span>
|
|
<span class="normal">325</span>
|
|
<span class="normal">326</span>
|
|
<span class="normal">327</span>
|
|
<span class="normal">328</span>
|
|
<span class="normal">329</span>
|
|
<span class="normal">330</span>
|
|
<span class="normal">331</span>
|
|
<span class="normal">332</span>
|
|
<span class="normal">333</span>
|
|
<span class="normal">334</span>
|
|
<span class="normal">335</span>
|
|
<span class="normal">336</span>
|
|
<span class="normal">337</span>
|
|
<span class="normal">338</span>
|
|
<span class="normal">339</span>
|
|
<span class="normal">340</span>
|
|
<span class="normal">341</span>
|
|
<span class="normal">342</span>
|
|
<span class="normal">343</span>
|
|
<span class="normal">344</span>
|
|
<span class="normal">345</span>
|
|
<span class="normal">346</span>
|
|
<span class="normal">347</span>
|
|
<span class="normal">348</span>
|
|
<span class="normal">349</span>
|
|
<span class="normal">350</span>
|
|
<span class="normal">351</span>
|
|
<span class="normal">352</span>
|
|
<span class="normal">353</span>
|
|
<span class="normal">354</span>
|
|
<span class="normal">355</span>
|
|
<span class="normal">356</span>
|
|
<span class="normal">357</span>
|
|
<span class="normal">358</span>
|
|
<span class="normal">359</span>
|
|
<span class="normal">360</span>
|
|
<span class="normal">361</span>
|
|
<span class="normal">362</span>
|
|
<span class="normal">363</span>
|
|
<span class="normal">364</span>
|
|
<span class="normal">365</span>
|
|
<span class="normal">366</span>
|
|
<span class="normal">367</span>
|
|
<span class="normal">368</span>
|
|
<span class="normal">369</span>
|
|
<span class="normal">370</span>
|
|
<span class="normal">371</span>
|
|
<span class="normal">372</span>
|
|
<span class="normal">373</span>
|
|
<span class="normal">374</span>
|
|
<span class="normal">375</span>
|
|
<span class="normal">376</span>
|
|
<span class="normal">377</span>
|
|
<span class="normal">378</span>
|
|
<span class="normal">379</span>
|
|
<span class="normal">380</span>
|
|
<span class="normal">381</span>
|
|
<span class="normal">382</span>
|
|
<span class="normal">383</span>
|
|
<span class="normal">384</span>
|
|
<span class="normal">385</span>
|
|
<span class="normal">386</span>
|
|
<span class="normal">387</span>
|
|
<span class="normal">388</span>
|
|
<span class="normal">389</span>
|
|
<span class="normal">390</span>
|
|
<span class="normal">391</span>
|
|
<span class="normal">392</span>
|
|
<span class="normal">393</span>
|
|
<span class="normal">394</span>
|
|
<span class="normal">395</span>
|
|
<span class="normal">396</span>
|
|
<span class="normal">397</span>
|
|
<span class="normal">398</span>
|
|
<span class="normal">399</span>
|
|
<span class="normal">400</span>
|
|
<span class="normal">401</span>
|
|
<span class="normal">402</span>
|
|
<span class="normal">403</span>
|
|
<span class="normal">404</span>
|
|
<span class="normal">405</span>
|
|
<span class="normal">406</span>
|
|
<span class="normal">407</span>
|
|
<span class="normal">408</span>
|
|
<span class="normal">409</span>
|
|
<span class="normal">410</span>
|
|
<span class="normal">411</span>
|
|
<span class="normal">412</span>
|
|
<span class="normal">413</span>
|
|
<span class="normal">414</span>
|
|
<span class="normal">415</span>
|
|
<span class="normal">416</span>
|
|
<span class="normal">417</span>
|
|
<span class="normal">418</span>
|
|
<span class="normal">419</span>
|
|
<span class="normal">420</span>
|
|
<span class="normal">421</span>
|
|
<span class="normal">422</span>
|
|
<span class="normal">423</span>
|
|
<span class="normal">424</span>
|
|
<span class="normal">425</span>
|
|
<span class="normal">426</span>
|
|
<span class="normal">427</span>
|
|
<span class="normal">428</span>
|
|
<span class="normal">429</span>
|
|
<span class="normal">430</span>
|
|
<span class="normal">431</span>
|
|
<span class="normal">432</span>
|
|
<span class="normal">433</span>
|
|
<span class="normal">434</span>
|
|
<span class="normal">435</span>
|
|
<span class="normal">436</span>
|
|
<span class="normal">437</span>
|
|
<span class="normal">438</span>
|
|
<span class="normal">439</span>
|
|
<span class="normal">440</span>
|
|
<span class="normal">441</span>
|
|
<span class="normal">442</span>
|
|
<span class="normal">443</span>
|
|
<span class="normal">444</span>
|
|
<span class="normal">445</span>
|
|
<span class="normal">446</span>
|
|
<span class="normal">447</span>
|
|
<span class="normal">448</span>
|
|
<span class="normal">449</span>
|
|
<span class="normal">450</span>
|
|
<span class="normal">451</span>
|
|
<span class="normal">452</span>
|
|
<span class="normal">453</span>
|
|
<span class="normal">454</span>
|
|
<span class="normal">455</span>
|
|
<span class="normal">456</span>
|
|
<span class="normal">457</span>
|
|
<span class="normal">458</span>
|
|
<span class="normal">459</span>
|
|
<span class="normal">460</span>
|
|
<span class="normal">461</span>
|
|
<span class="normal">462</span>
|
|
<span class="normal">463</span>
|
|
<span class="normal">464</span>
|
|
<span class="normal">465</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">format_string</span><span class="p">(</span>
|
|
<span class="bp">cls</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">template</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">save_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
|
|
<span class="n">unique_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">""</span><span class="p">,</span>
|
|
<span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
|
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Format a string using the specified template type and variables.</span>
|
|
|
|
<span class="sd"> This is the main method executed by the node. It formats the template using either</span>
|
|
<span class="sd"> Python's str.format() or Jinja2 templating, and optionally saves the state to disk.</span>
|
|
<span class="sd"> The node is OUTPUT_NODE=True so the formatted string also renders as a read-only</span>
|
|
<span class="sd"> text display directly on the node (no separate Show Text node needed).</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> template_type (str): Either "Simple" or "Jinja2" to specify the template engine.</span>
|
|
<span class="sd"> template (str): The template string to format.</span>
|
|
<span class="sd"> save_path (str): Optional path to save the node state. If empty, state is not saved.</span>
|
|
<span class="sd"> unique_id (str): The unique identifier for this node instance (passed by ComfyUI).</span>
|
|
<span class="sd"> **kwargs: Variable keyword arguments that provide values for template variables.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: ``{"ui": {"text": [formatted_string]}, "result": result}`` where</span>
|
|
<span class="sd"> ``result`` is a tuple containing the formatted string, the save path,</span>
|
|
<span class="sd"> followed by the values of input variables (in order).</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Simple template example</span>
|
|
<span class="sd"> ret = FormatString.format_string(</span>
|
|
<span class="sd"> template_type="Simple",</span>
|
|
<span class="sd"> template="Hello {name}, you are {age} years old",</span>
|
|
<span class="sd"> save_path="",</span>
|
|
<span class="sd"> unique_id="123",</span>
|
|
<span class="sd"> name="Alice",</span>
|
|
<span class="sd"> age="30"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(ret["result"]) # Outputs: ('Hello Alice, you are 30 years old', '', 'Alice', '30')</span>
|
|
|
|
<span class="sd"> # Jinja2 template example</span>
|
|
<span class="sd"> ret = FormatString.format_string(</span>
|
|
<span class="sd"> template_type="Jinja2",</span>
|
|
<span class="sd"> template="Hello {{ name }}, today is {{ datetime.now().strftime('%A') }}",</span>
|
|
<span class="sd"> save_path="",</span>
|
|
<span class="sd"> unique_id="124",</span>
|
|
<span class="sd"> name="Bob"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(ret["result"]) # Outputs: ('Hello Bob, today is Wednesday', '', 'Bob')</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # Test simple format</span>
|
|
<span class="sd"> >>> ret = FormatString.format_string(</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}, you are {age} years old",</span>
|
|
<span class="sd"> ... save_path="",</span>
|
|
<span class="sd"> ... name="Alice",</span>
|
|
<span class="sd"> ... age="30"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> result = ret["result"]</span>
|
|
<span class="sd"> >>> assert result[0] == "Hello Alice, you are 30 years old"</span>
|
|
<span class="sd"> >>> assert result[1] == ""</span>
|
|
<span class="sd"> >>> assert result[2] == "Alice"</span>
|
|
<span class="sd"> >>> assert result[3] == "30"</span>
|
|
<span class="sd"> >>> assert ret["ui"]["text"][0] == "Hello Alice, you are 30 years old"</span>
|
|
<span class="sd"> >>></span>
|
|
<span class="sd"> >>> # Test Jinja2 format with datetime (can't test exact output due to time dependency)</span>
|
|
<span class="sd"> >>> ret = FormatString.format_string(</span>
|
|
<span class="sd"> ... template_type="Jinja2",</span>
|
|
<span class="sd"> ... template="Name: {{ name }}",</span>
|
|
<span class="sd"> ... save_path="",</span>
|
|
<span class="sd"> ... name="Bob"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> result = ret["result"]</span>
|
|
<span class="sd"> >>> assert result[0] == "Name: Bob"</span>
|
|
<span class="sd"> >>> assert result[1] == ""</span>
|
|
<span class="sd"> >>> assert result[2] == "Bob"</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Formatting string - type: </span><span class="si">%s</span><span class="s2">, unique_id: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">unique_id</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Template: </span><span class="si">%.100s</span><span class="s2">..."</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
|
|
<span class="n">keys</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_extract_keys</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Extracted variables: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">keys</span><span class="p">)</span>
|
|
<span class="n">input_vals</span> <span class="o">=</span> <span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">k</span><span class="si">}</span><span class="s2">=</span><span class="si">{</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span><span class="w"> </span><span class="s1">''</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Input values: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">input_vals</span><span class="p">)</span>
|
|
|
|
<span class="c1"># CRITICAL: Update RETURN_TYPES/RETURN_NAMES before execution to ensure they match our return tuple</span>
|
|
<span class="c1"># This is necessary because update_widget might not have been called yet (e.g., on workflow load)</span>
|
|
<span class="k">if</span> <span class="n">unique_id</span><span class="p">:</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">update_widget</span><span class="p">(</span><span class="n">unique_id</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updated RETURN_TYPES for node </span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">unique_id</span><span class="p">,</span> <span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="n">template_type</span> <span class="o">==</span> <span class="s2">"Simple"</span><span class="p">:</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Simple format successful: </span><span class="si">%.50s</span><span class="s2">"</span><span class="p">,</span> <span class="n">formatted_string</span><span class="p">)</span>
|
|
<span class="k">except</span> <span class="ne">KeyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Missing variable in Simple template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="k">raise</span> <span class="c1"># Re-raise for proper error handling</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error in Simple template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error: </span><span class="si">{</span><span class="n">error_msg</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="k">else</span><span class="p">:</span> <span class="c1"># Jinja2</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">jinja_template</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">jinja_env</span><span class="o">.</span><span class="n">from_string</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="c1"># Combine user-provided kwargs with additional_context</span>
|
|
<span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="o">**</span><span class="bp">cls</span><span class="o">.</span><span class="n">additional_context</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">}</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">jinja_template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="o">**</span><span class="n">context</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Jinja2 format successful, result length: </span><span class="si">%d</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">formatted_string</span><span class="p">)</span>
|
|
<span class="p">)</span>
|
|
<span class="k">except</span> <span class="n">exceptions</span><span class="o">.</span><span class="n">TemplateSyntaxError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error in Jinja2 template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">error_msg</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">error_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Error rendering Jinja2 template: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">error_msg</span><span class="p">)</span>
|
|
<span class="n">formatted_string</span> <span class="o">=</span> <span class="n">error_msg</span>
|
|
|
|
<span class="c1"># Save the state</span>
|
|
<span class="n">save_data</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="n">template_type</span><span class="p">,</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="n">template</span><span class="p">,</span>
|
|
<span class="s2">"inputs"</span><span class="p">:</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">},</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="s2">""</span>
|
|
<span class="k">if</span> <span class="n">save_path</span><span class="p">:</span>
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
|
|
<span class="n">folder_paths</span><span class="o">.</span><span class="n">get_output_directory</span><span class="p">(),</span> <span class="n">save_path</span>
|
|
<span class="p">)</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">actual_save_path</span><span class="p">),</span> <span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">actual_save_path</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">save_data</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Node state saved to: </span><span class="si">{</span><span class="n">actual_save_path</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Error saving node state: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="n">actual_save_path</span> <span class="o">=</span> <span class="s2">""</span> <span class="c1"># Reset save_path if saving failed</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"No save_path provided, skipping state save"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Return formatted_string and saved_file_path FIRST (fixed positions 0,1),</span>
|
|
<span class="c1"># then all input values (for chaining)</span>
|
|
<span class="c1"># The order must match what was set in update_widget's RETURN_TYPES/RETURN_NAMES</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span>
|
|
<span class="n">formatted_string</span><span class="p">,</span>
|
|
<span class="n">actual_save_path</span><span class="p">,</span>
|
|
<span class="p">)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="s2">""</span><span class="p">))</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">)</span>
|
|
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Returning </span><span class="si">%d</span><span class="s2"> outputs: keys=</span><span class="si">%s</span><span class="s2">, save_path=</span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">),</span>
|
|
<span class="n">keys</span><span class="p">,</span>
|
|
<span class="n">actual_save_path</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Full result tuple length: </span><span class="si">%d</span><span class="s2">, expected: </span><span class="si">%d</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">{</span>
|
|
<span class="s2">"ui"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"text"</span><span class="p">:</span> <span class="p">[</span><span class="n">formatted_string</span><span class="p">]},</span>
|
|
<span class="s2">"result"</span><span class="p">:</span> <span class="n">result</span><span class="p">,</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.get_node_config" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">get_node_config</span><span class="p">(</span><span class="n">node_id</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Get the configuration for a specific node instance.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>node_id</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The unique identifier of the node instance.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code><span title="typing.Dict">Dict</span>[<span title="str">str</span>, <span title="typing.Any">Any</span>]</code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Dict[str, Any]: The configuration for the specified node, or an empty dict if not found.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="c1"># After updating a node's configuration</span>
|
|
<span class="n">config</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">get_node_config</span><span class="p">(</span><span class="s2">"node_123"</span><span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">config</span><span class="p">)</span> <span class="c1"># Shows the stored configuration for node_123</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> # First create a config
|
|
>>> _ = FormatString.update_widget(
|
|
... node_id="test_node_2",
|
|
... template_type="Simple",
|
|
... template="Hello {name}"
|
|
... )
|
|
>>> # Then retrieve it
|
|
>>> config = FormatString.get_node_config("test_node_2")
|
|
>>> assert "inputs" in config
|
|
>>> assert "outputs" in config
|
|
>>> assert "name" in config["inputs"]
|
|
>>> assert len(config["outputs"]) == 3 # name, formatted_string, saved_file_path
|
|
>>> # Test non-existent node
|
|
>>> empty_config = FormatString.get_node_config("non_existent_node")
|
|
>>> assert empty_config == {}
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">571</span>
|
|
<span class="normal">572</span>
|
|
<span class="normal">573</span>
|
|
<span class="normal">574</span>
|
|
<span class="normal">575</span>
|
|
<span class="normal">576</span>
|
|
<span class="normal">577</span>
|
|
<span class="normal">578</span>
|
|
<span class="normal">579</span>
|
|
<span class="normal">580</span>
|
|
<span class="normal">581</span>
|
|
<span class="normal">582</span>
|
|
<span class="normal">583</span>
|
|
<span class="normal">584</span>
|
|
<span class="normal">585</span>
|
|
<span class="normal">586</span>
|
|
<span class="normal">587</span>
|
|
<span class="normal">588</span>
|
|
<span class="normal">589</span>
|
|
<span class="normal">590</span>
|
|
<span class="normal">591</span>
|
|
<span class="normal">592</span>
|
|
<span class="normal">593</span>
|
|
<span class="normal">594</span>
|
|
<span class="normal">595</span>
|
|
<span class="normal">596</span>
|
|
<span class="normal">597</span>
|
|
<span class="normal">598</span>
|
|
<span class="normal">599</span>
|
|
<span class="normal">600</span>
|
|
<span class="normal">601</span>
|
|
<span class="normal">602</span>
|
|
<span class="normal">603</span>
|
|
<span class="normal">604</span>
|
|
<span class="normal">605</span>
|
|
<span class="normal">606</span>
|
|
<span class="normal">607</span>
|
|
<span class="normal">608</span>
|
|
<span class="normal">609</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_node_config</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">node_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Get the configuration for a specific node instance.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> node_id (str): The unique identifier of the node instance.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: The configuration for the specified node, or an empty dict if not found.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # After updating a node's configuration</span>
|
|
<span class="sd"> config = FormatString.get_node_config("node_123")</span>
|
|
<span class="sd"> print(config) # Shows the stored configuration for node_123</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> # First create a config</span>
|
|
<span class="sd"> >>> _ = FormatString.update_widget(</span>
|
|
<span class="sd"> ... node_id="test_node_2",</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> # Then retrieve it</span>
|
|
<span class="sd"> >>> config = FormatString.get_node_config("test_node_2")</span>
|
|
<span class="sd"> >>> assert "inputs" in config</span>
|
|
<span class="sd"> >>> assert "outputs" in config</span>
|
|
<span class="sd"> >>> assert "name" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert len(config["outputs"]) == 3 # name, formatted_string, saved_file_path</span>
|
|
<span class="sd"> >>> # Test non-existent node</span>
|
|
<span class="sd"> >>> empty_config = FormatString.get_node_config("non_existent_node")</span>
|
|
<span class="sd"> >>> assert empty_config == {}</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="bp">cls</span><span class="o">.</span><span class="n">node_configs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">node_id</span><span class="p">,</span> <span class="p">{})</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.load_node_state" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">load_node_state</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Load a previously saved node state from disk.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>file_path</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Path to the saved node state JSON file.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code><span title="typing.Dict">Dict</span>[<span title="str">str</span>, <span title="typing.Any">Any</span>]</code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Dict[str, Any]: The loaded node state, or an empty dict if loading failed.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="c1"># Load a previously saved state</span>
|
|
<span class="n">state</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">load_node_state</span><span class="p">(</span><span class="s2">"/path/to/saved_state.json"</span><span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">state</span><span class="p">[</span><span class="s2">"template"</span><span class="p">])</span> <span class="c1"># Shows the saved template</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">state</span><span class="p">[</span><span class="s2">"inputs"</span><span class="p">])</span> <span class="c1"># Shows the saved input values</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> import tempfile
|
|
>>> import json
|
|
>>> import os
|
|
>>> # Create a temporary file with test data
|
|
>>> test_data = {
|
|
... "template_type": "Simple",
|
|
... "template": "Hello {name}",
|
|
... "inputs": {"name": "Alice"}
|
|
... }
|
|
>>> with tempfile.NamedTemporaryFile(delete=False, mode="w") as temp:
|
|
... json.dump(test_data, temp)
|
|
... temp_path = temp.name
|
|
>>> # Test loading the file
|
|
>>> state = FormatString.load_node_state(temp_path)
|
|
>>> assert state["template_type"] == "Simple"
|
|
>>> assert state["template"] == "Hello {name}"
|
|
>>> assert state["inputs"]["name"] == "Alice"
|
|
>>> # Clean up
|
|
>>> os.unlink(temp_path)
|
|
>>> # Test loading non-existent file
|
|
>>> empty_state = FormatString.load_node_state("non_existent_file.json")
|
|
>>> assert empty_state == {}
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">611</span>
|
|
<span class="normal">612</span>
|
|
<span class="normal">613</span>
|
|
<span class="normal">614</span>
|
|
<span class="normal">615</span>
|
|
<span class="normal">616</span>
|
|
<span class="normal">617</span>
|
|
<span class="normal">618</span>
|
|
<span class="normal">619</span>
|
|
<span class="normal">620</span>
|
|
<span class="normal">621</span>
|
|
<span class="normal">622</span>
|
|
<span class="normal">623</span>
|
|
<span class="normal">624</span>
|
|
<span class="normal">625</span>
|
|
<span class="normal">626</span>
|
|
<span class="normal">627</span>
|
|
<span class="normal">628</span>
|
|
<span class="normal">629</span>
|
|
<span class="normal">630</span>
|
|
<span class="normal">631</span>
|
|
<span class="normal">632</span>
|
|
<span class="normal">633</span>
|
|
<span class="normal">634</span>
|
|
<span class="normal">635</span>
|
|
<span class="normal">636</span>
|
|
<span class="normal">637</span>
|
|
<span class="normal">638</span>
|
|
<span class="normal">639</span>
|
|
<span class="normal">640</span>
|
|
<span class="normal">641</span>
|
|
<span class="normal">642</span>
|
|
<span class="normal">643</span>
|
|
<span class="normal">644</span>
|
|
<span class="normal">645</span>
|
|
<span class="normal">646</span>
|
|
<span class="normal">647</span>
|
|
<span class="normal">648</span>
|
|
<span class="normal">649</span>
|
|
<span class="normal">650</span>
|
|
<span class="normal">651</span>
|
|
<span class="normal">652</span>
|
|
<span class="normal">653</span>
|
|
<span class="normal">654</span>
|
|
<span class="normal">655</span>
|
|
<span class="normal">656</span>
|
|
<span class="normal">657</span>
|
|
<span class="normal">658</span>
|
|
<span class="normal">659</span>
|
|
<span class="normal">660</span>
|
|
<span class="normal">661</span>
|
|
<span class="normal">662</span>
|
|
<span class="normal">663</span>
|
|
<span class="normal">664</span>
|
|
<span class="normal">665</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">load_node_state</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Load a previously saved node state from disk.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> file_path (str): Path to the saved node state JSON file.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: The loaded node state, or an empty dict if loading failed.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Load a previously saved state</span>
|
|
<span class="sd"> state = FormatString.load_node_state("/path/to/saved_state.json")</span>
|
|
<span class="sd"> print(state["template"]) # Shows the saved template</span>
|
|
<span class="sd"> print(state["inputs"]) # Shows the saved input values</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> import tempfile</span>
|
|
<span class="sd"> >>> import json</span>
|
|
<span class="sd"> >>> import os</span>
|
|
<span class="sd"> >>> # Create a temporary file with test data</span>
|
|
<span class="sd"> >>> test_data = {</span>
|
|
<span class="sd"> ... "template_type": "Simple",</span>
|
|
<span class="sd"> ... "template": "Hello {name}",</span>
|
|
<span class="sd"> ... "inputs": {"name": "Alice"}</span>
|
|
<span class="sd"> ... }</span>
|
|
<span class="sd"> >>> with tempfile.NamedTemporaryFile(delete=False, mode="w") as temp:</span>
|
|
<span class="sd"> ... json.dump(test_data, temp)</span>
|
|
<span class="sd"> ... temp_path = temp.name</span>
|
|
<span class="sd"> >>> # Test loading the file</span>
|
|
<span class="sd"> >>> state = FormatString.load_node_state(temp_path)</span>
|
|
<span class="sd"> >>> assert state["template_type"] == "Simple"</span>
|
|
<span class="sd"> >>> assert state["template"] == "Hello {name}"</span>
|
|
<span class="sd"> >>> assert state["inputs"]["name"] == "Alice"</span>
|
|
<span class="sd"> >>> # Clean up</span>
|
|
<span class="sd"> >>> os.unlink(temp_path)</span>
|
|
<span class="sd"> >>> # Test loading non-existent file</span>
|
|
<span class="sd"> >>> empty_state = FormatString.load_node_state("non_existent_file.json")</span>
|
|
<span class="sd"> >>> assert empty_state == {}</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">file_path</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">load_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">load_data</span>
|
|
<span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="p">{}</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Failed to load node state from </span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">file_path</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">{}</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.time_now" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">time_now</span><span class="p">()</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-staticmethod"><code>staticmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Get the current time in a formatted string.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th> <th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td><code>str</code></td> <td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Current time formatted as 'YYYYMMDD-HHMMSS'.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="n">timestamp</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">time_now</span><span class="p">()</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">timestamp</span><span class="p">)</span> <span class="c1"># Outputs something like: '20240327-153045'</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> from datetime import datetime
|
|
>>> timestamp = FormatString.time_now()
|
|
>>> assert len(timestamp) == 15 # Format YYYYMMDD-HHMMSS is 15 chars
|
|
>>> assert timestamp[8] == '-' # Check format separator
|
|
>>> # Verify it's roughly the current time (allowing some seconds of delay)
|
|
>>> current = datetime.now().strftime("%Y%m%d-%H%M")
|
|
>>> assert timestamp.startswith(current)
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"> 80</span>
|
|
<span class="normal"> 81</span>
|
|
<span class="normal"> 82</span>
|
|
<span class="normal"> 83</span>
|
|
<span class="normal"> 84</span>
|
|
<span class="normal"> 85</span>
|
|
<span class="normal"> 86</span>
|
|
<span class="normal"> 87</span>
|
|
<span class="normal"> 88</span>
|
|
<span class="normal"> 89</span>
|
|
<span class="normal"> 90</span>
|
|
<span class="normal"> 91</span>
|
|
<span class="normal"> 92</span>
|
|
<span class="normal"> 93</span>
|
|
<span class="normal"> 94</span>
|
|
<span class="normal"> 95</span>
|
|
<span class="normal"> 96</span>
|
|
<span class="normal"> 97</span>
|
|
<span class="normal"> 98</span>
|
|
<span class="normal"> 99</span>
|
|
<span class="normal">100</span>
|
|
<span class="normal">101</span>
|
|
<span class="normal">102</span>
|
|
<span class="normal">103</span>
|
|
<span class="normal">104</span>
|
|
<span class="normal">105</span>
|
|
<span class="normal">106</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@staticmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">time_now</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Get the current time in a formatted string.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> str: Current time formatted as 'YYYYMMDD-HHMMSS'.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> timestamp = FormatString.time_now()</span>
|
|
<span class="sd"> print(timestamp) # Outputs something like: '20240327-153045'</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> from datetime import datetime</span>
|
|
<span class="sd"> >>> timestamp = FormatString.time_now()</span>
|
|
<span class="sd"> >>> assert len(timestamp) == 15 # Format YYYYMMDD-HHMMSS is 15 chars</span>
|
|
<span class="sd"> >>> assert timestamp[8] == '-' # Check format separator</span>
|
|
<span class="sd"> >>> # Verify it's roughly the current time (allowing some seconds of delay)</span>
|
|
<span class="sd"> >>> current = datetime.now().strftime("%Y%m%d-%H%M")</span>
|
|
<span class="sd"> >>> assert timestamp.startswith(current)</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m</span><span class="si">%d</span><span class="s2">-%H%M%S"</span><span class="p">)</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h3 id="comfydv.format_string.FormatString.update_widget" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">update_widget</span><span class="p">(</span><span class="n">node_id</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-classmethod"><code>classmethod</code></small>
|
|
</span>
|
|
|
|
</h3>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>Update a node's widget configuration based on the template.</p>
|
|
<p>This method is called when a template is changed to dynamically update the
|
|
node's inputs and outputs based on the variables detected in the template.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>node_id</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The unique identifier of the node instance.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>template_type</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The template type ("Simple" or "Jinja2").</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>template</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="str">str</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The template string.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code><span title="typing.Dict">Dict</span>[<span title="str">str</span>, <span title="typing.Any">Any</span>]</code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>Dict[str, Any]: Updated configuration for the node.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">format_string</span><span class="w"> </span><span class="kn">import</span> <span class="n">FormatString</span>
|
|
|
|
<span class="c1"># Called via ComfyUI's web API when template changes</span>
|
|
<span class="n">config</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">update_widget</span><span class="p">(</span>
|
|
<span class="n">node_id</span><span class="o">=</span><span class="s2">"node_123"</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="o">=</span><span class="s2">"Simple"</span><span class="p">,</span>
|
|
<span class="n">template</span><span class="o">=</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">, you are </span><span class="si">{age}</span><span class="s2"> years old"</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s2">"inputs"</span><span class="p">])</span> <span class="c1"># Shows inputs including 'name' and 'age'</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">])</span> <span class="c1"># Shows outputs including extracted variables</span>
|
|
</code></pre></div>
|
|
</details> <!-- Example Test:
|
|
>>> config = FormatString.update_widget(
|
|
... node_id="test_node",
|
|
... template_type="Simple",
|
|
... template="Hello {name}, you are {age} years old"
|
|
... )
|
|
>>> assert "name" in config["inputs"]
|
|
>>> assert "age" in config["inputs"]
|
|
>>> assert len(config["outputs"]) == 4 # formatted_string, saved_file_path, name, age
|
|
>>> assert config["outputs"][0]["name"] == "formatted_string"
|
|
>>> assert config["outputs"][1]["name"] == "saved_file_path"
|
|
>>> assert config["outputs"][2]["name"] == "name"
|
|
>>> assert config["outputs"][3]["name"] == "age"
|
|
>>> # Check that RETURN_TYPES and RETURN_NAMES are updated
|
|
>>> assert len(FormatString.RETURN_TYPES) == 4
|
|
>>> assert len(FormatString.RETURN_NAMES) == 4
|
|
>>> assert FormatString.RETURN_NAMES[0] == "formatted_string"
|
|
>>> assert FormatString.RETURN_NAMES[1] == "saved_file_path"
|
|
>>> assert FormatString.RETURN_NAMES[2] == "name"
|
|
>>> assert FormatString.RETURN_NAMES[3] == "age"
|
|
>>> # Check that node config is stored
|
|
>>> assert "test_node" in FormatString.node_configs
|
|
>>> assert FormatString.node_configs["test_node"] == config
|
|
-->
|
|
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">467</span>
|
|
<span class="normal">468</span>
|
|
<span class="normal">469</span>
|
|
<span class="normal">470</span>
|
|
<span class="normal">471</span>
|
|
<span class="normal">472</span>
|
|
<span class="normal">473</span>
|
|
<span class="normal">474</span>
|
|
<span class="normal">475</span>
|
|
<span class="normal">476</span>
|
|
<span class="normal">477</span>
|
|
<span class="normal">478</span>
|
|
<span class="normal">479</span>
|
|
<span class="normal">480</span>
|
|
<span class="normal">481</span>
|
|
<span class="normal">482</span>
|
|
<span class="normal">483</span>
|
|
<span class="normal">484</span>
|
|
<span class="normal">485</span>
|
|
<span class="normal">486</span>
|
|
<span class="normal">487</span>
|
|
<span class="normal">488</span>
|
|
<span class="normal">489</span>
|
|
<span class="normal">490</span>
|
|
<span class="normal">491</span>
|
|
<span class="normal">492</span>
|
|
<span class="normal">493</span>
|
|
<span class="normal">494</span>
|
|
<span class="normal">495</span>
|
|
<span class="normal">496</span>
|
|
<span class="normal">497</span>
|
|
<span class="normal">498</span>
|
|
<span class="normal">499</span>
|
|
<span class="normal">500</span>
|
|
<span class="normal">501</span>
|
|
<span class="normal">502</span>
|
|
<span class="normal">503</span>
|
|
<span class="normal">504</span>
|
|
<span class="normal">505</span>
|
|
<span class="normal">506</span>
|
|
<span class="normal">507</span>
|
|
<span class="normal">508</span>
|
|
<span class="normal">509</span>
|
|
<span class="normal">510</span>
|
|
<span class="normal">511</span>
|
|
<span class="normal">512</span>
|
|
<span class="normal">513</span>
|
|
<span class="normal">514</span>
|
|
<span class="normal">515</span>
|
|
<span class="normal">516</span>
|
|
<span class="normal">517</span>
|
|
<span class="normal">518</span>
|
|
<span class="normal">519</span>
|
|
<span class="normal">520</span>
|
|
<span class="normal">521</span>
|
|
<span class="normal">522</span>
|
|
<span class="normal">523</span>
|
|
<span class="normal">524</span>
|
|
<span class="normal">525</span>
|
|
<span class="normal">526</span>
|
|
<span class="normal">527</span>
|
|
<span class="normal">528</span>
|
|
<span class="normal">529</span>
|
|
<span class="normal">530</span>
|
|
<span class="normal">531</span>
|
|
<span class="normal">532</span>
|
|
<span class="normal">533</span>
|
|
<span class="normal">534</span>
|
|
<span class="normal">535</span>
|
|
<span class="normal">536</span>
|
|
<span class="normal">537</span>
|
|
<span class="normal">538</span>
|
|
<span class="normal">539</span>
|
|
<span class="normal">540</span>
|
|
<span class="normal">541</span>
|
|
<span class="normal">542</span>
|
|
<span class="normal">543</span>
|
|
<span class="normal">544</span>
|
|
<span class="normal">545</span>
|
|
<span class="normal">546</span>
|
|
<span class="normal">547</span>
|
|
<span class="normal">548</span>
|
|
<span class="normal">549</span>
|
|
<span class="normal">550</span>
|
|
<span class="normal">551</span>
|
|
<span class="normal">552</span>
|
|
<span class="normal">553</span>
|
|
<span class="normal">554</span>
|
|
<span class="normal">555</span>
|
|
<span class="normal">556</span>
|
|
<span class="normal">557</span>
|
|
<span class="normal">558</span>
|
|
<span class="normal">559</span>
|
|
<span class="normal">560</span>
|
|
<span class="normal">561</span>
|
|
<span class="normal">562</span>
|
|
<span class="normal">563</span>
|
|
<span class="normal">564</span>
|
|
<span class="normal">565</span>
|
|
<span class="normal">566</span>
|
|
<span class="normal">567</span>
|
|
<span class="normal">568</span>
|
|
<span class="normal">569</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@classmethod</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">update_widget</span><span class="p">(</span>
|
|
<span class="bp">cls</span><span class="p">,</span> <span class="n">node_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">template_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">template</span><span class="p">:</span> <span class="nb">str</span>
|
|
<span class="p">)</span> <span class="o">-></span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> Update a node's widget configuration based on the template.</span>
|
|
|
|
<span class="sd"> This method is called when a template is changed to dynamically update the</span>
|
|
<span class="sd"> node's inputs and outputs based on the variables detected in the template.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> node_id (str): The unique identifier of the node instance.</span>
|
|
<span class="sd"> template_type (str): The template type ("Simple" or "Jinja2").</span>
|
|
<span class="sd"> template (str): The template string.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> Dict[str, Any]: Updated configuration for the node.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> ```python</span>
|
|
<span class="sd"> from format_string import FormatString</span>
|
|
|
|
<span class="sd"> # Called via ComfyUI's web API when template changes</span>
|
|
<span class="sd"> config = FormatString.update_widget(</span>
|
|
<span class="sd"> node_id="node_123",</span>
|
|
<span class="sd"> template_type="Simple",</span>
|
|
<span class="sd"> template="Hello {name}, you are {age} years old"</span>
|
|
<span class="sd"> )</span>
|
|
<span class="sd"> print(config["inputs"]) # Shows inputs including 'name' and 'age'</span>
|
|
<span class="sd"> print(config["outputs"]) # Shows outputs including extracted variables</span>
|
|
<span class="sd"> ```</span>
|
|
|
|
<span class="sd"> <!-- Example Test:</span>
|
|
<span class="sd"> >>> config = FormatString.update_widget(</span>
|
|
<span class="sd"> ... node_id="test_node",</span>
|
|
<span class="sd"> ... template_type="Simple",</span>
|
|
<span class="sd"> ... template="Hello {name}, you are {age} years old"</span>
|
|
<span class="sd"> ... )</span>
|
|
<span class="sd"> >>> assert "name" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert "age" in config["inputs"]</span>
|
|
<span class="sd"> >>> assert len(config["outputs"]) == 4 # formatted_string, saved_file_path, name, age</span>
|
|
<span class="sd"> >>> assert config["outputs"][0]["name"] == "formatted_string"</span>
|
|
<span class="sd"> >>> assert config["outputs"][1]["name"] == "saved_file_path"</span>
|
|
<span class="sd"> >>> assert config["outputs"][2]["name"] == "name"</span>
|
|
<span class="sd"> >>> assert config["outputs"][3]["name"] == "age"</span>
|
|
<span class="sd"> >>> # Check that RETURN_TYPES and RETURN_NAMES are updated</span>
|
|
<span class="sd"> >>> assert len(FormatString.RETURN_TYPES) == 4</span>
|
|
<span class="sd"> >>> assert len(FormatString.RETURN_NAMES) == 4</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[0] == "formatted_string"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[1] == "saved_file_path"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[2] == "name"</span>
|
|
<span class="sd"> >>> assert FormatString.RETURN_NAMES[3] == "age"</span>
|
|
<span class="sd"> >>> # Check that node config is stored</span>
|
|
<span class="sd"> >>> assert "test_node" in FormatString.node_configs</span>
|
|
<span class="sd"> >>> assert FormatString.node_configs["test_node"] == config</span>
|
|
<span class="sd"> --></span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updating widget config - node_id: </span><span class="si">%s</span><span class="s2">, template_type: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">node_id</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Template: </span><span class="si">%.100s</span><span class="s2">..."</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
|
|
<span class="n">keys</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_extract_keys</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Extracted </span><span class="si">%d</span><span class="s2"> variables from template: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">),</span> <span class="n">keys</span><span class="p">)</span>
|
|
|
|
<span class="n">config</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s2">"inputs"</span><span class="p">:</span> <span class="p">{</span>
|
|
<span class="s2">"template_type"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"Simple"</span><span class="p">,</span> <span class="s2">"Jinja2"</span><span class="p">],),</span>
|
|
<span class="s2">"template"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"multiline"</span><span class="p">:</span> <span class="kc">True</span><span class="p">}),</span>
|
|
<span class="s2">"save_path"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">}),</span>
|
|
<span class="p">},</span>
|
|
<span class="s2">"outputs"</span><span class="p">:</span> <span class="p">[],</span>
|
|
<span class="p">}</span>
|
|
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"inputs"</span><span class="p">][</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"default"</span><span class="p">:</span> <span class="s2">""</span><span class="p">})</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s2">"name"</span><span class="p">:</span> <span class="n">key</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">})</span>
|
|
|
|
<span class="c1"># Add formatted_string and saved_file_path at the START of outputs (fixed positions)</span>
|
|
<span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
|
|
<span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"formatted_string"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">},</span>
|
|
<span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"saved_file_path"</span><span class="p">,</span> <span class="s2">"type"</span><span class="p">:</span> <span class="s2">"STRING"</span><span class="p">},</span>
|
|
<span class="p">]</span> <span class="o">+</span> <span class="n">config</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">]</span>
|
|
|
|
<span class="c1"># Update RETURN_TYPES and RETURN_NAMES dynamically</span>
|
|
<span class="c1"># formatted_string and saved_file_path are ALWAYS first two outputs (positions 0,1)</span>
|
|
<span class="c1"># This allows passing through variable values for chaining</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,</span> <span class="s2">"STRING"</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span><span class="s2">"STRING"</span><span class="p">,)</span> <span class="o">*</span> <span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_NAMES</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"formatted_string"</span><span class="p">,</span> <span class="s2">"saved_file_path"</span><span class="p">)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">OUTPUT_IS_LIST</span> <span class="o">=</span> <span class="p">(</span><span class="kc">False</span><span class="p">,)</span> <span class="o">*</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">keys</span><span class="p">)</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span>
|
|
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Updated RETURN_TYPES to </span><span class="si">%d</span><span class="s2"> outputs: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="nb">len</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_TYPES</span><span class="p">),</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">RETURN_NAMES</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Store the configuration for this specific node</span>
|
|
<span class="bp">cls</span><span class="o">.</span><span class="n">node_configs</span><span class="p">[</span><span class="n">node_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">config</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Stored config for node </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">node_id</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="n">config</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h2 id="comfydv.format_string.get_format_string_node_config" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">get_format_string_node_config</span><span class="p">(</span><span class="n">request</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-async"><code>async</code></small>
|
|
</span>
|
|
|
|
</h2>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>AIOHTTP route handler for retrieving a FormatString node's configuration.</p>
|
|
<p>This endpoint retrieves the stored configuration for a specific node instance.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>request</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="aiohttp.web.Request">Request</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The HTTP request object containing the node ID in the URL.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>web.Response: JSON response with the node's configuration.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<p>This would typically be called by the frontend JavaScript via a GET request:</p>
|
|
<div class="language-javascript highlight"><pre><span></span><code><span class="c1">// In ComfyUI frontend</span>
|
|
<span class="nx">fetch</span><span class="p">(</span><span class="s2">"/get_format_string_node_config/node_123"</span><span class="p">)</span>
|
|
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
|
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
|
|
</code></pre></div>
|
|
</details>
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">757</span>
|
|
<span class="normal">758</span>
|
|
<span class="normal">759</span>
|
|
<span class="normal">760</span>
|
|
<span class="normal">761</span>
|
|
<span class="normal">762</span>
|
|
<span class="normal">763</span>
|
|
<span class="normal">764</span>
|
|
<span class="normal">765</span>
|
|
<span class="normal">766</span>
|
|
<span class="normal">767</span>
|
|
<span class="normal">768</span>
|
|
<span class="normal">769</span>
|
|
<span class="normal">770</span>
|
|
<span class="normal">771</span>
|
|
<span class="normal">772</span>
|
|
<span class="normal">773</span>
|
|
<span class="normal">774</span>
|
|
<span class="normal">775</span>
|
|
<span class="normal">776</span>
|
|
<span class="normal">777</span>
|
|
<span class="normal">778</span>
|
|
<span class="normal">779</span>
|
|
<span class="normal">780</span>
|
|
<span class="normal">781</span>
|
|
<span class="normal">782</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@PromptServer</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/get_format_string_node_config/</span><span class="si">{node_id}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_format_string_node_config</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> AIOHTTP route handler for retrieving a FormatString node's configuration.</span>
|
|
|
|
<span class="sd"> This endpoint retrieves the stored configuration for a specific node instance.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> request (web.Request): The HTTP request object containing the node ID in the URL.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> web.Response: JSON response with the node's configuration.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> This would typically be called by the frontend JavaScript via a GET request:</span>
|
|
|
|
<span class="sd"> ```javascript</span>
|
|
<span class="sd"> // In ComfyUI frontend</span>
|
|
<span class="sd"> fetch("/get_format_string_node_config/node_123")</span>
|
|
<span class="sd"> .then(response => response.json())</span>
|
|
<span class="sd"> .then(data => console.log(data));</span>
|
|
<span class="sd"> ```</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">node_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">match_info</span><span class="p">[</span><span class="s2">"node_id"</span><span class="p">]</span>
|
|
<span class="n">config</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">get_node_config</span><span class="p">(</span><span class="n">node_id</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">json_response</span><span class="p">(</span><span class="n">config</span><span class="p">)</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h2 id="comfydv.format_string.load_format_string_node" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">load_format_string_node</span><span class="p">(</span><span class="n">request</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-async"><code>async</code></small>
|
|
</span>
|
|
|
|
</h2>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>AIOHTTP route handler for loading a FormatString node's state from disk.</p>
|
|
<p>This endpoint receives JSON data containing a file path, then loads and returns
|
|
the node state from that file.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>request</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="aiohttp.web.Request">Request</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The HTTP request object containing JSON data.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>web.Response: JSON response with the loaded node state.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<p>This would typically be called by the frontend JavaScript via a POST request:</p>
|
|
<div class="language-javascript highlight"><pre><span></span><code><span class="c1">// In ComfyUI frontend</span>
|
|
<span class="nx">fetch</span><span class="p">(</span><span class="s2">"/load_format_string_node"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nx">method</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nx">headers</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"Content-Type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"application/json"</span><span class="w"> </span><span class="p">},</span>
|
|
<span class="w"> </span><span class="nx">body</span><span class="o">:</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
|
|
<span class="w"> </span><span class="nx">file_path</span><span class="o">:</span><span class="w"> </span><span class="s2">"/path/to/saved_state.json"</span>
|
|
<span class="w"> </span><span class="p">})</span>
|
|
<span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
|
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
|
|
</code></pre></div>
|
|
</details>
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">721</span>
|
|
<span class="normal">722</span>
|
|
<span class="normal">723</span>
|
|
<span class="normal">724</span>
|
|
<span class="normal">725</span>
|
|
<span class="normal">726</span>
|
|
<span class="normal">727</span>
|
|
<span class="normal">728</span>
|
|
<span class="normal">729</span>
|
|
<span class="normal">730</span>
|
|
<span class="normal">731</span>
|
|
<span class="normal">732</span>
|
|
<span class="normal">733</span>
|
|
<span class="normal">734</span>
|
|
<span class="normal">735</span>
|
|
<span class="normal">736</span>
|
|
<span class="normal">737</span>
|
|
<span class="normal">738</span>
|
|
<span class="normal">739</span>
|
|
<span class="normal">740</span>
|
|
<span class="normal">741</span>
|
|
<span class="normal">742</span>
|
|
<span class="normal">743</span>
|
|
<span class="normal">744</span>
|
|
<span class="normal">745</span>
|
|
<span class="normal">746</span>
|
|
<span class="normal">747</span>
|
|
<span class="normal">748</span>
|
|
<span class="normal">749</span>
|
|
<span class="normal">750</span>
|
|
<span class="normal">751</span>
|
|
<span class="normal">752</span>
|
|
<span class="normal">753</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@PromptServer</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/load_format_string_node"</span><span class="p">)</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">load_format_string_node</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> AIOHTTP route handler for loading a FormatString node's state from disk.</span>
|
|
|
|
<span class="sd"> This endpoint receives JSON data containing a file path, then loads and returns</span>
|
|
<span class="sd"> the node state from that file.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> request (web.Request): The HTTP request object containing JSON data.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> web.Response: JSON response with the loaded node state.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> This would typically be called by the frontend JavaScript via a POST request:</span>
|
|
|
|
<span class="sd"> ```javascript</span>
|
|
<span class="sd"> // In ComfyUI frontend</span>
|
|
<span class="sd"> fetch("/load_format_string_node", {</span>
|
|
<span class="sd"> method: "POST",</span>
|
|
<span class="sd"> headers: { "Content-Type": "application/json" },</span>
|
|
<span class="sd"> body: JSON.stringify({</span>
|
|
<span class="sd"> file_path: "/path/to/saved_state.json"</span>
|
|
<span class="sd"> })</span>
|
|
<span class="sd"> }).then(response => response.json())</span>
|
|
<span class="sd"> .then(data => console.log(data));</span>
|
|
<span class="sd"> ```</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">request</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
|
<span class="n">file_path</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"file_path"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
<span class="n">state</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">load_node_state</span><span class="p">(</span><span class="n">file_path</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">json_response</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="doc doc-object doc-function">
|
|
|
|
|
|
<h2 id="comfydv.format_string.update_format_string_node" class="doc doc-heading">
|
|
<code class="highlight language-python"><span class="n">update_format_string_node</span><span class="p">(</span><span class="n">request</span><span class="p">)</span></code>
|
|
|
|
<span class="doc doc-labels">
|
|
<small class="doc doc-label doc-label-async"><code>async</code></small>
|
|
</span>
|
|
|
|
</h2>
|
|
|
|
|
|
<div class="doc doc-contents ">
|
|
|
|
<p>AIOHTTP route handler for updating a FormatString node's configuration.</p>
|
|
<p>This endpoint receives JSON data containing a node ID, template type, and template,
|
|
then updates the node's configuration based on the template.</p>
|
|
|
|
|
|
<p><span class="doc-section-title">Parameters:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
<th>Default</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
<code>request</code>
|
|
</td>
|
|
<td>
|
|
<code><span title="aiohttp.web.Request">Request</span></code>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>The HTTP request object containing JSON data.</p>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<em>required</em>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<p><span class="doc-section-title">Returns:</span></p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr class="doc-section-item">
|
|
<td>
|
|
</td>
|
|
<td>
|
|
<div class="doc-md-description">
|
|
<p>web.Response: JSON response with the updated node configuration.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
|
|
<details class="example" open>
|
|
<summary>Example</summary>
|
|
<p>This would typically be called by the frontend JavaScript via a POST request:</p>
|
|
<div class="language-javascript highlight"><pre><span></span><code><span class="c1">// In ComfyUI frontend</span>
|
|
<span class="nx">fetch</span><span class="p">(</span><span class="s2">"/update_format_string_node"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
|
|
<span class="w"> </span><span class="nx">method</span><span class="o">:</span><span class="w"> </span><span class="s2">"POST"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nx">headers</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s2">"Content-Type"</span><span class="o">:</span><span class="w"> </span><span class="s2">"application/json"</span><span class="w"> </span><span class="p">},</span>
|
|
<span class="w"> </span><span class="nx">body</span><span class="o">:</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
|
|
<span class="w"> </span><span class="nx">nodeId</span><span class="o">:</span><span class="w"> </span><span class="s2">"node_123"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nx">template_type</span><span class="o">:</span><span class="w"> </span><span class="s2">"Simple"</span><span class="p">,</span>
|
|
<span class="w"> </span><span class="nx">template</span><span class="o">:</span><span class="w"> </span><span class="s2">"Hello {name}"</span>
|
|
<span class="w"> </span><span class="p">})</span>
|
|
<span class="p">}).</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
|
<span class="w"> </span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">data</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
|
|
</code></pre></div>
|
|
</details>
|
|
|
|
<details class="quote">
|
|
<summary>Source code in <code>src/comfydv/format_string.py</code></summary>
|
|
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">669</span>
|
|
<span class="normal">670</span>
|
|
<span class="normal">671</span>
|
|
<span class="normal">672</span>
|
|
<span class="normal">673</span>
|
|
<span class="normal">674</span>
|
|
<span class="normal">675</span>
|
|
<span class="normal">676</span>
|
|
<span class="normal">677</span>
|
|
<span class="normal">678</span>
|
|
<span class="normal">679</span>
|
|
<span class="normal">680</span>
|
|
<span class="normal">681</span>
|
|
<span class="normal">682</span>
|
|
<span class="normal">683</span>
|
|
<span class="normal">684</span>
|
|
<span class="normal">685</span>
|
|
<span class="normal">686</span>
|
|
<span class="normal">687</span>
|
|
<span class="normal">688</span>
|
|
<span class="normal">689</span>
|
|
<span class="normal">690</span>
|
|
<span class="normal">691</span>
|
|
<span class="normal">692</span>
|
|
<span class="normal">693</span>
|
|
<span class="normal">694</span>
|
|
<span class="normal">695</span>
|
|
<span class="normal">696</span>
|
|
<span class="normal">697</span>
|
|
<span class="normal">698</span>
|
|
<span class="normal">699</span>
|
|
<span class="normal">700</span>
|
|
<span class="normal">701</span>
|
|
<span class="normal">702</span>
|
|
<span class="normal">703</span>
|
|
<span class="normal">704</span>
|
|
<span class="normal">705</span>
|
|
<span class="normal">706</span>
|
|
<span class="normal">707</span>
|
|
<span class="normal">708</span>
|
|
<span class="normal">709</span>
|
|
<span class="normal">710</span>
|
|
<span class="normal">711</span>
|
|
<span class="normal">712</span>
|
|
<span class="normal">713</span>
|
|
<span class="normal">714</span>
|
|
<span class="normal">715</span>
|
|
<span class="normal">716</span>
|
|
<span class="normal">717</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="nd">@PromptServer</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/update_format_string_node"</span><span class="p">)</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_format_string_node</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""</span>
|
|
<span class="sd"> AIOHTTP route handler for updating a FormatString node's configuration.</span>
|
|
|
|
<span class="sd"> This endpoint receives JSON data containing a node ID, template type, and template,</span>
|
|
<span class="sd"> then updates the node's configuration based on the template.</span>
|
|
|
|
<span class="sd"> Args:</span>
|
|
<span class="sd"> request (web.Request): The HTTP request object containing JSON data.</span>
|
|
|
|
<span class="sd"> Returns:</span>
|
|
<span class="sd"> web.Response: JSON response with the updated node configuration.</span>
|
|
|
|
<span class="sd"> Example:</span>
|
|
<span class="sd"> This would typically be called by the frontend JavaScript via a POST request:</span>
|
|
|
|
<span class="sd"> ```javascript</span>
|
|
<span class="sd"> // In ComfyUI frontend</span>
|
|
<span class="sd"> fetch("/update_format_string_node", {</span>
|
|
<span class="sd"> method: "POST",</span>
|
|
<span class="sd"> headers: { "Content-Type": "application/json" },</span>
|
|
<span class="sd"> body: JSON.stringify({</span>
|
|
<span class="sd"> nodeId: "node_123",</span>
|
|
<span class="sd"> template_type: "Simple",</span>
|
|
<span class="sd"> template: "Hello {name}"</span>
|
|
<span class="sd"> })</span>
|
|
<span class="sd"> }).then(response => response.json())</span>
|
|
<span class="sd"> .then(data => console.log(data));</span>
|
|
<span class="sd"> ```</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">request</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
|
<span class="n">node_id</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"nodeId"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
<span class="n">template_type</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template_type"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
<span class="n">template</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"template"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span>
|
|
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
|
<span class="s2">"Web API: update_format_string_node - node_id: </span><span class="si">%s</span><span class="s2">, template_type: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">node_id</span><span class="p">,</span>
|
|
<span class="n">template_type</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="n">updated_config</span> <span class="o">=</span> <span class="n">FormatString</span><span class="o">.</span><span class="n">update_widget</span><span class="p">(</span><span class="n">node_id</span><span class="p">,</span> <span class="n">template_type</span><span class="p">,</span> <span class="n">template</span><span class="p">)</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">"Successfully updated config for node </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">node_id</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">json_response</span><span class="p">(</span><span class="n">updated_config</span><span class="p">)</span>
|
|
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
|
<span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Error updating node config: </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">),</span> <span class="n">exc_info</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">json_response</span><span class="p">({</span><span class="s2">"error"</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)},</span> <span class="n">status</span><span class="o">=</span><span class="mi">500</span><span class="p">)</span>
|
|
</code></pre></div></td></tr></table></div>
|
|
</details>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
|
|
|
|
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
|
</div>
|
|
|
|
</main>
|
|
|
|
<footer class="md-footer">
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-copyright">
|
|
|
|
|
|
Made with
|
|
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
|
Material for MkDocs
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
<div class="md-dialog" data-md-component="dialog">
|
|
<div class="md-dialog__inner md-typeset"></div>
|
|
</div>
|
|
|
|
|
|
<script id="__config" type="application/json">{"base": "../../..", "features": [], "search": "../../../assets/javascripts/workers/search.f8cc74c7.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
|
|
|
|
|
|
<script src="../../../assets/javascripts/bundle.c8b220af.min.js"></script>
|
|
|
|
|
|
</body>
|
|
</html> |