From e452a2e645b0579f15148e8acc00cb19b2fb8860 Mon Sep 17 00:00:00 2001 From: StableLlama Date: Fri, 9 May 2025 23:38:54 +0200 Subject: [PATCH 1/5] Add more unit tests Little naming cleanup (first round) --- src/basic_data_handling/__init__.py | 6 +- src/basic_data_handling/casting_nodes.py | 4 +- ...{control_flow.py => control_flow_nodes.py} | 0 src/basic_data_handling/data_list_nodes.py | 4 +- src/basic_data_handling/string_nodes.py | 6 +- tests/test_casting_nodes.py | 81 +++++++++ tests/test_comparison_nodes.py | 115 ++++++++++++ tests/test_control_flow_nodes.py | 39 +++++ tests/test_data_list_nodes.py | 164 ++++++++++++++++++ tests/test_string_nodes.py | 4 +- 10 files changed, 411 insertions(+), 12 deletions(-) rename src/basic_data_handling/{control_flow.py => control_flow_nodes.py} (100%) create mode 100644 tests/test_casting_nodes.py create mode 100644 tests/test_comparison_nodes.py create mode 100644 tests/test_control_flow_nodes.py create mode 100644 tests/test_data_list_nodes.py diff --git a/src/basic_data_handling/__init__.py b/src/basic_data_handling/__init__.py index b900d85..6e867b9 100644 --- a/src/basic_data_handling/__init__.py +++ b/src/basic_data_handling/__init__.py @@ -1,4 +1,4 @@ -from . import (boolean_nodes, casting_nodes, comparison_nodes, control_flow, +from . import (boolean_nodes, casting_nodes, comparison_nodes, control_flow_nodes, data_list_nodes, dict_nodes, float_nodes, int_nodes, list_nodes, math_nodes, path_nodes, regex_nodes, set_nodes, string_nodes) @@ -6,7 +6,7 @@ NODE_CLASS_MAPPINGS = {} NODE_CLASS_MAPPINGS.update(boolean_nodes.NODE_CLASS_MAPPINGS) NODE_CLASS_MAPPINGS.update(casting_nodes.NODE_CLASS_MAPPINGS) NODE_CLASS_MAPPINGS.update(comparison_nodes.NODE_CLASS_MAPPINGS) -NODE_CLASS_MAPPINGS.update(control_flow.NODE_CLASS_MAPPINGS) +NODE_CLASS_MAPPINGS.update(control_flow_nodes.NODE_CLASS_MAPPINGS) NODE_CLASS_MAPPINGS.update(data_list_nodes.NODE_CLASS_MAPPINGS) NODE_CLASS_MAPPINGS.update(dict_nodes.NODE_CLASS_MAPPINGS) NODE_CLASS_MAPPINGS.update(float_nodes.NODE_CLASS_MAPPINGS) @@ -22,7 +22,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {} NODE_DISPLAY_NAME_MAPPINGS.update(boolean_nodes.NODE_DISPLAY_NAME_MAPPINGS) NODE_DISPLAY_NAME_MAPPINGS.update(casting_nodes.NODE_DISPLAY_NAME_MAPPINGS) NODE_DISPLAY_NAME_MAPPINGS.update(comparison_nodes.NODE_DISPLAY_NAME_MAPPINGS) -NODE_DISPLAY_NAME_MAPPINGS.update(control_flow.NODE_DISPLAY_NAME_MAPPINGS) +NODE_DISPLAY_NAME_MAPPINGS.update(control_flow_nodes.NODE_DISPLAY_NAME_MAPPINGS) NODE_DISPLAY_NAME_MAPPINGS.update(data_list_nodes.NODE_DISPLAY_NAME_MAPPINGS) NODE_DISPLAY_NAME_MAPPINGS.update(dict_nodes.NODE_DISPLAY_NAME_MAPPINGS) NODE_DISPLAY_NAME_MAPPINGS.update(float_nodes.NODE_DISPLAY_NAME_MAPPINGS) diff --git a/src/basic_data_handling/casting_nodes.py b/src/basic_data_handling/casting_nodes.py index 8681b06..ce6924b 100644 --- a/src/basic_data_handling/casting_nodes.py +++ b/src/basic_data_handling/casting_nodes.py @@ -51,7 +51,7 @@ class CastToInt: def convert_to_int(self, input: Any) -> tuple[int]: try: return (int(input),) - except ValueError: + except (ValueError, TypeError): raise ValueError(f"Cannot convert {input} to an INT.") @@ -79,7 +79,7 @@ class CastToFloat: def convert_to_float(self, input: Any) -> tuple[float]: try: return (float(input),) - except ValueError: + except (ValueError, TypeError): raise ValueError(f"Cannot convert {input} to a FLOAT.") diff --git a/src/basic_data_handling/control_flow.py b/src/basic_data_handling/control_flow_nodes.py similarity index 100% rename from src/basic_data_handling/control_flow.py rename to src/basic_data_handling/control_flow_nodes.py diff --git a/src/basic_data_handling/data_list_nodes.py b/src/basic_data_handling/data_list_nodes.py index 40d3198..8efe914 100644 --- a/src/basic_data_handling/data_list_nodes.py +++ b/src/basic_data_handling/data_list_nodes.py @@ -481,7 +481,7 @@ class DataListGetItem: def INPUT_TYPES(cls): return { "required": { - "input_list": ("*",), + "list": ("*",), "index": ("INT", {"default": 0}), } } @@ -557,7 +557,7 @@ class DataListContains: def INPUT_TYPES(cls): return { "required": { - "input_list": ("*",), + "list": ("*",), "value": ("*",), } } diff --git a/src/basic_data_handling/string_nodes.py b/src/basic_data_handling/string_nodes.py index 1996252..fe1e729 100644 --- a/src/basic_data_handling/string_nodes.py +++ b/src/basic_data_handling/string_nodes.py @@ -79,7 +79,7 @@ class StringCenter: return (string.center(width, fillchar),) -class StringConcat: +class DataStringConcat: """Combines two text strings together, joining them end-to-end.""" @classmethod def INPUT_TYPES(cls): @@ -1771,7 +1771,7 @@ NODE_CLASS_MAPPINGS = { "StringCapitalize": StringCapitalize, "StringCasefold": StringCasefold, "StringCenter": StringCenter, - "StringConcat": StringConcat, + "DataStringConcat": DataStringConcat, "StringCount": StringCount, "StringDecode": StringDecode, "StringEncode": StringEncode, @@ -1816,7 +1816,7 @@ NODE_DISPLAY_NAME_MAPPINGS = { "StringCapitalize": "capitalize", "StringCasefold": "casefold", "StringCenter": "center", - "StringConcat": "concat", + "DataStringConcat": "concat", "StringCount": "count", "StringDecode": "decode", "StringEncode": "encode", diff --git a/tests/test_casting_nodes.py b/tests/test_casting_nodes.py new file mode 100644 index 0000000..b65ec1e --- /dev/null +++ b/tests/test_casting_nodes.py @@ -0,0 +1,81 @@ +import pytest +from src.basic_data_handling.casting_nodes import (CastToString, CastToInt, CastToFloat, CastToBoolean, + CastToList, CastDataListToList, CastToSet, CastDataListToSet, + CastToDict) + + +def test_cast_to_string(): + node = CastToString() + assert node.convert_to_string(123) == ("123",) + assert node.convert_to_string(None) == ("None",) + assert node.convert_to_string(True) == ("True",) + assert node.convert_to_string("hello") == ("hello",) + + +def test_cast_to_int(): + node = CastToInt() + assert node.convert_to_int("123") == (123,) + assert node.convert_to_int(456) == (456,) + with pytest.raises(ValueError): + node.convert_to_int("abc") + with pytest.raises(ValueError): + node.convert_to_int(None) + + +def test_cast_to_float(): + node = CastToFloat() + assert node.convert_to_float("123.45") == (123.45,) + assert node.convert_to_float(67.89) == (67.89,) + assert node.convert_to_float(123) == (123.0,) + with pytest.raises(ValueError): + node.convert_to_float("abc") + with pytest.raises(ValueError): + node.convert_to_float(None) + + +def test_cast_to_boolean(): + node = CastToBoolean() + assert node.convert_to_boolean(0) == (False,) + assert node.convert_to_boolean(1) == (True,) + assert node.convert_to_boolean("") == (False,) + assert node.convert_to_boolean("non_empty_string") == (True,) + + +def test_cast_to_list(): + node = CastToList() + assert node.convert_to_list(123) == ([123],) + assert node.convert_to_list([1, 2, 3]) == ([1, 2, 3],) + assert node.convert_to_list("hello") == (["hello"],) + assert node.convert_to_list(None) == ([None],) + + +def test_cast_data_list_to_list(): + node = CastDataListToList() + assert node.convert(list=[1, 2, 3]) == ([1, 2, 3],) + assert node.convert(list=[]) == ([],) + assert node.convert(list=["a", "b", "c"]) == (["a", "b", "c"],) + + +def test_cast_to_set(): + node = CastToSet() + assert node.convert_to_set(123) == ({123},) + assert node.convert_to_set([1, 2, 2]) == ({1, 2},) + assert node.convert_to_set("abc") == ({"abc"},) + assert node.convert_to_set(None) == ({None},) + + +def test_cast_data_list_to_set(): + node = CastDataListToSet() + assert node.convert(list=[1, 2, 3, 3]) == ({1, 2, 3},) + assert node.convert(list=["a", "b", "b"]) == ({"a", "b"},) + assert node.convert(list=[]) == (set(),) + + +def test_cast_to_dict(): + node = CastToDict() + assert node.convert_to_dict({"key": "value"}) == ({"key": "value"},) + assert node.convert_to_dict([("key1", "value1"), ("key2", "value2")]) == ({"key1": "value1", "key2": "value2"},) + with pytest.raises(ValueError): + node.convert_to_dict(123) + with pytest.raises(ValueError): + node.convert_to_dict("string") diff --git a/tests/test_comparison_nodes.py b/tests/test_comparison_nodes.py new file mode 100644 index 0000000..310cb3e --- /dev/null +++ b/tests/test_comparison_nodes.py @@ -0,0 +1,115 @@ +import pytest +from src.basic_data_handling.comparison_nodes import ( + Equal, + NotEqual, + GreaterThan, + LessThan, + GreaterThanOrEqual, + LessThanOrEqual, + StringComparison, + NumberInRange, + IsNull, + CompareLength, +) + + +def test_equal(): + node = Equal() + assert node.compare(10, 10) == (True,) + assert node.compare(10, 20) == (False,) + assert node.compare("hello", "hello") == (True,) + assert node.compare([1, 2], [1, 2]) == (True,) + assert node.compare(None, None) == (True,) + + +def test_not_equal(): + node = NotEqual() + assert node.compare(10, 10) == (False,) + assert node.compare(10, 20) == (True,) + assert node.compare("hello", "world") == (True,) + assert node.compare([1, 2], [1, 3]) == (True,) + assert node.compare(None, []) == (True,) + + +def test_greater_than(): + node = GreaterThan() + assert node.compare(10, 5) == (True,) + assert node.compare(5, 10) == (False,) + assert node.compare(10, 10) == (False,) + assert node.compare(5.6, 2.3) == (True,) + + +def test_less_than(): + node = LessThan() + assert node.compare(5, 10) == (True,) + assert node.compare(10, 5) == (False,) + assert node.compare(10, 10) == (False,) + assert node.compare(2.3, 5.6) == (True,) + + +def test_greater_than_or_equal(): + node = GreaterThanOrEqual() + assert node.compare(10, 10) == (True,) + assert node.compare(15, 10) == (True,) + assert node.compare(5, 10) == (False,) + assert node.compare(5.5, 5.5) == (True,) + + +def test_less_than_or_equal(): + node = LessThanOrEqual() + assert node.compare(10, 10) == (True,) + assert node.compare(5, 15) == (True,) + assert node.compare(15, 5) == (False,) + assert node.compare(3.1, 3.1) == (True,) + + +def test_string_comparison(): + node = StringComparison() + + # Case-sensitive tests + assert node.compare("hello", "hello", "==", "True") == (True,) + assert node.compare("apple", "banana", "<", "True") == (True,) + assert node.compare("apple", "banana", ">", "True") == (False,) + assert node.compare("apple", "apple", "!=", "True") == (False,) + + # Case-insensitive tests + assert node.compare("Hello", "hello", "==", "False") == (True,) + assert node.compare("Apple", "BANANA", "<", "False") == (True,) + assert node.compare("Grape", "GRAPE", ">=", "False") == (True,) + + +def test_number_in_range(): + node = NumberInRange() + + # Inclusive range tests + assert node.check_range(50, 0, 100) == (True,) + assert node.check_range(0, 0, 100) == (True,) + + # Exclusive range tests + assert node.check_range(0, 0, 100, include_min="False") == (False,) + assert node.check_range(100, 0, 100, include_max="False") == (False,) + + # Out of range tests + assert node.check_range(-1, 0, 100) == (False,) + assert node.check_range(101, 0, 100) == (False,) + + +def test_is_null(): + node = IsNull() + assert node.check_null(None) == (True,) + assert node.check_null(0) == (False,) + assert node.check_null("") == (False,) + assert node.check_null([]) == (False,) + + +def test_compare_length(): + node = CompareLength() + + # Valid comparisons + assert node.compare_length([1, 2, 3], "==", 3) == (True, 3) + assert node.compare_length("hello", "!=", 4) == (True, 5) + assert node.compare_length((1, 2), ">", 1) == (True, 2) + + # Invalid comparisons + assert node.compare_length({"key": "value"}, "<", 1) == (False, 1) + assert node.compare_length(123, "==", 0) == (False, -1) # Non-container input edge case diff --git a/tests/test_control_flow_nodes.py b/tests/test_control_flow_nodes.py new file mode 100644 index 0000000..612790c --- /dev/null +++ b/tests/test_control_flow_nodes.py @@ -0,0 +1,39 @@ +import pytest +from src.basic_data_handling.control_flow_nodes import IfElse, SwitchCase + + +def test_if_else(): + node = IfElse() + + # Test where condition is True + assert node.execute(True, "Value if True", "Value if False") == ("Value if True",) + + # Test where condition is False + assert node.execute(False, "Value if True", "Value if False") == ("Value if False",) + + # Test edge cases + assert node.execute(True, 1, 2) == (1,) # Integers + assert node.execute(False, [1, 2, 3], None) == (None,) # Complex types + assert node.execute(True, None, "fallback") == (None,) # Fallback to True branch + + +def test_switch_case(): + node = SwitchCase() + + # Selector within range, valid cases + assert node.execute(0, "Case 0", "Case 1", "Case 2", "Case 3") == ("Case 0",) + assert node.execute(1, "Case 0", "Case 1", "Case 2", "Case 3") == ("Case 1",) + assert node.execute(3, "Case 0", "Case 1", "Case 2", "Case 3") == ("Case 3",) + + # Selector out of range, fallback to default case + assert node.execute(4, "Case 0", "Case 1", "Case 2", "Case 3", default="Default") == ("Default",) + assert node.execute(99, "Case 0", "Case 1", "Case 2", "Case 3", default="Default") == ("Default",) + + # Selector out of range, no default provided + assert node.execute(4, "Case 0", "Case 1", "Case 2", "Case 3") == (None,) + + # Edge cases + assert node.execute(0, None, "Case 1", "Case 2") == (None,) # Case with None + assert node.execute(2, "Case 0", "Case 1", "Case 2") == ("Case 2",) + assert node.execute(0, 123, False, "Case 2") == (123,) # Different data types + assert node.execute(10, "Case 0", "Case 1", "Case 2", default="Fallback") == ("Fallback",) diff --git a/tests/test_data_list_nodes.py b/tests/test_data_list_nodes.py new file mode 100644 index 0000000..2346550 --- /dev/null +++ b/tests/test_data_list_nodes.py @@ -0,0 +1,164 @@ +import pytest +from src.basic_data_handling.data_list_nodes import ( + DataListAppend, + DataListExtend, + DataListInsert, + DataListRemove, + DataListPop, + DataListClear, + DataListIndex, + DataListCount, + DataListSort, + DataListReverse, + DataListCopy, + DataListLength, + DataListSlice, + DataListGetItem, + DataListSetItem, + DataListContains, + DataListCreateEmpty, + DataListZip, + DataListFilter, + DataListMin, + DataListMax, +) + + +def test_append(): + node = DataListAppend() + assert node.append(list=[1, 2, 3], item=[4]) == ([1, 2, 3, 4],) + assert node.append(list=[], item=["test"]) == (["test"],) + assert node.append(list=[1, 2, 3], item=[]) == ([1, 2, 3],) + + +def test_extend(): + node = DataListExtend() + assert node.extend(list_a=[1, 2], list_b=[3, 4]) == ([1, 2, 3, 4],) + assert node.extend(list_a=[], list_b=["a", "b"]) == (["a", "b"],) + assert node.extend(list_a=[1], list_b=[]) == ([1],) + + +def test_insert(): + node = DataListInsert() + assert node.insert(list=[1, 2, 4], index=[2], item=[3]) == ([1, 2, 3, 4],) + assert node.insert(list=[], index=[0], item=["a"]) == (["a"],) + assert node.insert(list=[1, 2], index=[5], item=[3]) == ([1, 2, 3],) # Out-of-range insert + + +def test_remove(): + node = DataListRemove() + assert node.remove(list=[1, 2, 3], value=[2]) == ([1, 3], True) + assert node.remove(list=["a", "b", "a"], value=["a"]) == (["b", "a"], True) + assert node.remove(list=[1, 2, 3], value=[5]) == ([1, 2, 3], False) # Value not found + + +def test_pop(): + node = DataListPop() + assert node.pop(list=[1, 2, 3], index=[1]) == ([1, 3], 2) + assert node.pop(list=["a", "b", "c"], index=[-1]) == (["a", "b"], "c") # Negative index + assert node.pop(list=[], index=[0]) == ([], None) # Pop from empty list + + +def test_clear(): + node = DataListClear() + assert node.clear(list=[1, 2, 3]) == ([],) + assert node.clear(list=[]) == ([],) + + +def test_index(): + node = DataListIndex() + assert node.list_index(list=["a", "b", "c"], value=["b"]) == (1,) + assert node.list_index(list=[1, 2, 3], value=[5]) == (-1,) # Value not found + assert node.list_index(list=[1, 2, 1, 2], value=[1], start=[1]) == (2,) + + +def test_count(): + node = DataListCount() + assert node.count(list=[1, 2, 1, 2], value=[1]) == (2,) + assert node.count(list=["a", "b", "a"], value=["a"]) == (2,) + assert node.count(list=[], value=["x"]) == (0,) + + +def test_sort(): + node = DataListSort() + assert node.sort(list=[3, 2, 1]) == ([1, 2, 3],) + assert node.sort(list=["c", "a", "b"]) == (["a", "b", "c"],) + assert node.sort(list=[3, 1, 2], reverse=["True"]) == ([3, 2, 1],) # Reverse sort + + +def test_reverse(): + node = DataListReverse() + assert node.reverse(list=[1, 2, 3]) == ([3, 2, 1],) + assert node.reverse(list=[]) == ([],) + + +def test_copy(): + node = DataListCopy() + assert node.copy(list=[1, 2, 3]) == ([1, 2, 3],) + assert node.copy(list=[]) == ([],) + + +def test_length(): + node = DataListLength() + assert node.length(list=[1, 2, 3]) == (3,) + assert node.length(list=[]) == (0,) + + +def test_slice(): + node = DataListSlice() + assert node.slice(list=[1, 2, 3, 4, 5], start=[1], stop=[4]) == ([2, 3, 4],) + assert node.slice(list=[1, 2, 3], start=[0], stop=[2], step=[2]) == ([1],) + assert node.slice(list=["a", "b", "c"], start=[-2], stop=[3]) == (["b", "c"],) + + +def test_get_item(): + node = DataListGetItem() + assert node.get_item(list=[1, 2, 3], index=[1]) == (2,) + assert node.get_item(list=["a", "b", "c"], index=[-1]) == ("c",) # Negative index + assert node.get_item(list=[], index=[0]) == (None,) # Out of range + + +def test_set_item(): + node = DataListSetItem() + assert node.set_item(list=[1, 2, 3], index=[1], value=[9]) == ([1, 9, 3],) + assert node.set_item(list=["a", "b", "c"], index=[-1], value=["z"]) == (["a", "b", "z"],) + with pytest.raises(IndexError): + node.set_item(list=[], index=[0], value=["test"]) # Out of range + + +def test_contains(): + node = DataListContains() + assert node.contains(list=[1, 2, 3], value=[2]) == (True,) + assert node.contains(list=["a", "b"], value=["c"]) == (False,) + assert node.contains(list=[], value=["x"]) == (False,) + + +def test_create_empty(): + node = DataListCreateEmpty() + assert node.create_empty() == ([],) + + +def test_zip(): + node = DataListZip() + assert node.zip_lists(list1=[1, 2], list2=["a", "b"]) == ([[1, "a"], [2, "b"]],) + assert node.zip_lists(list1=[1], list2=["a", "b"]) == ([[1, "a"]],) # Shortest list length + + +def test_filter(): + node = DataListFilter() + assert node.filter_data(value=[1, 2, 3], filter=[False, True, False]) == ([1, 3],) + assert node.filter_data(value=[1, 2], filter=[True, True]) == ([],) + + +def test_min(): + node = DataListMin() + assert node.find_min(list=[3, 1, 2]) == (1,) + assert node.find_min(list=[-1, -5, 0]) == (-5,) + assert node.find_min(list=[]) == (None,) + + +def test_max(): + node = DataListMax() + assert node.find_max(list=[3, 1, 2]) == (3,) + assert node.find_max(list=[-1, -5, 0]) == (0,) + assert node.find_max(list=[]) == (None,) diff --git a/tests/test_string_nodes.py b/tests/test_string_nodes.py index ce48d0b..4a096d4 100644 --- a/tests/test_string_nodes.py +++ b/tests/test_string_nodes.py @@ -4,7 +4,7 @@ from src.basic_data_handling.string_nodes import ( StringCapitalize, StringCasefold, StringCenter, - StringConcat, + DataStringConcat, StringCount, StringDecode, StringEncode, @@ -72,7 +72,7 @@ def test_center(): assert node.center("test", 10, "ab") == ("aaatestaaa",) def test_concat(): - node = StringConcat() + node = DataStringConcat() assert node.concat("hello ", "world") == ("hello world",) assert node.concat("", "") == ("",) # Empty strings assert node.concat("123", "456") == ("123456",) # Numbers as strings From 3614ba28eab5924454ac51dcd2a6aec25ac7d00b Mon Sep 17 00:00:00 2001 From: StableLlama Date: Sat, 10 May 2025 00:01:49 +0200 Subject: [PATCH 2/5] Fix types for **kwargs --- src/basic_data_handling/data_list_nodes.py | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/basic_data_handling/data_list_nodes.py b/src/basic_data_handling/data_list_nodes.py index 8efe914..b65f1ad 100644 --- a/src/basic_data_handling/data_list_nodes.py +++ b/src/basic_data_handling/data_list_nodes.py @@ -30,7 +30,7 @@ class DataListAppend: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def append(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def append(self, **kwargs: list[Any]) -> tuple[list[Any]]: result = kwargs.get('list', []).copy() item = kwargs.get('item', []) if len(item) > 0: @@ -66,7 +66,7 @@ class DataListExtend: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def extend(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def extend(self, **kwargs: list[Any]) -> tuple[list[Any]]: return (kwargs.get('list_a', []) + kwargs.get('list_b', []),) @@ -99,7 +99,7 @@ class DataListInsert: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def insert(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def insert(self, **kwargs: list[Any]) -> tuple[list[Any]]: result = kwargs.get('list', []).copy() result.insert(kwargs.get('index', [0])[0], kwargs.get('item', [None])[0]) return (result,) @@ -133,7 +133,7 @@ class DataListRemove: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def remove(self, **kwargs: dict[str, list]) -> tuple[list[Any], bool]: + def remove(self, **kwargs: list[Any]) -> tuple[list[Any], bool]: result = kwargs.get('list', []).copy() value = kwargs.get('value', []) try: @@ -172,12 +172,12 @@ class DataListPop: OUTPUT_IS_LIST = (True, False) @classmethod - def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str: - if input_types[0].get("index", "INT") not in ("INT"): + def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: + if input_types[0].get("index", "INT") is not "INT": return "index must be an INT type" return True - def pop(self, **kwargs: dict[str, list]) -> tuple[list[Any], Any]: + def pop(self, **kwargs: list[Any]) -> tuple[list[Any], Any]: result = kwargs.get('list', []).copy() index = kwargs.get('index', [-1])[0] try: @@ -213,7 +213,7 @@ class DataListClear: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def clear(self, **kwargs: dict[str, list]) -> tuple[[]]: + def clear(self, **kwargs: list[Any]) -> tuple[list]: # Return a new empty list rather than modifying the input return ([],) @@ -250,7 +250,7 @@ class DataListIndex: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def list_index(self, **kwargs: dict[str, list]) -> tuple[int]: + def list_index(self, **kwargs: list[Any]) -> tuple[int]: input_list = kwargs.get('list', []) value = kwargs.get('value', [None])[0] start = kwargs.get('start', [0])[0] @@ -291,7 +291,7 @@ class DataListCount: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def count(self, **kwargs: dict[str, list]) -> tuple[int]: + def count(self, **kwargs: list[Any]) -> tuple[int]: value = kwargs.get('value', [None])[0] return (kwargs.get('list', []).count(value),) @@ -326,7 +326,7 @@ class DataListSort: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def sort(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def sort(self, **kwargs: list[Any]) -> tuple[list[Any]]: # Convert string to boolean reverse = kwargs.get('reverse', ["False"])[0] == "True" @@ -360,7 +360,7 @@ class DataListReverse: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def reverse(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def reverse(self, **kwargs: list[Any]) -> tuple[list[Any]]: result = kwargs.get('list', []).copy() result.reverse() return (result,) @@ -392,7 +392,7 @@ class DataListCopy: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def copy(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def copy(self, **kwargs: list[Any]) -> tuple[list[Any]]: return (kwargs.get('list', []).copy(),) @@ -421,7 +421,7 @@ class DataListLength: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def length(self, **kwargs: dict[str, list]) -> tuple[int]: + def length(self, **kwargs: list[Any]) -> tuple[int]: return (len(kwargs.get('list', [])),) @@ -457,7 +457,7 @@ class DataListSlice: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def slice(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def slice(self, **kwargs: list[Any]) -> tuple[list[Any]]: input_list = kwargs.get('list', []) start = kwargs.get('start', [0])[0] stop = kwargs.get('stop', [-1])[0] @@ -497,7 +497,7 @@ class DataListGetItem: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def get_item(self, **kwargs: dict[str, list]) -> tuple[Any]: + def get_item(self, **kwargs: list[Any]) -> tuple[Any]: index = kwargs.get('index', [0])[0] try: return (kwargs.get('list', [])[index],) @@ -534,7 +534,7 @@ class DataListSetItem: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def set_item(self, **kwargs: dict[str, list]) -> tuple[Any]: + def set_item(self, **kwargs: list[Any]) -> tuple[Any]: input_list = kwargs.get('list', []) index = kwargs.get('index', [0])[0] value = kwargs.get('value', [None])[0] @@ -573,7 +573,7 @@ class DataListContains: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def contains(self, **kwargs: dict[str, list]) -> tuple[bool]: + def contains(self, **kwargs: list[Any]) -> tuple[bool]: value = kwargs.get('value', []) if len(value) == 0: return (False,) @@ -597,7 +597,7 @@ class DataListCreateEmpty: FUNCTION = "create_empty" OUTPUT_IS_LIST = (True,) - def create_empty(self) -> tuple[[]]: + def create_empty(self) -> tuple[list]: return ([],) @@ -634,7 +634,7 @@ class DataListZip: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def zip_lists(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def zip_lists(self, **kwargs: list[Any]) -> tuple[list[Any]]: lists = [kwargs.get('list1', []), kwargs.get('list2', [])] if 'list3' in kwargs: @@ -677,12 +677,12 @@ class DataListFilter: OUTPUT_IS_LIST = (True,) @classmethod - def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str: - if input_types[0]["filter"] not in ("BOOLEAN"): + def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: + if input_types[0]["filter"] is not "BOOLEAN": return "filter must be a BOOLEAN type" return True - def filter_data(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def filter_data(self, **kwargs: list[Any]) -> tuple[list[Any]]: values = kwargs.get('value', []) filters = kwargs.get('filter', []) @@ -716,12 +716,12 @@ class DataListMin: INPUT_IS_LIST = True @classmethod - def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str: + def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: if input_types[0]["list"] not in ("FLOAT", "INT"): return "list must contain FLOAT or INT types" return True - def find_min(self, **kwargs: dict[str, list]) -> tuple[Any]: + def find_min(self, **kwargs: list[Any]) -> tuple[Any]: values = kwargs.get('list', []) if not values: return (None,) @@ -758,12 +758,12 @@ class DataListMax: INPUT_IS_LIST = True @classmethod - def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str: + def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: if input_types[0]["list"] not in ("FLOAT", "INT"): return "list must contain FLOAT or INT types" return True - def find_max(self, **kwargs: dict[str, list]) -> tuple[Any]: + def find_max(self, **kwargs: list[Any]) -> tuple[Any]: values = kwargs.get('list', []) if not values: return (None,) From b344618f99abee87195ef814abb0a59420b38733 Mon Sep 17 00:00:00 2001 From: StableLlama Date: Sat, 10 May 2025 00:21:04 +0200 Subject: [PATCH 3/5] Some code cleanup --- src/basic_data_handling/casting_nodes.py | 4 +- src/basic_data_handling/control_flow_nodes.py | 2 +- src/basic_data_handling/int_nodes.py | 2 +- src/basic_data_handling/regex_nodes.py | 1 - src/basic_data_handling/string_nodes.py | 228 ------------------ tests/test_boolean_nodes.py | 2 +- tests/test_comparison_nodes.py | 2 +- tests/test_control_flow_nodes.py | 2 +- tests/test_string_nodes.py | 2 +- 9 files changed, 8 insertions(+), 237 deletions(-) diff --git a/src/basic_data_handling/casting_nodes.py b/src/basic_data_handling/casting_nodes.py index ce6924b..01e3a31 100644 --- a/src/basic_data_handling/casting_nodes.py +++ b/src/basic_data_handling/casting_nodes.py @@ -161,7 +161,7 @@ class CastDataListToList: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def convert(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def convert(self, **kwargs: list[Any]) -> tuple[list[Any]]: return (kwargs.get('list', []).copy(),) @@ -218,7 +218,7 @@ class CastDataListToSet: def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool: return True - def convert(self, **kwargs: dict[str, list]) -> tuple[list[Any]]: + def convert(self, **kwargs: list[Any]) -> tuple[set[Any]]: return (set(kwargs.get('list', [])),) diff --git a/src/basic_data_handling/control_flow_nodes.py b/src/basic_data_handling/control_flow_nodes.py index 419b283..11cb064 100644 --- a/src/basic_data_handling/control_flow_nodes.py +++ b/src/basic_data_handling/control_flow_nodes.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Union +from typing import Any from inspect import cleandoc class IfElse: diff --git a/src/basic_data_handling/int_nodes.py b/src/basic_data_handling/int_nodes.py index 38a02ab..dabf783 100644 --- a/src/basic_data_handling/int_nodes.py +++ b/src/basic_data_handling/int_nodes.py @@ -201,7 +201,7 @@ class IntToBytes: DESCRIPTION = cleandoc(__doc__ or "") FUNCTION = "to_bytes" - def to_bytes(self, int_value: int, length: int, byteorder: Literal["big", "little"], signed: Literal["True", "False"]) -> tuple[int]: + def to_bytes(self, int_value: int, length: int, byteorder: Literal["big", "little"], signed: Literal["True", "False"]) -> tuple[bytes]: signed_bool = (signed == "True") return (int_value.to_bytes(length, byteorder=byteorder, signed=signed_bool),) diff --git a/src/basic_data_handling/regex_nodes.py b/src/basic_data_handling/regex_nodes.py index e762e53..944e782 100644 --- a/src/basic_data_handling/regex_nodes.py +++ b/src/basic_data_handling/regex_nodes.py @@ -1,4 +1,3 @@ -from typing import Any from inspect import cleandoc import re diff --git a/src/basic_data_handling/string_nodes.py b/src/basic_data_handling/string_nodes.py index fe1e729..6f46780 100644 --- a/src/basic_data_handling/string_nodes.py +++ b/src/basic_data_handling/string_nodes.py @@ -696,29 +696,6 @@ class StringLjust: return (string.ljust(width, fillchar),) -class StringLower: - """ - Converts the string to lowercase. - - This node returns a copy of the string with all uppercase characters converted to lowercase. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "lower" - - def lower(self, string): - return (string.lower(),) - - class StringLstrip: """ Removes leading characters from the string. @@ -749,36 +726,6 @@ class StringLstrip: return (string.lstrip(chars),) -class StringReplace: - """ - Replaces occurrences of a substring with another substring. - - This node returns a copy of the string with all occurrences of substring - old replaced by new. If the optional argument count is given, only the - first count occurrences are replaced. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "old": ("STRING", {"default": ""}), - "new": ("STRING", {"default": ""}), - }, - "optional": { - "count": ("INT", {"default": -1, "min": -1}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "replace" - - def replace(self, string, old, new, count=-1): - return (string.replace(old, new, count),) - - class StringRemoveprefix: """ Removes prefix from the string if present. @@ -829,40 +776,6 @@ class StringRemovesuffix: return (string.removesuffix(suffix),) -class StringRfind: - """ - Finds the highest index of the substring in the string. - - This node searches for the last occurrence of the specified substring within the input string. - Returns the highest index where the substring is found. If the substring is not found, it returns -1. - Optional start and end parameters allow you to limit the search to a specific portion of the string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "substring": ("STRING", {"default": ""}), - }, - "optional": { - "start": ("INT", {"default": 0, "min": 0}), - "end": ("INT", {"default": 0, "min": 0}), - } - } - - RETURN_TYPES = ("INT",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rfind" - - def rfind(self, string, substring, start=0, end=0): - # If end is 0 or negative, search to the end of the string - if end <= 0: - end = len(string) - - return (string.rfind(substring, start, end),) - - class StringRjust: """ Right-aligns the string within a field of a given width. @@ -1011,36 +924,6 @@ class StringLower: return (string.lower(),) -class StringLstrip: - """ - Removes leading characters from the string. - - This node returns a copy of the string with leading characters removed. - If chars is provided, it specifies the set of characters to be removed. - If chars is not provided, whitespace characters are removed. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "chars": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "lstrip" - - def lstrip(self, string, chars=None): - if chars == "": - chars = None - return (string.lstrip(chars),) - - class StringReplace: """ Replaces occurrences of a substring with another substring. @@ -1071,31 +954,6 @@ class StringReplace: return (string.replace(old, new, count),) -class StringRemoveprefix: - """ - Removes prefix from the string if present. - - This node returns a copy of the string with the specified prefix removed - if the string starts with that prefix, otherwise returns the original string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "prefix": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "removeprefix" - - def removeprefix(self, string, prefix): - return (string.removeprefix(prefix),) - - class StringRemovesuffix: """ Removes suffix from the string if present. @@ -1277,37 +1135,6 @@ class StringJoin: return (separator.join(strings),) -class StringLjust: - """ - Left-aligns the string within a field of a given width. - - This node returns a string left-aligned in a field of the specified width. - If fillchar is provided, it is used as the padding character instead of a space. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "width": ("INT", {"default": 10, "min": 0}), - }, - "optional": { - "fillchar": ("STRING", {"default": " "}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "ljust" - - def ljust(self, string, width, fillchar=" "): - # Ensure fillchar is only one character - if len(fillchar) > 0: - fillchar = fillchar[0] - return (string.ljust(width, fillchar),) - - class StringLower: """ Converts the string to lowercase. @@ -1331,36 +1158,6 @@ class StringLower: return (string.lower(),) -class StringLstrip: - """ - Removes leading characters from the string. - - This node returns a copy of the string with leading characters removed. - If chars is provided, it specifies the set of characters to be removed. - If chars is not provided, whitespace characters are removed. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "chars": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "lstrip" - - def lstrip(self, string, chars=None): - if chars == "": - chars = None - return (string.lstrip(chars),) - - class StringRemoveprefix: """ Removes prefix from the string if present. @@ -1386,31 +1183,6 @@ class StringRemoveprefix: return (string.removeprefix(prefix),) -class StringRemovesuffix: - """ - Removes suffix from the string if present. - - This node returns a copy of the string with the specified suffix removed - if the string ends with that suffix, otherwise returns the original string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "suffix": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "removesuffix" - - def removesuffix(self, string, suffix): - return (string.removesuffix(suffix),) - - class StringRfind: """ Finds the highest index of the substring in the string. diff --git a/tests/test_boolean_nodes.py b/tests/test_boolean_nodes.py index 14ac869..a20f8ea 100644 --- a/tests/test_boolean_nodes.py +++ b/tests/test_boolean_nodes.py @@ -1,4 +1,4 @@ -import pytest +#import pytest from src.basic_data_handling.boolean_nodes import ( BooleanAnd, diff --git a/tests/test_comparison_nodes.py b/tests/test_comparison_nodes.py index 310cb3e..9d44431 100644 --- a/tests/test_comparison_nodes.py +++ b/tests/test_comparison_nodes.py @@ -1,4 +1,4 @@ -import pytest +#import pytest from src.basic_data_handling.comparison_nodes import ( Equal, NotEqual, diff --git a/tests/test_control_flow_nodes.py b/tests/test_control_flow_nodes.py index 612790c..f3de291 100644 --- a/tests/test_control_flow_nodes.py +++ b/tests/test_control_flow_nodes.py @@ -1,4 +1,4 @@ -import pytest +#import pytest from src.basic_data_handling.control_flow_nodes import IfElse, SwitchCase diff --git a/tests/test_string_nodes.py b/tests/test_string_nodes.py index 4a096d4..46ff19a 100644 --- a/tests/test_string_nodes.py +++ b/tests/test_string_nodes.py @@ -1,4 +1,4 @@ -import pytest +#import pytest from src.basic_data_handling.string_nodes import ( StringCapitalize, From 7505a76004ca55812c5b2ac8f611c5d05b547cee Mon Sep 17 00:00:00 2001 From: StableLlama Date: Sat, 10 May 2025 00:30:55 +0200 Subject: [PATCH 4/5] Some code cleanup --- pyproject.toml | 2 +- src/basic_data_handling/string_nodes.py | 326 ------------------------ 2 files changed, 1 insertion(+), 327 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d5afc97..97fa73e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "basic_data_handling" -version = "0.0.8" +version = "0.0.9" description = """NOTE: Still in development! Expect breaking changes! Basic Python functions for manipulating data that every programmer is used to. Currently supported ComfyUI data types: BOOLEAN, FLOAT, INT, STRING and data lists. diff --git a/src/basic_data_handling/string_nodes.py b/src/basic_data_handling/string_nodes.py index 6f46780..f66132d 100644 --- a/src/basic_data_handling/string_nodes.py +++ b/src/basic_data_handling/string_nodes.py @@ -776,37 +776,6 @@ class StringRemovesuffix: return (string.removesuffix(suffix),) -class StringRjust: - """ - Right-aligns the string within a field of a given width. - - This node returns a string right-aligned in a field of the specified width. - If fillchar is provided, it is used as the padding character instead of a space. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "width": ("INT", {"default": 10, "min": 0}), - }, - "optional": { - "fillchar": ("STRING", {"default": " "}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rjust" - - def rjust(self, string, width, fillchar=" "): - # Ensure fillchar is only one character - if len(fillchar) > 0: - fillchar = fillchar[0] - return (string.rjust(width, fillchar),) - - class StringRsplit: """ Splits the string at the specified separator from the right. @@ -839,68 +808,6 @@ class StringRsplit: return (string.rsplit(sep, maxsplit),) -class StringRstrip: - """ - Removes trailing characters from the string. - - This node returns a copy of the string with trailing characters removed. - If chars is provided, it specifies the set of characters to be removed. - If chars is not provided, whitespace characters are removed. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "chars": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rstrip" - - def rstrip(self, string, chars=None): - if chars == "": - chars = None - return (string.rstrip(chars),) - - - -class StringLjust: - """ - Left-aligns the string within a field of a given width. - - This node returns a string left-aligned in a field of the specified width. - If fillchar is provided, it is used as the padding character instead of a space. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "width": ("INT", {"default": 10, "min": 0}), - }, - "optional": { - "fillchar": ("STRING", {"default": " "}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "ljust" - - def ljust(self, string, width, fillchar=" "): - # Ensure fillchar is only one character - if len(fillchar) > 0: - fillchar = fillchar[0] - return (string.ljust(width, fillchar),) - - class StringLower: """ Converts the string to lowercase. @@ -954,65 +861,6 @@ class StringReplace: return (string.replace(old, new, count),) -class StringRemovesuffix: - """ - Removes suffix from the string if present. - - This node returns a copy of the string with the specified suffix removed - if the string ends with that suffix, otherwise returns the original string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "suffix": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "removesuffix" - - def removesuffix(self, string, suffix): - return (string.removesuffix(suffix),) - - -class StringRfind: - """ - Finds the highest index of the substring in the string. - - This node searches for the last occurrence of the specified substring within the input string. - Returns the highest index where the substring is found. If the substring is not found, it returns -1. - Optional start and end parameters allow you to limit the search to a specific portion of the string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "substring": ("STRING", {"default": ""}), - }, - "optional": { - "start": ("INT", {"default": 0, "min": 0}), - "end": ("INT", {"default": 0, "min": 0}), - } - } - - RETURN_TYPES = ("INT",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rfind" - - def rfind(self, string, substring, start=0, end=0): - # If end is 0 or negative, search to the end of the string - if end <= 0: - end = len(string) - - return (string.rfind(substring, start, end),) - - class StringRjust: """ Right-aligns the string within a field of a given width. @@ -1044,69 +892,6 @@ class StringRjust: return (string.rjust(width, fillchar),) -class StringRsplit: - """ - Splits the string at the specified separator from the right. - - This node returns a list of strings by splitting the input string at the specified separator, - starting from the right. If maxsplit is provided, at most maxsplit splits are done. - If the separator is not specified or is None, any whitespace string is a separator. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "sep": ("STRING", {"default": ""}), - "maxsplit": ("INT", {"default": -1, "min": -1}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rsplit" - OUTPUT_IS_LIST = (True,) - - def rsplit(self, string, sep=None, maxsplit=-1): - if sep == "": - sep = None - return (string.rsplit(sep, maxsplit),) - - - -class StringRstrip: - """ - Removes trailing characters from the string. - - This node returns a copy of the string with trailing characters removed. - If chars is provided, it specifies the set of characters to be removed. - If chars is not provided, whitespace characters are removed. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "chars": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rstrip" - - def rstrip(self, string, chars=None): - if chars == "": - chars = None - return (string.rstrip(chars),) - - class StringJoin: """ Joins strings from a data list with a specified separator. @@ -1135,54 +920,6 @@ class StringJoin: return (separator.join(strings),) -class StringLower: - """ - Converts the string to lowercase. - - This node returns a copy of the string with all uppercase characters converted to lowercase. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "lower" - - def lower(self, string): - return (string.lower(),) - - -class StringRemoveprefix: - """ - Removes prefix from the string if present. - - This node returns a copy of the string with the specified prefix removed - if the string starts with that prefix, otherwise returns the original string. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "prefix": ("STRING", {"default": ""}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "removeprefix" - - def removeprefix(self, string, prefix): - return (string.removeprefix(prefix),) - - class StringRfind: """ Finds the highest index of the substring in the string. @@ -1217,69 +954,6 @@ class StringRfind: return (string.rfind(substring, start, end),) -class StringRjust: - """ - Right-aligns the string within a field of a given width. - - This node returns a string right-aligned in a field of the specified width. - If fillchar is provided, it is used as the padding character instead of a space. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - "width": ("INT", {"default": 10, "min": 0}), - }, - "optional": { - "fillchar": ("STRING", {"default": " "}), - } - } - - RETURN_TYPES = ("STRING",) - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rjust" - - def rjust(self, string, width, fillchar=" "): - # Ensure fillchar is only one character - if len(fillchar) > 0: - fillchar = fillchar[0] - return (string.rjust(width, fillchar),) - - -class StringRsplit: - """ - Splits the string at the specified separator from the right. - - This node returns a list of strings by splitting the input string at the specified separator, - starting from the right. If maxsplit is provided, at most maxsplit splits are done. - If the separator is not specified or is None, any whitespace string is a separator. - """ - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "string": ("STRING", {"default": "", "defaultInput": True}), - }, - "optional": { - "sep": ("STRING", {"default": ""}), - "maxsplit": ("INT", {"default": -1, "min": -1}), - } - } - - RETURN_TYPES = ("STRING",) # Changed from "LIST" to "STRING" - CATEGORY = "Basic/STRING" - DESCRIPTION = cleandoc(__doc__ or "") - FUNCTION = "rsplit" - OUTPUT_IS_LIST = (True,) # This indicates that the output is a data list - - def rsplit(self, string, sep=None, maxsplit=-1): - if sep == "": - sep = None - return (string.rsplit(sep, maxsplit),) - - class StringRstrip: """ Removes trailing characters from the string. From 867ead6571515a3b3cbd74d29ea8ba354002fa9a Mon Sep 17 00:00:00 2001 From: StableLlama Date: Sat, 10 May 2025 00:34:33 +0200 Subject: [PATCH 5/5] Some code cleanup --- src/basic_data_handling/data_list_nodes.py | 4 ++-- src/basic_data_handling/dict_nodes.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/basic_data_handling/data_list_nodes.py b/src/basic_data_handling/data_list_nodes.py index b65f1ad..9c406e7 100644 --- a/src/basic_data_handling/data_list_nodes.py +++ b/src/basic_data_handling/data_list_nodes.py @@ -173,7 +173,7 @@ class DataListPop: @classmethod def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: - if input_types[0].get("index", "INT") is not "INT": + if input_types[0].get("index", "INT") != "INT": return "index must be an INT type" return True @@ -678,7 +678,7 @@ class DataListFilter: @classmethod def VALIDATE_INPUTS(cls, input_types: list[dict[str, str]]) -> bool|str: - if input_types[0]["filter"] is not "BOOLEAN": + if input_types[0]["filter"] != "BOOLEAN": return "filter must be a BOOLEAN type" return True diff --git a/src/basic_data_handling/dict_nodes.py b/src/basic_data_handling/dict_nodes.py index a41b3a1..8ddf05e 100644 --- a/src/basic_data_handling/dict_nodes.py +++ b/src/basic_data_handling/dict_nodes.py @@ -353,7 +353,7 @@ class DictPopItem: return result, key, value, True else: return result, "", None, False - except Exception as e: + except: return result, "", None, False