Files
StableLlama 26878b18f1 Added:
- Data List and LIST: new "filter empty" node that removes every empty entry
  (`None`, empty STRING, empty LIST/DICT/SET, ...); `0` and `False` are kept.
  An optional boolean switch also treats a STRING consisting only of whitespace
  as empty.
2026-10-16 17:22:16 +02:00

475 lines
17 KiB
Python

import pytest
from src.basic_data_handling.data_list_nodes import (
DataListAll,
DataListAny,
DataListAppend,
DataListContains,
DataListCount,
DataListCreate,
DataListCreateFromBoolean,
DataListCreateFromFloat,
DataListCreateFromInt,
DataListCreateFromString,
DataListEnumerate,
DataListExtend,
DataListFilter,
DataListFilterEmpty,
DataListFilterSelect,
DataListFirst,
DataListGetItem,
DataListIndex,
DataListInsert,
DataListLast,
DataListLength,
DataListListCreate,
DataListMax,
DataListMin,
DataListPop,
DataListPopRandom,
DataListRange,
DataListRemove,
DataListReverse,
DataListSetItem,
DataListShuffle,
DataListSlice,
DataListSort,
DataListSum,
DataListToList,
DataListToSet,
DataListZip,
)
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_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_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_shuffle():
node = DataListShuffle()
# Test determinism: Same seed should produce the same shuffle
original_list = [1, 2, 3, 4, 5]
result1 = node.shuffle_list(list=original_list, seed=[42])
result2 = node.shuffle_list(list=original_list, seed=[42])
assert result1 == result2 # Same seed, same output
# Verify the output is a permutation of the input
assert sorted(result1[0]) == sorted(original_list)
assert len(result1[0]) == len(original_list)
# Test different seeds produce different shuffles (not guaranteed, but likely for this list)
result3 = node.shuffle_list(list=original_list, seed=[123])
assert result1 != result3 # Different seed, likely different output
# Test empty list
assert node.shuffle_list(list=[], seed=[0]) == ([],)
# Test single-item list
assert node.shuffle_list(list=[42], seed=[99]) == ([42],)
# Test mixed data types
mixed_list = ["apple", 3.14, True, 42]
result4 = node.shuffle_list(list=mixed_list, seed=[7])
assert sorted(result4[0], key=str) == sorted(mixed_list, key=str) # Sort for comparison since types may not be directly comparable
assert len(result4[0]) == len(mixed_list)
# Test that the original list is not modified (node should return a copy)
original_copy = original_list.copy()
node.shuffle_list(list=original_list, seed=[1])
assert original_list == original_copy # Original should remain unchanged
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_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
assert node.zip_lists(list1=[1, 2, 3], list2=["a", "b"]) == ([[1, "a"], [2, "b"]],) # Different lengths
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]) == ([],)
assert node.filter_data(value=[1, 2, 3], filter=[False, False, False]) == ([1, 2, 3],)
def test_filter_empty():
node = DataListFilterEmpty()
assert node.filter_empty(list=[1, 2, 3]) == ([1, 2, 3],)
assert node.filter_empty(list=[None, 1, "", 2, [], 3, {}, set()]) == ([1, 2, 3],)
assert node.filter_empty(list=[0, False, 0.0, "", None]) == ([0, False, 0.0],) # 0 and False are not empty
assert node.filter_empty(list=["", " ", "\t", "a"]) == ([" ", "\t", "a"],) # whitespace is kept by default
assert node.filter_empty(list=["", " ", "\t", "a"], treat_whitespace_as_empty=[True]) == (["a"],)
assert node.filter_empty(list=[], treat_whitespace_as_empty=[True]) == ([],)
# Entries without a length (e.g. TENSORs) are never regarded as empty
opaque = object()
assert node.filter_empty(list=[opaque, None, ""]) == ([opaque],)
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,)
def test_filter_select():
node = DataListFilterSelect()
true_list, false_list = node.select(value=[1, 2, 3], select=[True, False, True])
assert true_list == [1, 3]
assert false_list == [2]
# All true case
true_list, false_list = node.select(value=["a", "b"], select=[True, True])
assert true_list == ["a", "b"]
assert false_list == []
# All false case
true_list, false_list = node.select(value=[1, 2, 3], select=[False, False, False])
assert true_list == []
assert false_list == [1, 2, 3]
def test_create():
node = DataListCreate()
# Testing with one item
assert node.create_list(item_0="test", item_1="") == (["test"],)
# Testing with multiple items of different types
assert node.create_list(item_0=1, item_1="two", item_2=3.0, item_3="") == ([1, "two", 3.0],)
# Testing with empty list (no items)
assert node.create_list(item_0="") == ([],)
def test_create_from_boolean():
node = DataListCreateFromBoolean()
# Testing with boolean values
assert node.create_list(item_0=True, item_1=False, item_2=False) == ([True, False],)
# Testing with boolean-convertible values
assert node.create_list(item_0=1, item_1=0, item_2="") == ([True, False],)
# Testing with empty list
assert node.create_list(item_0=0) == ([],)
def test_create_from_float():
node = DataListCreateFromFloat()
# Testing with float values
assert node.create_list(item_0=1.5, item_1=2.5, item_2=2) == ([1.5, 2.5],)
# Testing with float-convertible values
assert node.create_list(item_0=1, item_1="2.5", item_2="") == ([1.0, 2.5],)
# Testing with empty list
assert node.create_list(item_0="") == ([],)
def test_create_from_int():
node = DataListCreateFromInt()
# Testing with integer values
assert node.create_list(item_0=1, item_1=2, item_2="") == ([1, 2],)
# Testing with int-convertible values
assert node.create_list(item_0="1", item_1=2.0, item_2="") == ([1, 2],)
# Testing with empty list
assert node.create_list(item_0="") == ([],)
def test_create_from_string():
node = DataListCreateFromString()
# Testing with string values
assert node.create_list(item_0="hello", item_1="world", item_2="") == (["hello", "world"],)
# Testing with string-convertible values
assert node.create_list(item_0=123, item_1=True, item_2="") == (["123", "True"],)
# Testing with empty list
assert node.create_list(item_0="") == ([],)
def test_list_create():
node = DataListListCreate()
# Testing with string values
assert node.create_list(item_0=["hello", "world"], item_1=["bye", "bye!"], item_2="") == ([["hello", "world"], ["bye", "bye!"]],)
# Testing with mixed values
assert node.create_list(item_0=[123, 456], item_1=[True, False], item_2="") == ([[123, 456], [True, False]],)
# Testing with empty list
assert node.create_list(item_0="") == ([],)
def test_pop_random():
node = DataListPopRandom()
result_list, item = node.pop_random_element(list=[1])
assert result_list == [] and item == 1 # Only one item, so it must be chosen
# With multiple items, we can't predict which one will be popped
# But we can check that an item was removed and returned
result_list, item = node.pop_random_element(list=[1, 2, 3])
assert len(result_list) == 2 and item in [1, 2, 3]
# Empty list case
assert node.pop_random_element(list=[]) == ([], None)
# Same seed should produce the same popped item
original_list = [1, 2, 3, 4]
result1, item1 = node.pop_random_element(list=original_list, seed=[42])
result2, item2 = node.pop_random_element(list=original_list, seed=[42])
assert item1 == item2
assert result1 == result2
def test_first():
node = DataListFirst()
assert node.get_first_element(list=[1, 2, 3]) == (1,)
assert node.get_first_element(list=["a", "b", "c"]) == ("a",)
assert node.get_first_element(list=[]) == (None,) # Empty list
def test_last():
node = DataListLast()
assert node.get_last_element(list=[1, 2, 3]) == (3,)
assert node.get_last_element(list=["a", "b", "c"]) == ("c",)
assert node.get_last_element(list=[]) == (None,) # Empty list
def test_to_list():
node = DataListToList()
# Test with regular list
assert node.convert(list=[1, 2, 3]) == ([1, 2, 3],)
# Test with empty list
assert node.convert(list=[]) == ([],)
# Test with mixed types
assert node.convert(list=[1, "two", 3.0]) == ([1, "two", 3.0],)
def test_to_set():
node = DataListToSet()
# Test with regular list
assert node.convert(list=[1, 2, 3]) == ({1, 2, 3},)
# Test with empty list
assert node.convert(list=[]) == (set(),)
# Test with duplicates
assert node.convert(list=[1, 2, 1, 3, 2]) == ({1, 2, 3},)
# Test with mixed types (that can be in a set)
assert node.convert(list=[1, "two", 3.0]) == ({1, "two", 3.0},)
def test_all():
node = DataListAll()
# All true values
assert node.check_all(list=[True, True, 1, "text"]) == (True,)
# Contains false value
assert node.check_all(list=[True, False, True]) == (False,)
# Empty list (returns True)
assert node.check_all(list=[]) == (True,)
def test_any():
node = DataListAny()
# Contains true value
assert node.check_any(list=[False, True, False]) == (True,)
# All false values
assert node.check_any(list=[False, 0, "", None]) == (False,)
# Empty list (returns False)
assert node.check_any(list=[]) == (False,)
def test_enumerate():
node = DataListEnumerate()
# Basic enumeration starting from 0
assert node.enumerate_list(list=["a", "b", "c"]) == ([[0, "a"], [1, "b"], [2, "c"]],)
# Custom start index
assert node.enumerate_list(list=["x", "y", "z"], start=[10]) == ([[10, "x"], [11, "y"], [12, "z"]],)
# Empty list
assert node.enumerate_list(list=[]) == ([],)
def test_sum():
node = DataListSum()
# Integer sum
int_sum, float_sum = node.sum_list(list=[1, 2, 3])
assert int_sum == 6
assert float_sum == 6.0
# Mixed number types
int_sum, float_sum = node.sum_list(list=[1, 2.5, 3])
assert int_sum == 6 # Integer part of the sum
assert float_sum == 6.5 # Full float sum
# With start value
int_sum, float_sum = node.sum_list(list=[1, 2, 3], start=[10])
assert int_sum == 16
assert float_sum == 16.0
# Empty list with start value
int_sum, float_sum = node.sum_list(list=[], start=[5])
assert int_sum == 5
assert float_sum == 5.0
def test_range():
node = DataListRange()
# Test with default start (0) and step (1)
assert node.create_range(stop=5) == ([0, 1, 2, 3, 4],)
# Test with custom start and stop
assert node.create_range(start=2, stop=6) == ([2, 3, 4, 5],)
# Test with custom step
assert node.create_range(start=0, stop=10, step=2) == ([0, 2, 4, 6, 8],)
# Test with negative numbers
assert node.create_range(start=-3, stop=3) == ([-3, -2, -1, 0, 1, 2],)
# Test backward counting
assert node.create_range(start=5, stop=0, step=-1) == ([5, 4, 3, 2, 1],)
# Test empty range
assert node.create_range(start=0, stop=0) == ([],)
# Test when start > stop with positive step (returns empty list)
assert node.create_range(start=10, stop=5) == ([],)
# Test with ValueError (step cannot be zero)
with pytest.raises(ValueError, match="Step cannot be zero"):
node.create_range(start=0, stop=5, step=0)
def test_data_list_none_source():
"""Graceful behaviour when the Data List source is None."""
assert DataListAll().check_all(list=None) == (True,)
assert DataListAny().check_any(list=None) == (False,)
assert DataListAppend().append(list=None, item=[1]) == ([1],)
assert DataListContains().contains(list=None, value=[1]) == (False,)
assert DataListCount().count(list=None, value=[1]) == (0,)
assert DataListEnumerate().enumerate_list(list=None) == ([],)
assert DataListExtend().extend(list_a=None, list_b=None) == ([],)
assert DataListFilter().filter_data(value=None, filter=None) == ([],)
assert DataListFilterEmpty().filter_empty(list=None) == ([],)
assert DataListFilterSelect().select(value=None, select=None) == ([], [])
assert DataListFirst().get_first_element(list=None) == (None,)
assert DataListGetItem().get_item(list=None, index=[0]) == (None,)
assert DataListIndex().list_index(list=None, value=[1]) == (-1,)
assert DataListInsert().insert(list=None, index=[0], item=[1]) == ([1],)
assert DataListLast().get_last_element(list=None) == (None,)
assert DataListLength().length(list=None) == (0,)
assert DataListMax().find_max(list=None) == (None,)
assert DataListMin().find_min(list=None) == (None,)
assert DataListPop().pop(list=None) == ([], None)
assert DataListPopRandom().pop_random_element(list=None) == ([], None)
assert DataListRemove().remove(list=None, value=[1]) == ([], False)
assert DataListReverse().reverse(list=None) == ([],)
assert DataListShuffle().shuffle_list(list=None, seed=[0]) == ([],)
assert DataListSlice().slice(list=None) == ([],)
assert DataListSort().sort(list=None) == ([],)
assert DataListSum().sum_list(list=None) == (0, 0.0)
assert DataListZip().zip_lists(list1=None, list2=None) == ([],)
assert DataListToList().convert(list=None) == ([],)
assert DataListToSet().convert(list=None) == (set(),)