feat: add convert component with dynamic output support (#7773)

* Create convertor.py

* [autofix.ci] apply automated fixes

* convert component

* [autofix.ci] apply automated fixes

* add Type_conversion base class with dispatchers for performance based conversion

* fix lint issues

* add type_convertor test

* [autofix.ci] apply automated fixes

* update tests

* fix tests

* update with auto conversion methods

* update function to component file

* feat: enhance input validation for Data, DataFrame, and Message types

* test: add unit tests for DataInput, MessageInput, and DataFrameInput data conversion

* updated changes to use type classes

* [autofix.ci] apply automated fixes

* add convert logic

* update converts

* Update converter.py

* [autofix.ci] apply automated fixes

* revert converter.py

* Update inputs.py

* Update test_inputs.py

* update to logic

* Update test_type_convertor_component.py

* update converter

* [autofix.ci] apply automated fixes

* refactor: rename conversion functions for clarity

Updated function names for converting inputs to Message, Data, and DataFrame types to improve readability and consistency. The changes include renaming `get_message_converter` to `convert_to_message`, `get_data_converter` to `convert_to_data`, and `get_dataframe_converter` to `convert_to_dataframe`. Additionally, added a check for dictionary input in the data conversion function.

* fix: add TYPE_CHECKING for conditional imports in message.py

Introduced TYPE_CHECKING to optimize imports for the DataFrame type, ensuring that the import only occurs during type checking. This change enhances performance and maintains compatibility with static type checkers.

* refactor: simplify data conversion methods in Message class

Removed unnecessary parameters from the `to_data` and `to_dataframe` methods in the Message class, enhancing clarity and reducing complexity. The methods now directly use instance attributes, improving code readability and maintainability.

* refactor: enhance DataFrame methods for clarity and type safety

Updated the `to_data` and `to_message` methods in the DataFrame class to improve clarity and type safety. The `to_data` method now directly converts the DataFrame to a Data object without parameters, and the `to_message` method uses the instance's data directly. Added TYPE_CHECKING for conditional imports to optimize performance and maintain compatibility with static type checkers.

* refactor: streamline Data class methods for improved clarity

Refactored the `to_message` and `to_dataframe` methods in the Data class to eliminate unnecessary parameters and directly utilize instance attributes. This change enhances code readability and maintainability while ensuring type safety with the appropriate imports for Message and DataFrame. Additionally, updated the logic to access instance data more intuitively.

* refactor: simplify conversion method calls by removing redundant arguments

* rename test file

* refactor: remove obsolete test file for data conversion

* refactor: add support for converting dictionary to DataFrame

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>
Co-authored-by: Yuqi Tang <yuqi.tang@datastax.com>
This commit is contained in:
Edwin Jose 2025-06-02 16:06:56 -04:00 • committed by GitHub
commit 360836800d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 293 additions and 6 deletions

View file

@ -0,0 +1,115 @@
import pandas as pd
import pytest
from langflow.components.processing.converter import TypeConverterComponent
from langflow.schema.data import Data
from langflow.schema.dataframe import DataFrame
from langflow.schema.message import Message
from tests.base import ComponentTestBaseWithoutClient
class TestTypeConverterComponent(ComponentTestBaseWithoutClient):
@pytest.fixture
def component_class(self):
"""Return the component class to test."""
return TypeConverterComponent
@pytest.fixture
def file_names_mapping(self):
"""Return an empty list since this component doesn't have version-specific files."""
return []
# Message to other types
def test_message_to_message(self, component_class):
"""Test converting Message to Message."""
component = component_class(input_data=Message(text="Hello World"), output_type="Message")
result = component.convert_to_message()
assert isinstance(result, Message)
assert result.text == "Hello World"
def test_message_to_data(self, component_class):
"""Test converting Message to Data."""
component = component_class(input_data=Message(text="Hello"), output_type="Data")
result = component.convert_to_data()
assert isinstance(result, Data)
assert "text" in result.data
assert result.data["text"] == "Hello"
def test_message_to_dataframe(self, component_class):
"""Test converting Message to DataFrame."""
component = component_class(input_data=Message(text="Hello"), output_type="DataFrame")
result = component.convert_to_dataframe()
assert isinstance(result, DataFrame)
assert "text" in result.columns
assert result.iloc[0]["text"] == "Hello"
# Data to other types
def test_data_to_message(self, component_class):
"""Test converting Data to Message."""
component = component_class(input_data=Data(data={"text": "Hello World"}), output_type="Message")
result = component.convert_to_message()
assert isinstance(result, Message)
assert result.text == "Hello World"
def test_data_to_data(self, component_class):
"""Test converting Data to Data."""
component = component_class(input_data=Data(data={"key": "value"}), output_type="Data")
result = component.convert_to_data()
assert isinstance(result, Data)
assert result.data == {"key": "value"}
def test_data_to_dataframe(self, component_class):
"""Test converting Data to DataFrame."""
component = component_class(input_data=Data(data={"text": "Hello World"}), output_type="DataFrame")
result = component.convert_to_dataframe()
assert isinstance(result, DataFrame)
assert "text" in result.columns
assert result.iloc[0]["text"] == "Hello World"
# DataFrame to other types
def test_dataframe_to_message(self, component_class):
"""Test converting DataFrame to Message."""
df_data = pd.DataFrame({"col1": ["Hello"], "col2": ["World"]})
component = component_class(input_data=DataFrame(data=df_data), output_type="Message")
result = component.convert_to_message()
assert isinstance(result, Message)
assert result.text == "| col1 | col2 |\n|:-------|:-------|\n| Hello | World |"
def test_dataframe_to_data(self, component_class):
"""Test converting DataFrame to Data."""
df_data = pd.DataFrame({"col1": ["Hello"]})
component = component_class(input_data=DataFrame(data=df_data), output_type="Data")
result = component.convert_to_data()
assert isinstance(result, Data)
assert isinstance(result.data, dict)
def test_dataframe_to_dataframe(self, component_class):
"""Test converting DataFrame to DataFrame."""
df_data = pd.DataFrame({"col1": ["Hello"], "col2": ["World"]})
component = component_class(input_data=DataFrame(data=df_data), output_type="DataFrame")
result = component.convert_to_dataframe()
assert isinstance(result, DataFrame)
assert "col1" in result.columns
assert "col2" in result.columns
assert result.iloc[0]["col1"] == "Hello"
assert result.iloc[0]["col2"] == "World"
def test_update_outputs(self, component_class):
"""Test the update_outputs method."""
component = component_class(input_data=Message(text="Hello"), output_type="Message")
frontend_node = {"outputs": []}
# Test with Message output
updated = component.update_outputs(frontend_node, "output_type", "Message")
assert len(updated["outputs"]) == 1
assert updated["outputs"][0]["name"] == "message_output"
# Test with Data output
updated = component.update_outputs(frontend_node, "output_type", "Data")
assert len(updated["outputs"]) == 1
assert updated["outputs"][0]["name"] == "data_output"
# Test with DataFrame output
updated = component.update_outputs(frontend_node, "output_type", "DataFrame")
assert len(updated["outputs"]) == 1
assert updated["outputs"][0]["name"] == "dataframe_output"