From 52494ac1d0a97e73e2df2679139c952c4cd8291b Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:57:39 -0300 Subject: [PATCH 1/2] [fix] issue #4 False-positive "Input-dict isn't a dict" error on older python versions (3.10) --- funcs_common.py | 6 ++++-- node_dict_preview.py | 10 ++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/funcs_common.py b/funcs_common.py index cca9b4f..6c5ec7c 100644 --- a/funcs_common.py +++ b/funcs_common.py @@ -7,7 +7,7 @@ import typing as _t import re as _re -from frozendict import deepfreeze as _deepfreeze +from frozendict import deepfreeze as _deepfreeze, frozendict as _frozendict from server import PromptServer as _PromptServer @@ -71,7 +71,9 @@ def _verify_input_dict(input_dict: _t.Dict[str, _T] = None, error_if_none=False) raise TypeError("No input-dict") return - if not isinstance(input_dict, dict): + # In py3.10, frozendict isn't a dict, but is a `typing.Mapping`. + # So, this many types to check against: + if not isinstance(input_dict, (dict, _frozendict, _t.Mapping)): raise TypeError(f"Input-dict isn't a dict. Got: {input_dict!r}") errors_dict: _t.Dict[_t.Any, str] = dict() diff --git a/node_dict_preview.py b/node_dict_preview.py index e599de3..beacc28 100644 --- a/node_dict_preview.py +++ b/node_dict_preview.py @@ -7,7 +7,7 @@ import typing as _t from inspect import cleandoc as _cleandoc from pprint import pformat as _pformat -from frozendict import deepfreeze as _deepfreeze +from frozendict import deepfreeze as _deepfreeze, frozendict as _frozendict from . import _meta from .docstring_formatter import format_docstring as _format_docstring @@ -24,7 +24,13 @@ def _to_regular_dict_recursive_copy(input_dict: dict = None) -> dict: if not input_dict: return dict() return { - k: (_to_regular_dict_recursive_copy(v) if isinstance(v, dict) else v) + k: ( + _to_regular_dict_recursive_copy(v) + # In py3.10, frozendict isn't a dict, but is a `typing.Mapping`. + # So, this many types to check against: + if isinstance(v, (dict, _frozendict, _t.Mapping)) + else v + ) for k, v in input_dict.items() } From 6cc98314ec60d8befd013392a61154b0790e88b1 Mon Sep 17 00:00:00 2001 From: "Lex Darlog (DRL)" <3897975+Lex-DRL@users.noreply.github.com> Date: Wed, 4 Mar 2026 23:37:24 -0300 Subject: [PATCH 2/2] `v1.1.2` --- CHANGELOG.md | 10 +++++++--- pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8764012..aa98c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ No other features planned (but I have nothing against improvements: feel free to To do some fancy stuff with dictionaries, specialized node packs are recommended instead. +# v1.1.2 + +- `[fix]` [False-positive `Input-dict isn't a dict` type-check error on older python versions (3.10)](https://github.com/Lex-DRL/ComfyUI-StringConstructor/issues/4) + # v1.1.1 - Shorten tooltip for `safe_format` toggle. @@ -19,7 +23,7 @@ To do some fancy stuff with dictionaries, specialized node packs are recommended - All the secondary dict-related nodes are moved to a subcategory. - Default node name shortened: `Format-Dict` → just `Dict`. -- New node: `Extract String from Dict` - to be actually self-sufficient for the common use cases. +- `✨New node` - `Extract String from Dict` - to be actually self-sufficient for the common use cases. # v1.0.3 @@ -28,11 +32,11 @@ To do some fancy stuff with dictionaries, specialized node packs are recommended # v1.0.2 -- New node: `Validate Format-Dict` +- `✨New node` - `Validate Format-Dict` # v1.0.1 -- ❗ Recursive formatting. +- `✨New feature` ❗ Recursive formatting. - Tiny tweaks to tooltips/descriptions. # v1.0.0 diff --git a/pyproject.toml b/pyproject.toml index 164a926..771309e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "string-constructor" -version = "1.1.1" +version = "1.1.2" 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)." license = {file = "LICENSE.md"} readme = "README.md"