diff --git a/src/backend/base/langflow/components/processing/parser.py b/src/backend/base/langflow/components/processing/parser.py index 62a9ebb52..567ebc7df 100644 --- a/src/backend/base/langflow/components/processing/parser.py +++ b/src/backend/base/langflow/components/processing/parser.py @@ -1,3 +1,4 @@ +import json from typing import Any from langflow.custom import Component @@ -7,6 +8,7 @@ from langflow.io import ( MessageTextInput, MultilineInput, Output, + TabInput, ) from langflow.schema import Data, DataFrame from langflow.schema.message import Message @@ -19,18 +21,18 @@ class ParserComponent(Component): "Enable 'Stringify' to convert input into a readable string instead." ) icon = "braces" - beta = True inputs = [ - BoolInput( - name="stringify", - display_name="Stringify", - info="Enable to convert input to a string instead of using a template.", - value=False, + TabInput( + name="mode", + display_name="Mode", + options=["Parser", "Stringify"], + value="Parser", + info="Convert into raw string instead of using a template.", real_time_refresh=True, ), MultilineInput( - name="template", + name="pattern", display_name="Template", info=( "Use variables within curly brackets to extract column values for DataFrames " @@ -69,9 +71,9 @@ class ParserComponent(Component): def update_build_config(self, build_config, field_value, field_name=None): """Dynamically hide/show `template` and enforce requirement based on `stringify`.""" - if field_name == "stringify": - build_config["template"]["show"] = not field_value - build_config["template"]["required"] = not field_value + if field_name == "mode": + build_config["pattern"]["show"] = self.mode == "Parser" + build_config["pattern"]["required"] = self.mode == "Parser" if field_value: clean_data = BoolInput( name="clean_data", @@ -118,7 +120,7 @@ class ParserComponent(Component): def parse_combined_text(self) -> Message: """Parse all rows/items into a single text or convert input to string if `stringify` is enabled.""" # Early return for stringify option - if self.stringify: + if self.mode == "Stringify": return self.convert_to_string() df, data = self._clean_args() @@ -126,10 +128,10 @@ class ParserComponent(Component): lines = [] if df is not None: for _, row in df.iterrows(): - formatted_text = self.template.format(**row.to_dict()) + formatted_text = self.pattern.format(**row.to_dict()) lines.append(formatted_text) elif data is not None: - formatted_text = self.template.format(text=data.get_text()) + formatted_text = self.pattern.format(**data.data) lines.append(formatted_text) combined_text = self.sep.join(lines) @@ -144,10 +146,7 @@ class ParserComponent(Component): if isinstance(data, Message): return data.get_text() if isinstance(data, Data): - if data.get_text() is None: - msg = "Empty Data object" - raise ValueError(msg) - return data.get_text() + return json.dumps(data.data) if isinstance(data, DataFrame): if hasattr(self, "clean_data") and self.clean_data: # Remove empty rows @@ -170,4 +169,7 @@ class ParserComponent(Component): else: result = self._safe_convert(self.input_data) self.log(f"Converted to string with length: {len(result)}") - return Message(text=result) + + message = Message(text=result) + self.status = message + return message diff --git a/src/backend/tests/unit/components/processing/test_parser_component.py b/src/backend/tests/unit/components/processing/test_parser_component.py index e663edb77..3ed456f6a 100644 --- a/src/backend/tests/unit/components/processing/test_parser_component.py +++ b/src/backend/tests/unit/components/processing/test_parser_component.py @@ -17,7 +17,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): """Return the default kwargs for the component.""" return { "input_data": DataFrame({"Name": ["John"], "Age": [30], "Country": ["USA"]}), - "template": "Name: {Name}, Age: {Age}, Country: {Country}", + "pattern": "Name: {Name}, Age: {Age}, Country: {Country}", "sep": "\n", "stringify": False, "clean_data": False, @@ -44,7 +44,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): data = Data(text="Hello World") kwargs = { "input_data": data, - "template": "text: {text}", + "pattern": "text: {text}", "sep": "\n", "stringify": False, } @@ -62,7 +62,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): data_frame = DataFrame({"Name": ["John", "Jane"], "Age": [30, 25]}) kwargs = { "input_data": data_frame, - "stringify": True, + "mode": "Stringify", "clean_data": False, } component = component_class(**kwargs) @@ -101,7 +101,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): message = Message(text="Test message content") kwargs = { "input_data": message, - "stringify": True, + "mode": "Stringify", } component = component_class(**kwargs) @@ -119,7 +119,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): ) kwargs = { "input_data": data_frame, - "stringify": True, + "mode": "Stringify", "clean_data": True, } component = component_class(**kwargs) @@ -150,7 +150,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): # Arrange kwargs = { "input_data": 123, # Invalid input type - "template": "{value}", + "pattern": "{value}", "sep": "\n", } component = component_class(**kwargs) @@ -163,7 +163,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): # Arrange kwargs = { "input_data": None, - "template": "{value}", + "pattern": "{value}", "sep": "\n", } component = component_class(**kwargs) @@ -177,7 +177,7 @@ class TestParserComponent(ComponentTestBaseWithoutClient): data_frame = DataFrame({"Name": ["John"]}) kwargs = { "input_data": data_frame, - "template": "{InvalidColumn}", # Invalid column name + "pattern": "{InvalidColumn}", # Invalid column name "sep": "\n", "stringify": False, } @@ -197,9 +197,9 @@ class TestParserComponent(ComponentTestBaseWithoutClient): ) kwargs = { "input_data": data_frame, - "template": "{Name} is {Age} years old", + "pattern": "{Name} is {Age} years old", "sep": " | ", - "stringify": False, + "mode": "Parser", } component = component_class(**kwargs)