diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d6a77d..48b9b4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # v0.0.1 MVP nodes: +- `Add String to Format-Dict` - `Format-Dict from Text` - `Format-Dict Preview` - `String Formatter` diff --git a/__init__.py b/__init__.py index df80d2b..83000be 100644 --- a/__init__.py +++ b/__init__.py @@ -4,16 +4,19 @@ import typing as _t +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 NODE_CLASS_MAPPINGS: _t.Dict[str, type] = { + 'StringConstructorDictAddString': StringConstructorDictAddString, 'StringConstructorDictFromText': StringConstructorDictFromText, 'StringConstructorDictPreview': StringConstructorDictPreview, 'StringConstructorFormatter': StringConstructorFormatter, } NODE_DISPLAY_NAME_MAPPINGS: _t.Dict[str, str] = { + 'StringConstructorDictAddString': "Add String to Format-Dict", 'StringConstructorDictFromText': "Format-Dict from Text", 'StringConstructorDictPreview': "Preview Format-Dict", 'StringConstructorFormatter': "String Formatter", diff --git a/funcs_dict_add_string.py b/funcs_dict_add_string.py new file mode 100644 index 0000000..da61249 --- /dev/null +++ b/funcs_dict_add_string.py @@ -0,0 +1,29 @@ +# encoding: utf-8 +""" +The actual code (MVC pattern) for `StringConstructorDictString` node. +""" + +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 + +def set_dict_string( + name: str, value: str, strip_lines=True, in_dict: _t.Dict[str, _T] = None, + # unique_id: str = None, +): + """Update/append a string to the dict.""" + out_dict: _t.Dict[str, _T] = _verify_input_dict(in_dict) + errors_dict: _t.Dict[_t.Any, str] = dict() + name = _validate_key(name, errors_dict) + _raise_from_errors_dict(errors_dict) + value = str(value) + if strip_lines: + value = '\n'.join( + x.strip() for x in value.splitlines() + ) + new_dict: _t.Dict[str, str] = {name: value} + out_dict.update(new_dict) + return (_deepfreeze(out_dict),) diff --git a/node_dict_add_string.py b/node_dict_add_string.py new file mode 100644 index 0000000..189c7ff --- /dev/null +++ b/node_dict_add_string.py @@ -0,0 +1,65 @@ +# encoding: utf-8 +""" +""" + +import typing as _t + +from inspect import cleandoc as _cleandoc + +from frozendict import deepfreeze as _deepfreeze + +from comfy.comfy_types.node_typing import IO as _IO + +from . import _meta +from .docstring_formatter import format_docstring as _format_docstring +from .enums import DataTypes as _DataTypes +from .funcs_dict_add_string import set_dict_string as _set_dict_string + + +# A tiny optimization by reusing the same immutable dict: +_input_types = _deepfreeze({ + 'required': { + 'name': (_IO.STRING, {'tooltip': ( + "Name of the substring inserted into the dict. " + "It must comprise only of latin letters, digits and underscores + it can't start with a digit." + )}), + 'cleanup': (_IO.BOOLEAN, {'default': True, 'label_on': 'extra spaces', 'label_off': 'no', 'tooltip': ( + "When enabled, each line in the sub-string is stripped from any spaces at its start and end." + )}), + 'string': (_IO.STRING, {'multiline': True, 'tooltip': "The actual sub-string to set into the dict."}), + }, + 'optional': { + 'str_dict': _DataTypes.input_str_dict(tooltip=( + "The dictionary to take named sub-strings from. It could be left unconnected, if the pattern doesn't reference " + "any sub-strings - then, this node acts exactly the same as a regular string-primitive node." + )), + }, + # 'hidden': { + # 'unique_id': 'UNIQUE_ID', # used for text display at the bottom of the node + # }, +}) + + +class StringConstructorDictAddString: + """Add/update a string to the Format-Dict.""" + NODE_NAME = 'StringConstructorDictAddString' + CATEGORY = _meta.category + DESCRIPTION = _format_docstring(_cleandoc(__doc__)) + + OUTPUT_NODE = True # Just to show the status message even if not connected to anything + + FUNCTION = 'main' + RETURN_TYPES = (_DataTypes.STR_DICT, ) + RETURN_NAMES = (_DataTypes.STR_DICT.lower(), ) + # OUTPUT_TOOLTIPS = tuple() + + @classmethod + def INPUT_TYPES(cls): + return _input_types + + def main( + self, name: str, cleanup: bool, string: str, + str_dict: _t.Dict[str, _t.Any] = None, + # unique_id: str = None, + ): + return _set_dict_string(name, string, strip_lines=cleanup, in_dict=str_dict)