Skip to content

Commit 152b3d8

Browse files
Cristhianzldiogocabral
authored andcommitted
fix: Union type on components (langflow-ai#4137)
* 🐛 (type_extraction.py): fix condition to correctly handle UnionType objects in type extraction process * ✨ (test_schema.py): add support for additional data types and nested structures in post_process_type function to improve type handling and flexibility * ✅ (test_schema.py): add additional test cases for post_process_type function to cover various Union types and combinations for better test coverage and accuracy
1 parent 4529500 commit 152b3d8

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

Diff for: src/backend/base/langflow/type_extraction/type_extraction.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ def post_process_type(_type):
5555

5656
# If the return type is not a Union, then we just return it as a list
5757
inner_type = _type[0] if isinstance(_type, list) else _type
58-
if not hasattr(inner_type, "__origin__") or inner_type.__origin__ != Union:
58+
if (not hasattr(inner_type, "__origin__") or inner_type.__origin__ != Union) and (
59+
not hasattr(inner_type, "__class__") or inner_type.__class__.__name__ != "UnionType"
60+
):
5961
return _type if isinstance(_type, list) else [_type]
6062
# If the return type is a Union, then we need to parse it
6163
_type = extract_union_types_from_generic_alias(_type)

Diff for: src/backend/tests/unit/test_schema.py

+56-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
from collections.abc import Sequence
1+
from types import NoneType
22
from typing import Union
33

4+
from langflow.schema.data import Data
45
import pytest
56
from pydantic import ValidationError
67

78
from langflow.template import Input, Output
89
from langflow.template.field.base import UNDEFINED
910
from langflow.type_extraction.type_extraction import post_process_type
11+
from collections.abc import Sequence as SequenceABC
1012

1113

1214
@pytest.fixture(name="client", autouse=True)
@@ -40,11 +42,62 @@ def test_validate_type_class(self):
4042
assert input_obj.field_type == "int"
4143

4244
def test_post_process_type_function(self):
45+
# Basic types
4346
assert set(post_process_type(int)) == {int}
47+
assert set(post_process_type(float)) == {float}
48+
49+
# List and Sequence types
4450
assert set(post_process_type(list[int])) == {int}
51+
assert set(post_process_type(SequenceABC[float])) == {float}
52+
53+
# Union types
4554
assert set(post_process_type(Union[int, str])) == {int, str}
46-
assert set(post_process_type(Union[int, Sequence[str]])) == {int, str}
47-
assert set(post_process_type(Union[int, Sequence[int]])) == {int}
55+
assert set(post_process_type(Union[int, SequenceABC[str]])) == {int, str}
56+
assert set(post_process_type(Union[int, SequenceABC[int]])) == {int}
57+
58+
# Nested Union with lists
59+
assert set(post_process_type(Union[list[int], list[str]])) == {int, str}
60+
assert set(post_process_type(Union[int, list[str], list[float]])) == {int, str, float}
61+
62+
# Custom data types
63+
assert set(post_process_type(Data)) == {Data}
64+
assert set(post_process_type(list[Data])) == {Data}
65+
66+
# Union with custom types
67+
assert set(post_process_type(Union[Data, str])) == {Data, str}
68+
assert set(post_process_type(Union[Data, int, list[str]])) == {Data, int, str}
69+
70+
# Empty lists and edge cases
71+
assert set(post_process_type(list)) == {list}
72+
assert set(post_process_type(Union[int, None])) == {int, NoneType}
73+
assert set(post_process_type(Union[None, list[None]])) == {None, NoneType}
74+
75+
# Handling complex nested structures
76+
assert set(post_process_type(Union[SequenceABC[Union[int, str]], list[float]])) == {int, str, float}
77+
assert set(post_process_type(Union[Union[Union[int, list[str]], list[float]], str])) == {int, str, float}
78+
79+
# Non-generic types should return as is
80+
assert set(post_process_type(dict)) == {dict}
81+
assert set(post_process_type(tuple)) == {tuple}
82+
83+
# Union with custom types
84+
assert set(post_process_type(Union[Data, str])) == {Data, str}
85+
assert set(post_process_type(Data | str)) == {Data, str}
86+
assert set(post_process_type(Data | int | list[str])) == {Data, int, str}
87+
88+
# More complex combinations with Data
89+
assert set(post_process_type(Data | list[float])) == {Data, float}
90+
assert set(post_process_type(Data | Union[int, str])) == {Data, int, str}
91+
assert set(post_process_type(Data | list[int] | None)) == {Data, int, type(None)}
92+
assert set(post_process_type(Data | Union[float, None])) == {Data, float, type(None)}
93+
94+
# Multiple Data types combined
95+
assert set(post_process_type(Union[Data, Union[str, float]])) == {Data, str, float}
96+
assert set(post_process_type(Union[Data | float | str, int])) == {Data, int, float, str}
97+
98+
# Testing with nested unions and lists
99+
assert set(post_process_type(Union[list[Data], list[Union[int, str]]])) == {Data, int, str}
100+
assert set(post_process_type(Data | list[Union[float, str]])) == {Data, float, str}
48101

49102
def test_input_to_dict(self):
50103
input_obj = Input(field_type="str")

0 commit comments

Comments
 (0)