Skip to content

Commit 644a14e

Browse files
committed
fix: remove invalid dynamic parameter from Output definitions in memory component
1 parent aa1ecc6 commit 644a14e

2 files changed

Lines changed: 143 additions & 5 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
"""Unit tests for Component.extract_data method."""
2+
3+
import pandas as pd
4+
import pytest
5+
6+
from lfx.custom.custom_component.component import Component
7+
from lfx.schema.message import Message
8+
9+
10+
class TestExtractData:
11+
"""Test suite for Component.extract_data method."""
12+
13+
@pytest.fixture
14+
def component(self):
15+
"""Create a basic component instance for testing."""
16+
return Component()
17+
18+
def test_extract_data_with_dataframe(self, component):
19+
"""Test that extract_data returns DataFrame unchanged."""
20+
# Arrange
21+
df = pd.DataFrame({"col1": [1, 2, 3], "col2": ["a", "b", "c"]})
22+
23+
# Act
24+
result = component.extract_data(df)
25+
26+
# Assert
27+
assert isinstance(result, pd.DataFrame)
28+
assert result is df # Should return the same object
29+
pd.testing.assert_frame_equal(result, df)
30+
31+
def test_extract_data_with_series(self, component):
32+
"""Test that extract_data returns Series unchanged."""
33+
# Arrange
34+
series = pd.Series([1, 2, 3, 4, 5], name="test_series")
35+
36+
# Act
37+
result = component.extract_data(series)
38+
39+
# Assert
40+
assert isinstance(result, pd.Series)
41+
assert result is series # Should return the same object
42+
pd.testing.assert_series_equal(result, series)
43+
44+
def test_extract_data_with_message(self, component):
45+
"""Test that extract_data handles Message objects correctly."""
46+
# Arrange
47+
message = Message(text="Test message")
48+
49+
# Act
50+
result = component.extract_data(message)
51+
52+
# Assert
53+
assert result == "Test message"
54+
assert component.status == "Test message"
55+
56+
def test_extract_data_with_message_no_text(self, component):
57+
"""Test that extract_data handles Message with no text."""
58+
# Arrange
59+
message = Message(text=None)
60+
61+
# Act
62+
result = component.extract_data(message)
63+
64+
# Assert
65+
assert result == "No text available"
66+
67+
def test_extract_data_with_dict(self, component):
68+
"""Test that extract_data handles dict correctly."""
69+
# Arrange
70+
data = {"key1": "value1", "key2": "value2"}
71+
72+
# Act
73+
result = component.extract_data(data)
74+
75+
# Assert
76+
assert result == data
77+
78+
def test_extract_data_with_string(self, component):
79+
"""Test that extract_data handles string correctly."""
80+
# Arrange
81+
data = "test string"
82+
83+
# Act
84+
result = component.extract_data(data)
85+
86+
# Assert
87+
assert result == data
88+
89+
def test_extract_data_dataframe_not_processed_by_hasattr(self, component):
90+
"""Test that DataFrame bypasses hasattr checks.
91+
92+
This is a regression test to ensure DataFrames are not incorrectly
93+
processed by downstream hasattr checks for .data or .model_dump attributes.
94+
"""
95+
# Arrange
96+
df = pd.DataFrame({"col1": [1, 2], "col2": [3, 4]})
97+
98+
# Act
99+
result = component.extract_data(df)
100+
101+
# Assert
102+
# The result should be the DataFrame itself, not processed further
103+
assert isinstance(result, pd.DataFrame)
104+
assert result is df
105+
# Verify it wasn't converted to dict or other format
106+
assert not isinstance(result, dict)
107+
assert not isinstance(result, str)
108+
109+
def test_extract_data_series_not_processed_by_hasattr(self, component):
110+
"""Test that Series bypasses hasattr checks.
111+
112+
This is a regression test to ensure Series are not incorrectly
113+
processed by downstream hasattr checks for .data or .model_dump attributes.
114+
"""
115+
# Arrange
116+
series = pd.Series([10, 20, 30])
117+
118+
# Act
119+
result = component.extract_data(series)
120+
121+
# Assert
122+
# The result should be the Series itself, not processed further
123+
assert isinstance(result, pd.Series)
124+
assert result is series
125+
# Verify it wasn't converted to dict or other format
126+
assert not isinstance(result, dict)
127+
assert not isinstance(result, str)
128+
129+
# Made with Bob

src/lfx/src/lfx/components/models_and_agents/memory.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,20 @@ class MemoryComponent(Component):
115115
]
116116

117117
outputs = [
118-
Output(display_name="Message", name="messages_text", method="retrieve_messages_as_text", dynamic=True),
119-
Output(display_name="Table", name="dataframe", method="retrieve_messages_dataframe", dynamic=True),
118+
Output(
119+
display_name="Message",
120+
name="messages_text",
121+
method="retrieve_messages_as_text",
122+
types=["Message"],
123+
selected="Message",
124+
),
125+
Output(
126+
display_name="Table",
127+
name="dataframe",
128+
method="retrieve_messages_dataframe",
129+
types=["Table"],
130+
selected="Table",
131+
),
120132
]
121133

122134
def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
@@ -133,7 +145,6 @@ def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any)
133145
types=["Message"],
134146
selected="Message",
135147
hidden=True,
136-
dynamic=True,
137148
)
138149
]
139150
if field_value == "Retrieve":
@@ -144,15 +155,13 @@ def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any)
144155
method="retrieve_messages_as_text",
145156
types=["Message"],
146157
selected="Message",
147-
dynamic=True,
148158
),
149159
Output(
150160
display_name="Table",
151161
name="dataframe",
152162
method="retrieve_messages_dataframe",
153163
types=["Table"],
154164
selected="Table",
155-
dynamic=True,
156165
),
157166
]
158167
return frontend_node

0 commit comments

Comments
 (0)