Merge branch 'dev': v1.0.2

This commit is contained in:
Lex Darlog (DRL)
2025-07-25 04:15:23 +05:00
10 changed files with 99 additions and 17 deletions
+8 -2
View File
@@ -1,7 +1,13 @@
## `TODO`
- Multi-item nodes.
- Bulk `Search & Replace` within **keys** in dictionary.
The pack has already started to sip into dictionary-editing domain. Only the validator and the actual formatting node needs to stay. The rest need to go to their own repo.
- ~~Multi-item nodes.~~
- ~~Bulk `Search & Replace` within **keys** in dictionary.~~
# v1.0.2
- New node: `Validate Format-Dict`
# v1.0.1
+3
View File
@@ -9,6 +9,7 @@ from .node_dict_add_string import StringConstructorDictAddString
from .node_dict_from_text import StringConstructorDictFromText
from .node_dict_preview import StringConstructorDictPreview
from .node_formatter import StringConstructorFormatter
from .node_validate_keys import StringConstructorValidateKeys
NODE_CLASS_MAPPINGS: _t.Dict[str, type] = {
'StringConstructorDictAddAny': StringConstructorDictAddAny,
@@ -16,6 +17,7 @@ NODE_CLASS_MAPPINGS: _t.Dict[str, type] = {
'StringConstructorDictFromText': StringConstructorDictFromText,
'StringConstructorDictPreview': StringConstructorDictPreview,
'StringConstructorFormatter': StringConstructorFormatter,
'StringConstructorValidateKeys': StringConstructorValidateKeys,
}
NODE_DISPLAY_NAME_MAPPINGS: _t.Dict[str, str] = {
'StringConstructorDictAddAny': "Add ANY to Format-Dict (Advanced)",
@@ -23,6 +25,7 @@ NODE_DISPLAY_NAME_MAPPINGS: _t.Dict[str, str] = {
'StringConstructorDictFromText': "Format-Dict from Text",
'StringConstructorDictPreview': "Preview Format-Dict",
'StringConstructorFormatter': "String Formatter",
'StringConstructorValidateKeys': "Validate Format-Dict",
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
+15 -3
View File
@@ -60,13 +60,15 @@ def _raise_from_errors_dict(
raise KeyError(msg)
def _verify_input_dict(input_dict: _t.Dict[str, _T] = None) -> _t.Dict[str, _T]:
def _verify_input_dict(input_dict: _t.Dict[str, _T] = None, error_if_none=False):
"""
Verify input dict to have only valid keys. Raises errors if invalid ones found.
Always returns a new dict instance (shallow copy if non-empty dict passed).
"""
if input_dict is None:
return dict()
if error_if_none:
raise TypeError("No input-dict")
return
if not isinstance(input_dict, dict):
raise TypeError(f"Input-dict isn't a dict. Got: {input_dict!r}")
@@ -78,4 +80,14 @@ def _verify_input_dict(input_dict: _t.Dict[str, _T] = None) -> _t.Dict[str, _T]:
errors_dict,
"Invalid input-dict:\n{}", "Invalid keys (string names) in input-dict:\n{}"
)
def _verify_input_dict_into_new(input_dict: _t.Dict[str, _T] = None) -> _t.Dict[str, _T]:
"""
Verify input dict to have only valid keys. Raises errors if invalid ones found.
Always returns a new dict instance (shallow copy if non-empty dict passed).
"""
if input_dict is None:
return dict()
_verify_input_dict(input_dict)
return dict(input_dict)
+2 -2
View File
@@ -7,7 +7,7 @@ import typing as _t
from frozendict import deepfreeze as _deepfreeze
from .funcs_common import _raise_from_errors_dict, _validate_key, _verify_input_dict
from .funcs_common import _raise_from_errors_dict, _validate_key, _verify_input_dict_into_new
def set_dict_any_type_item(
@@ -15,7 +15,7 @@ def set_dict_any_type_item(
# unique_id: str = None,
) -> _t.Tuple[_t.Dict[str, _t.Any]]:
"""Update/append an item of any type to the dict."""
out_dict: _t.Dict[str, _t.Any] = _verify_input_dict(in_dict)
out_dict: _t.Dict[str, _t.Any] = _verify_input_dict_into_new(in_dict)
if value is None:
return (_deepfreeze(in_dict), ) # No need to create another dict instance if it's already frozen
+2 -2
View File
@@ -8,7 +8,7 @@ import typing as _t
from frozendict import deepfreeze as _deepfreeze
from .enums import T as _T
from .funcs_common import _raise_from_errors_dict, _validate_key, _verify_input_dict
from .funcs_common import _raise_from_errors_dict, _validate_key, _verify_input_dict_into_new
def set_dict_string(
@@ -16,7 +16,7 @@ def set_dict_string(
# unique_id: str = None,
) -> _t.Tuple[_t.Dict[str, _t.Union[_T, str]]]:
"""Update/append a string to the dict."""
out_dict: _t.Dict[str, _t.Union[_T, str]] = _verify_input_dict(in_dict)
out_dict: _t.Dict[str, _t.Union[_T, str]] = _verify_input_dict_into_new(in_dict)
errors_dict: _t.Dict[_t.Any, str] = dict()
name = _validate_key(name, errors_dict)
_raise_from_errors_dict(errors_dict)
+2 -2
View File
@@ -8,7 +8,7 @@ import typing as _t
from frozendict import frozendict as _frozendict, deepfreeze as _deepfreeze
from .enums import T as _T
from .funcs_common import _show_text_on_node, _raise_from_errors_dict, _validate_key, _verify_input_dict
from .funcs_common import _show_text_on_node, _raise_from_errors_dict, _validate_key, _verify_input_dict_into_new
def _return_line_raw(line_raw: str, line_stripped:str) -> str:
@@ -61,7 +61,7 @@ def parse_dict_from_text(
multiline_str: str, strip_lines=True,
show: bool = True, in_dict: _t.Dict[str, _T] = None, unique_id: str = None
) -> _t.Tuple[_t.Dict[str, _T]]:
out_dict: _t.Dict[str, _T] = _verify_input_dict(in_dict)
out_dict: _t.Dict[str, _T] = _verify_input_dict_into_new(in_dict)
errors_dict: _t.Dict[_t.Any, str] = dict()
new_dict: _t.Dict[str, str] = {
+2 -2
View File
@@ -7,7 +7,7 @@ import typing as _t
from pprint import pformat as _pformat
from .funcs_common import _show_text_on_node, _verify_input_dict
from .funcs_common import _show_text_on_node, _verify_input_dict_into_new
def _to_regular_dict_recursive_copy(input_dict: dict = None) -> dict:
@@ -32,7 +32,7 @@ def _preview_single_entry(key: str, value) -> str:
def _preview_message(input_dict: dict = None):
input_dict = _to_regular_dict_recursive_copy(_verify_input_dict(input_dict))
input_dict = _to_regular_dict_recursive_copy(_verify_input_dict_into_new(input_dict))
parts: _t.List[str] = [
_preview_single_entry(k, v) for k, v in input_dict.items()
]
+2 -2
View File
@@ -7,7 +7,7 @@ import typing as _t
import sys as _sys
from .funcs_common import _show_text_on_node, _verify_input_dict
from .funcs_common import _show_text_on_node, _verify_input_dict_into_new
_RECURSION_LIMIT = max(int(_sys.getrecursionlimit()), 10) # You can externally monkey-patch it... but if it blows up, your fault 🤷🏻‍♂️
@@ -45,7 +45,7 @@ def formatter(
template: str, recursive: bool = False, format_dict: _t.Dict[str, _t.Any] = None,
show: bool = True, unique_id: str = None
) -> _t.Tuple[str]:
format_dict = _verify_input_dict(format_dict)
format_dict = _verify_input_dict_into_new(format_dict)
if not isinstance(template, str):
raise TypeError(f"Not a string: {template!r}")
+61
View File
@@ -0,0 +1,61 @@
# encoding: utf-8
"""
"""
import typing as _t
from inspect import cleandoc as _cleandoc
from frozendict import deepfreeze as _deepfreeze
from . import _meta
from .docstring_formatter import format_docstring as _format_docstring
from .enums import DataTypes as _DataTypes
from .funcs_common import _verify_input_dict, _show_text_on_node, _T
_input_types = _deepfreeze({
'required': {
'dict': _DataTypes.input_dict(),
},
# 'optional': {},
# 'hidden': {
# 'unique_id': 'UNIQUE_ID', # used for text display at the bottom of the node
# },
})
class StringConstructorValidateKeys:
"""
Verify the dict to have string-formatting-compatible keys. No need to add it before "String Formatter" node,
but it might be handy to verify the dict right after it's created.
"""
NODE_NAME = 'StringConstructorValidateKeys'
CATEGORY = _meta.category
DESCRIPTION = _format_docstring(_cleandoc(__doc__))
OUTPUT_NODE = True
FUNCTION = 'main'
RETURN_TYPES = (_DataTypes.DICT, )
RETURN_NAMES = (_DataTypes.DICT.lower(), )
# OUTPUT_TOOLTIPS = tuple()
@classmethod
def INPUT_TYPES(cls):
return _input_types
@staticmethod
def main(
dict: _t.Dict[str, _T],
# unique_id: str = None,
) -> _t.Tuple[_t.Dict[str, _T]]:
# try:
# _verify_input_dict(dict, error_if_none=True)
# except Exception:
# _show_text_on_node('❌', unique_id)
# raise
# return (Null, )
# _show_text_on_node('✅', unique_id)
_verify_input_dict(dict, error_if_none=True)
return (dict, )
+2 -2
View File
@@ -1,7 +1,7 @@
[project]
name = "string-constructor"
description = "Composing prompt variants from the same text pieces with ease:\n• Build your \"library\" (dictionary) of named text chunks (sub-strings) to use it across the entire workflow.\n• Compile these snippets into different prompts in-place - with just one string formatting node.\n• Freely update the dictionary down the line - get different prompts.\n• Reference text chunks within each other to build dependent hierarchies of less/more detailed descriptions.\n• A real life-saver for regional prompting (aka area composition)."
version = "1.0.1"
description = "String formatting (compiling text from pieces) made for humans:\n• Turn parts of prompt into a dictionary - to share them all across the entire workflow as a single connection.\n• Compose your prompt in-place from these snippets and regular text - with just one text field.\n• Easily update the dictionary down the line - get different prompts from the same template.\n• Reference text chunks within each other to build complex hierarchies of self-updating prompts.\n• A true time-saver for regional prompting (aka area composition)."
version = "1.0.2"
authors = [
{name = "Lex Darlog"}
]