diff --git a/CHANGELOG.md b/CHANGELOG.md index b402737..0158609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,22 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.0.0] - 2026-09-11 -- Critical change that ensures reliablity and **should** have no bad side - effects, but when you see any, please report: - DICT, LIST, SET and Data List nodes (plus the DICT/LIST-taking STRING nodes) +Critical change that ensures reliablity and **should** have no bad side +effects, but when you see any, please report: +- DICT, LIST, SET and Data List nodes (plus the DICT/LIST-taking STRING nodes) now degrade gracefully when their data source is not connected (`None`) instead of raising: read/query nodes return their natural "no data" result (the `get` default, an empty list, `False`, `0`, `None`), and transform nodes behave as if given an empty container. -- Add a "continue if not empty" flow-control node: it passes a value through - unchanged when it is non-empty, and blocks execution (via an execution blocker) - when the value is empty. It is list-aware (`INPUT_IS_LIST` / `OUTPUT_IS_LIST`), - so it is immune to ComfyUI's empty-input batching crash and passes data lists - through unchanged. By default the block is silent; an optional `message` can be - set to show a dialog. Use it before nodes that cannot handle an empty input - (e.g. a node receiving an empty Data List) to stop execution instead of failing. -- Add "create DICT from JSON string" and "create LIST from JSON string" nodes to - parse a multiline JSON object/array into a DICT/LIST - "save IMAGE to file" and "save IMAGE+MASK to file": `format` is now a dropdown (still connectable as a STRING) whose entries are derived from the formats the installed Pillow/image plugins can actually write (RGB node offers them all, @@ -32,6 +23,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 (auto-numbered under the output dir); both modes accept ComfyUI templates such as `%date:yyyy-MM-dd%` +Backward compatible changes: + - Add a "continue if not empty" flow-control node: it passes a value through + unchanged when it is non-empty, and blocks execution (via an execution blocker) + when the value is empty. It is list-aware (`INPUT_IS_LIST` / `OUTPUT_IS_LIST`), + so it is immune to ComfyUI's empty-input batching crash and passes data lists + through unchanged. By default the block is silent; an optional `message` can be + set to show a dialog. Use it before nodes that cannot handle an empty input + (e.g. a node receiving an empty Data List) to stop execution instead of failing. +- Add "create DICT from JSON string" and "create LIST from JSON string" nodes to + parse a multiline JSON object/array into a DICT/LIST + + ## [1.8.1] - 2026-09-06 - Add optional additional input for image saving to also save the prompt when provided diff --git a/src/basic_data_handling/control_flow_nodes.py b/src/basic_data_handling/control_flow_nodes.py index 96d64c1..6793ae6 100644 --- a/src/basic_data_handling/control_flow_nodes.py +++ b/src/basic_data_handling/control_flow_nodes.py @@ -13,7 +13,16 @@ except: NUMBER = "FLOAT,INT" ANY = "*" ComfyNodeABC = object - ExecutionBlocker = lambda x: x + + class ExecutionBlocker: + """Stand-in used when ComfyUI is not installed (e.g. in the test-suite). + + Mirrors ``comfy_execution.graph_utils.ExecutionBlocker``: it only stores + the message, but its class name shows up in the default ``repr`` exactly + like the real one, so callers/tests can still detect a blocker. + """ + def __init__(self, message): + self.message = message from ._dynamic_input import ContainsDynamicDict diff --git a/src/basic_data_handling/path_nodes.py b/src/basic_data_handling/path_nodes.py index 92358bd..230a7e6 100644 --- a/src/basic_data_handling/path_nodes.py +++ b/src/basic_data_handling/path_nodes.py @@ -1270,18 +1270,26 @@ def _discover_save_formats() -> tuple[list[str], list[str]]: return all_formats, alpha_formats -(_IMAGE_SAVE_FORMATS, _IMAGE_SAVE_ALPHA_FORMATS) = _discover_save_formats() +# Discovering the formats probes the installed Pillow/plugins, so it must not be +# required for importing this module: environments that only inspect the node +# metadata (e.g. the comfy-org/node-diff CI) have no Pillow installed. Fall back +# to the classic formats there instead of failing to load the whole node pack. +try: + (_IMAGE_SAVE_FORMATS, _IMAGE_SAVE_ALPHA_FORMATS) = _discover_save_formats() +except ModuleNotFoundError: + _IMAGE_SAVE_FORMATS = ["png", "jpg", "webp", "jxl", "bmp", "tif", "gif"] + _IMAGE_SAVE_ALPHA_FORMATS = ["png", "webp", "jxl"] +else: + # Always make sure the most common formats are present when the backend + # supports them (guards against an odd Pillow not probing its core formats). + for _token in ("png", "jpg", "webp"): + if _token in _PIL_FORMAT_BY_TOKEN and _PIL_FORMAT_BY_TOKEN[_token] and _token not in _IMAGE_SAVE_FORMATS: + _IMAGE_SAVE_FORMATS.insert(0, _token) -# Always make sure the most common formats are present when the backend supports -# them (guards against an odd Pillow not probing its own core formats). -for _token in ("png", "jpg", "webp"): - if _token in _PIL_FORMAT_BY_TOKEN and _PIL_FORMAT_BY_TOKEN[_token] and _token not in _IMAGE_SAVE_FORMATS: - _IMAGE_SAVE_FORMATS.insert(0, _token) - -# Log the supported save formats once at node-load time, so users can see what -# the running Pillow/image plugins can write. -print("Basic data handling: supported image formats: " + ", ".join(_IMAGE_SAVE_FORMATS)) -print("Basic data handling: supported IMAGE+MASK (alpha) formats: " + ", ".join(_IMAGE_SAVE_ALPHA_FORMATS)) + # Log the supported save formats once at node-load time, so users can see + # what the running Pillow/image plugins can write. + print("Basic data handling: supported image formats: " + ", ".join(_IMAGE_SAVE_FORMATS)) + print("Basic data handling: supported IMAGE+MASK (alpha) formats: " + ", ".join(_IMAGE_SAVE_ALPHA_FORMATS)) def _normalize_image_format(format: str) -> str: