Skip to content

Conversation

@edwinjosechittilappilly
Copy link
Collaborator

@edwinjosechittilappilly edwinjosechittilappilly commented Apr 24, 2025

This pull request introduces a new DataTypeConverterComponent in the src/backend/base/langflow/components/processing/convertor.py file. This component provides functionality to convert between three data types: Message, Data, and DataFrame. It includes input and output definitions, dynamic output adjustments, and methods for performing the conversions.

Key Changes:

New Component:

  • DataTypeConverterComponent class:
    • Added a new component to handle conversions between Message, Data, and DataFrame data types. It includes input definitions (HandleInput, TabInput), output definitions (Output), and a dynamic output adjustment method (update_outputs).

Conversion Methods:

  • to_message method:
    • Converts input data to the Message type, handling cases for Data, DataFrame, and fallback scenarios. Includes error handling for JSON serialization and markdown conversion.
  • to_data method:
    • Converts input data to the Data type, with support for parsing JSON from Message text and converting DataFrame to a dictionary. Includes error handling for invalid conversions.
  • to_dataframe method:
    • Converts input data to the DataFrame type, supporting JSON parsing from Message text and converting `Data

Summary by CodeRabbit

  • New Features
    • Introduced a Type Converter component that allows users to convert between Message, Data, and DataFrame types, with dynamic output selection.
  • Bug Fixes
    • Improved type conversion methods across Message, Data, and DataFrame types for smoother interoperability.
  • Tests
    • Added comprehensive tests to verify correct type conversions and output behavior for the new Type Converter component.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request introduces the DataTypeConverterComponent to enable conversions between Message, Data, and DataFrame types.

  • Added a new component with defined inputs and outputs
  • Implemented conversion methods (to_message, to_data, to_dataframe) with error handling
  • Integrated dynamic output adjustments based on the selected output type
Comments suppressed due to low confidence (1)

src/backend/base/langflow/components/processing/convertor.py:9

  • [nitpick] Consider renaming the file from 'convertor.py' to 'converter.py' for consistency with the class name and common spelling.
class DataTypeConverterComponent(Component):

@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 24, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 24, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 24, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 24, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 29, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Apr 29, 2025
@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Jun 2, 2025
@ogabrielluiz ogabrielluiz added the lgtm This PR has been approved by a maintainer label Jun 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/backend/base/langflow/schema/message.py (1)

282-283: Add missing docstring for the to_data method.

The method lacks documentation explaining its purpose and return value, as flagged by static analysis.

 def to_data(self) -> Data:
+    """Convert this Message to a Data object.
+    
+    Returns:
+        Data: A Data object containing this message's data.
+    """
     return Data(data=self.data)
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 282-282: Missing function or method docstring

(C0116)

src/backend/base/langflow/schema/dataframe.py (1)

192-206: Add docstring and fix line length violation.

The method needs documentation and has a line that exceeds the 100-character limit.

 def to_message(self) -> Message:
+    """Convert this DataFrame to a Message with markdown table format.
+    
+    Processes the DataFrame by cleaning empty rows, normalizing whitespace,
+    escaping pipe characters, and converting to markdown table format.
+    
+    Returns:
+        Message: A Message containing the DataFrame as markdown table.
+    """
     from langflow.schema.message import Message  # Local import to avoid circular import

     # Process DataFrame similar to the _safe_convert method
     # Remove empty rows
     processed_df = self.dropna(how="all")
     # Remove empty lines in each cell
     processed_df = processed_df.replace(r"^\s*$", "", regex=True)
     # Replace multiple newlines with a single newline
     processed_df = processed_df.replace(r"\n+", "\n", regex=True)
     # Replace pipe characters to avoid markdown table issues
     processed_df = processed_df.replace(r"\|", r"\\|", regex=True)
-    processed_df = processed_df.map(lambda x: str(x).replace("\n", "<br/>") if isinstance(x, str) else x)
+    processed_df = processed_df.map(
+        lambda x: str(x).replace("\n", "<br/>") if isinstance(x, str) else x
+    )
     # Convert to markdown and wrap in a Message
     return Message(text=processed_df.to_markdown(index=False))
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 204-204: Line too long (109/100)

(C0301)


[convention] 192-192: Missing function or method docstring

(C0116)


[warning] 193-193: Redefining name 'Message' from outer scope (line 8)

(W0621)


[warning] 193-193: Reimport 'Message' (imported line 8)

(W0404)


[convention] 193-193: Import outside toplevel (langflow.schema.message.Message)

(C0415)

src/backend/base/langflow/schema/data.py (2)

257-262: Add missing docstring for the to_message method.

The method lacks documentation explaining its purpose and behavior.

 def to_message(self) -> Message:
+    """Convert this Data to a Message.
+    
+    Uses the text from the configured text_key if available,
+    otherwise converts the entire data dictionary to string.
+    
+    Returns:
+        Message: A Message containing the text representation.
+    """
     from langflow.schema.message import Message  # Local import to avoid circular import

     if self.text_key in self.data:
         return Message(text=self.get_text())
     return Message(text=str(self.data))
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 257-257: Missing function or method docstring

(C0116)


[convention] 258-258: Import outside toplevel (langflow.schema.message.Message)

(C0415)


264-275: Add docstring and improve readability of complex conditional.

The method needs documentation and the long conditional affects readability.

 def to_dataframe(self) -> DataFrame:
+    """Convert this Data to a DataFrame.
+    
+    If the data contains exactly one key with a list of dictionaries as value,
+    that list is used as DataFrame data. Otherwise, wraps this Data object
+    in a single-row DataFrame.
+    
+    Returns:
+        DataFrame: A DataFrame representation of the data.
+    """
     from langflow.schema.dataframe import DataFrame  # Local import to avoid circular import

     data_dict = self.data
-    # If data contains only one key and the value is a list of dictionaries, convert to DataFrame
-    if (
-        len(data_dict) == 1
-        and isinstance(next(iter(data_dict.values())), list)
-        and all(isinstance(item, dict) for item in next(iter(data_dict.values())))
-    ):
-        return DataFrame(data=next(iter(data_dict.values())))
+    # If data contains only one key and the value is a list of dictionaries
+    if len(data_dict) == 1:
+        single_value = next(iter(data_dict.values()))
+        if (
+            isinstance(single_value, list)
+            and all(isinstance(item, dict) for item in single_value)
+        ):
+            return DataFrame(data=single_value)
     return DataFrame(data=[self])
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 268-268: Line too long (101/100)

(C0301)


[convention] 264-264: Missing function or method docstring

(C0116)


[convention] 265-265: Import outside toplevel (langflow.schema.dataframe.DataFrame)

(C0415)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3903d7b and b7314f0.

📒 Files selected for processing (3)
  • src/backend/base/langflow/schema/data.py (7 hunks)
  • src/backend/base/langflow/schema/dataframe.py (2 hunks)
  • src/backend/base/langflow/schema/message.py (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/backend/base/langflow/schema/dataframe.py (2)
src/backend/base/langflow/schema/message.py (2)
  • Message (38-288)
  • to_data (282-283)
src/backend/base/langflow/schema/data.py (2)
  • Data (23-275)
  • to_message (257-262)
src/backend/base/langflow/schema/message.py (2)
src/backend/base/langflow/schema/dataframe.py (2)
  • DataFrame (11-206)
  • to_data (183-190)
src/backend/base/langflow/schema/data.py (2)
  • Data (23-275)
  • to_dataframe (264-275)
🪛 Pylint (3.3.7)
src/backend/base/langflow/schema/data.py

[convention] 1-1: Missing module docstring

(C0114)


[convention] 268-268: Line too long (101/100)

(C0301)


[convention] 257-257: Missing function or method docstring

(C0116)


[convention] 258-258: Import outside toplevel (langflow.schema.message.Message)

(C0415)


[convention] 264-264: Missing function or method docstring

(C0116)


[convention] 265-265: Import outside toplevel (langflow.schema.dataframe.DataFrame)

(C0415)

src/backend/base/langflow/schema/dataframe.py

[convention] 204-204: Line too long (109/100)

(C0301)


[convention] 192-192: Missing function or method docstring

(C0116)


[warning] 193-193: Redefining name 'Message' from outer scope (line 8)

(W0621)


[warning] 193-193: Reimport 'Message' (imported line 8)

(W0404)


[convention] 193-193: Import outside toplevel (langflow.schema.message.Message)

(C0415)

src/backend/base/langflow/schema/message.py

[convention] 282-282: Missing function or method docstring

(C0116)


[convention] 286-286: Import outside toplevel (langflow.schema.dataframe.DataFrame)

(C0415)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Optimize new Python code in this PR
  • GitHub Check: Run Ruff Check and Format
  • GitHub Check: Update Starter Projects
🔇 Additional comments (2)
src/backend/base/langflow/schema/message.py (1)

285-288: Good implementation of the conversion method.

The method correctly operates on self (addressing previous design issues), uses local import to avoid circular dependencies, and follows the established pattern of wrapping the current instance in a list for DataFrame creation.

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 286-286: Import outside toplevel (langflow.schema.dataframe.DataFrame)

(C0415)

src/backend/base/langflow/schema/dataframe.py (1)

183-190: Well-implemented conversion method.

The to_data() method correctly operates on self, includes proper documentation, and follows a logical conversion pattern by wrapping DataFrame records under a 'results' key.

@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Jun 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/backend/base/langflow/components/processing/converter.py (2)

8-17: Add missing type hint for parameter.

The function parameter lacks a type hint, which reduces code clarity and IDE support.

The past review correctly identified this issue. The parameter v needs a proper type hint:

-def convert_to_message(v) -> Message:
+def convert_to_message(v: Message | Data | DataFrame | dict) -> Message:

46-49: Add comprehensive class docstring.

As identified in past reviews, the class needs proper documentation:

 class TypeConverterComponent(Component):
+    """
+    A component for converting between different data types.
+    
+    Supports conversion between Message, Data, and DataFrame types with
+    dynamic output configuration based on the selected output type.
+    """
     display_name = "Type Convert"
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 46-46: Missing class docstring

(C0115)

🧹 Nitpick comments (7)
src/backend/tests/unit/components/processing/test_type_converter_component.py (5)

1-9: Add module docstring and verify import consistency.

The module is missing a docstring and there's an inconsistency in the import path compared to the implementation file.

+"""
+Unit tests for the TypeConverterComponent.
+
+Tests conversion functionality between Message, Data, and DataFrame types,
+as well as dynamic output updating behavior.
+"""
 import pandas as pd
 import pytest
-from langflow.components.processing.converter import TypeConverterComponent
+from langflow.components.processing.converter import TypeConverterComponent

Note: Verify that the import path matches the actual file location in the implementation.

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)


[error] 1-1: Unable to import 'pandas'

(E0401)


[error] 3-3: Unable to import 'langflow.components.processing.converter'

(E0401)


[error] 3-3: No name 'components' in module 'langflow'

(E0611)


[error] 4-4: Unable to import 'langflow.schema.data'

(E0401)


[error] 4-4: No name 'schema' in module 'langflow'

(E0611)


[error] 5-5: Unable to import 'langflow.schema.dataframe'

(E0401)


[error] 5-5: No name 'schema' in module 'langflow'

(E0611)


[error] 6-6: Unable to import 'langflow.schema.message'

(E0401)


[error] 6-6: No name 'schema' in module 'langflow'

(E0611)


11-21: Add class docstring for better test documentation.

The test class lacks documentation explaining its purpose and structure.

 class TestTypeConverterComponent(ComponentTestBaseWithoutClient):
+    """Test suite for TypeConverterComponent functionality."""
+    
     @pytest.fixture
     def component_class(self):
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 11-11: Missing class docstring

(C0115)


49-49: Fix line length violations.

Multiple lines exceed the 100-character limit as flagged by static analysis.

-        component = component_class(input_data=Data(data={"text": "Hello World"}), output_type="Message")
+        component = component_class(
+            input_data=Data(data={"text": "Hello World"}), output_type="Message"
+        )

-        component = component_class(input_data=Data(data={"text": "Hello World"}), output_type="DataFrame")
+        component = component_class(
+            input_data=Data(data={"text": "Hello World"}), output_type="DataFrame"
+        )

Also applies to: 63-63

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 49-49: Line too long (105/100)

(C0301)


76-76: Verify hardcoded markdown table assertion.

The test asserts a specific markdown table format. This creates a brittle test that could break if the DataFrame-to-markdown conversion implementation changes.

Consider making this assertion more flexible:

-        assert result.text == "| col1   | col2   |\n|:-------|:-------|\n| Hello  | World  |"
+        # Verify it's a valid markdown table containing the expected data
+        assert "col1" in result.text
+        assert "col2" in result.text
+        assert "Hello" in result.text
+        assert "World" in result.text
+        assert "|" in result.text  # Ensure it's table format

97-115: Enhance test coverage for update_outputs method.

The test covers the happy path but misses edge cases and error conditions.

Consider adding additional test cases:

def test_update_outputs_edge_cases(self, component_class):
    """Test update_outputs with edge cases."""
    component = component_class(input_data=Message(text="Hello"), output_type="Message")
    frontend_node = {"outputs": []}
    
    # Test with invalid field_name (should not modify outputs)
    original_outputs = frontend_node["outputs"].copy()
    updated = component.update_outputs(frontend_node, "invalid_field", "Message")
    assert updated["outputs"] == original_outputs
    
    # Test with invalid output_type (should handle gracefully)
    updated = component.update_outputs(frontend_node, "output_type", "InvalidType")
    # Should either handle gracefully or raise appropriate error
src/backend/base/langflow/components/processing/converter.py (2)

1-6: Add missing module docstring.

The module lacks documentation explaining its purpose and functionality.

+"""
+Type conversion utilities and component for Langflow.
+
+Provides converter functions and a dynamic component for converting between
+Message, Data, and DataFrame types with configurable output selection.
+"""
 from typing import Any
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)


69-69: Fix multiple line length violations.

Several lines exceed the 100-character limit as flagged by static analysis.

-    outputs = [Output(display_name="Message Output", name="message_output", method="convert_to_message")]
+    outputs = [
+        Output(display_name="Message Output", name="message_output", method="convert_to_message")
+    ]

-                    Output(display_name="Message Output", name="message_output", method="convert_to_message").to_dict()
+                    Output(
+                        display_name="Message Output", 
+                        name="message_output", 
+                        method="convert_to_message"
+                    ).to_dict()

-                    Output(display_name="Data Output", name="data_output", method="convert_to_data").to_dict()
+                    Output(
+                        display_name="Data Output", 
+                        name="data_output", 
+                        method="convert_to_data"
+                    ).to_dict()

-        return convert_to_message(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        input_val = self.input_data[0] if isinstance(self.input_data, list) else self.input_data
+        return convert_to_message(input_val)

-        return convert_to_data(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        input_val = self.input_data[0] if isinstance(self.input_data, list) else self.input_data
+        return convert_to_data(input_val)

-        return convert_to_dataframe(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        input_val = self.input_data[0] if isinstance(self.input_data, list) else self.input_data
+        return convert_to_dataframe(input_val)

Also applies to: 80-80, 84-84, 89-89, 97-97, 101-101, 105-105

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 69-69: Line too long (105/100)

(C0301)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7314f0 and 84ed405.

📒 Files selected for processing (2)
  • src/backend/base/langflow/components/processing/converter.py (1 hunks)
  • src/backend/tests/unit/components/processing/test_type_converter_component.py (1 hunks)
🧰 Additional context used
🪛 Pylint (3.3.7)
src/backend/tests/unit/components/processing/test_type_converter_component.py

[convention] 49-49: Line too long (105/100)

(C0301)


[convention] 63-63: Line too long (107/100)

(C0301)


[convention] 1-1: Missing module docstring

(C0114)


[error] 1-1: Unable to import 'pandas'

(E0401)


[error] 3-3: Unable to import 'langflow.components.processing.converter'

(E0401)


[error] 3-3: No name 'components' in module 'langflow'

(E0611)


[error] 4-4: Unable to import 'langflow.schema.data'

(E0401)


[error] 4-4: No name 'schema' in module 'langflow'

(E0611)


[error] 5-5: Unable to import 'langflow.schema.dataframe'

(E0401)


[error] 5-5: No name 'schema' in module 'langflow'

(E0611)


[error] 6-6: Unable to import 'langflow.schema.message'

(E0401)


[error] 6-6: No name 'schema' in module 'langflow'

(E0611)


[convention] 11-11: Missing class docstring

(C0115)

src/backend/base/langflow/components/processing/converter.py

[convention] 69-69: Line too long (105/100)

(C0301)


[convention] 80-80: Line too long (119/100)

(C0301)


[convention] 84-84: Line too long (110/100)

(C0301)


[convention] 89-89: Line too long (111/100)

(C0301)


[convention] 97-97: Line too long (111/100)

(C0301)


[convention] 101-101: Line too long (108/100)

(C0301)


[convention] 105-105: Line too long (113/100)

(C0301)


[convention] 1-1: Missing module docstring

(C0114)


[convention] 46-46: Missing class docstring

(C0115)

⏰ Context from checks skipped due to timeout of 90000ms (11)
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 2/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 10/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 1/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 4/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 7/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 5/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 8/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 9/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 6/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 3/10
  • GitHub Check: Optimize new Python code in this PR
🔇 Additional comments (1)
src/backend/base/langflow/components/processing/converter.py (1)

29-31:

Details

❓ Verification inconclusive

Verify Data constructor usage with dict.

The code calls Data(v) with a dict, but this may not match the expected constructor signature.


🏁 Script executed:

#!/bin/bash
# Description: Verify the Data class constructor signature
# Expected: Should show how Data class handles dict initialization

ast-grep --pattern 'class Data:
  $$$
  def __init__($$$):
    $$$'

Length of output: 69


I couldn’t locate the Data class definition with the initial AST search. Let’s search the repository for any class Data declarations to confirm how its constructor is defined:


🏁 Script executed:

#!/bin/bash
# Find all Python files declaring class Data
rg -n "class Data" --glob "*.py"

Length of output: 1604


Let’s inspect how Data is defined to confirm its constructor signature:


🏁 Script executed:

#!/bin/bash
# Show class Data definition and its __init__ context
rg -n "class Data" -A 50 src/backend/base/langflow/schema/data.py

Length of output: 2087


Let’s verify how BaseModel.__init__ is defined in Pydantic to confirm if positional dicts are supported:


🏁 Script executed:

#!/bin/bash
python - << 'EOF'
import inspect
try:
    from pydantic import BaseModel
    print("BaseModel.__init__ signature:", inspect.signature(BaseModel.__init__))
except Exception as e:
    print("Error importing or inspecting BaseModel:", e)
EOF

Length of output: 78


Verify Data constructor usage with dict as positional argument

Pydantic’s BaseModel initializer only accepts field values as keyword arguments, so calling Data(v) where v is a dict may raise a TypeError or misassign fields. Please confirm whether Data(v) works as intended or if you should instead pass the dict explicitly:

  • File: src/backend/base/langflow/components/processing/converter.py, lines 29–31
  • Current code:
    if isinstance(v, dict):
        return Data(v)
  • Consider one of the following, depending on your intent:
    return Data(data=v)        # to populate the `data` field
    # – or –
    return Data(**v)           # if dict keys map directly to model fields

Comment on lines +95 to +105
def convert_to_message(self) -> Message:
"""Convert input to Message type."""
return convert_to_message(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)

def convert_to_data(self) -> Data:
"""Convert input to Data type."""
return convert_to_data(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)

def convert_to_dataframe(self) -> DataFrame:
"""Convert input to DataFrame type."""
return convert_to_dataframe(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract common input processing logic to reduce duplication.

All three conversion methods use identical logic to handle list inputs. This violates the DRY principle.

+    def _get_input_value(self):
+        """Extract the actual input value, handling list inputs."""
+        return self.input_data[0] if isinstance(self.input_data, list) else self.input_data
+
     def convert_to_message(self) -> Message:
         """Convert input to Message type."""
-        return convert_to_message(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        return convert_to_message(self._get_input_value())

     def convert_to_data(self) -> Data:
         """Convert input to Data type."""
-        return convert_to_data(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        return convert_to_data(self._get_input_value())

     def convert_to_dataframe(self) -> DataFrame:
         """Convert input to DataFrame type."""
-        return convert_to_dataframe(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
+        return convert_to_dataframe(self._get_input_value())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def convert_to_message(self) -> Message:
"""Convert input to Message type."""
return convert_to_message(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
def convert_to_data(self) -> Data:
"""Convert input to Data type."""
return convert_to_data(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
def convert_to_dataframe(self) -> DataFrame:
"""Convert input to DataFrame type."""
return convert_to_dataframe(self.input_data[0] if isinstance(self.input_data, list) else self.input_data)
def _get_input_value(self):
"""Extract the actual input value, handling list inputs."""
return self.input_data[0] if isinstance(self.input_data, list) else self.input_data
def convert_to_message(self) -> Message:
"""Convert input to Message type."""
return convert_to_message(self._get_input_value())
def convert_to_data(self) -> Data:
"""Convert input to Data type."""
return convert_to_data(self._get_input_value())
def convert_to_dataframe(self) -> DataFrame:
"""Convert input to DataFrame type."""
return convert_to_dataframe(self._get_input_value())
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 97-97: Line too long (111/100)

(C0301)


[convention] 101-101: Line too long (108/100)

(C0301)


[convention] 105-105: Line too long (113/100)

(C0301)

🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/converter.py around lines 95
to 105, the three conversion methods duplicate the logic to check if input_data
is a list and select the first element. Extract this common input processing
logic into a private helper method that returns the appropriate input element,
then update each conversion method to call this helper before passing the input
to the respective conversion function. This will reduce code duplication and
improve maintainability.

Comment on lines +71 to +93
def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
"""Dynamically show only the relevant output based on the selected output type."""
if field_name == "output_type":
# Start with empty outputs
frontend_node["outputs"] = []

# Add only the selected output type
if field_value == "Message":
frontend_node["outputs"].append(
Output(display_name="Message Output", name="message_output", method="convert_to_message").to_dict()
)
elif field_value == "Data":
frontend_node["outputs"].append(
Output(display_name="Data Output", name="data_output", method="convert_to_data").to_dict()
)
elif field_value == "DataFrame":
frontend_node["outputs"].append(
Output(
display_name="DataFrame Output", name="dataframe_output", method="convert_to_dataframe"
).to_dict()
)

return frontend_node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for invalid output types.

The update_outputs method doesn't handle the case where an invalid field_value is provided, which could leave the component in an inconsistent state.

     def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
         """Dynamically show only the relevant output based on the selected output type."""
         if field_name == "output_type":
             # Start with empty outputs
             frontend_node["outputs"] = []

             # Add only the selected output type
             if field_value == "Message":
                 frontend_node["outputs"].append(
                     Output(
                         display_name="Message Output", 
                         name="message_output", 
                         method="convert_to_message"
                     ).to_dict()
                 )
             elif field_value == "Data":
                 frontend_node["outputs"].append(
                     Output(
                         display_name="Data Output", 
                         name="data_output", 
                         method="convert_to_data"
                     ).to_dict()
                 )
             elif field_value == "DataFrame":
                 frontend_node["outputs"].append(
                     Output(
                         display_name="DataFrame Output", 
                         name="dataframe_output", 
                         method="convert_to_dataframe"
                     ).to_dict()
                 )
+            else:
+                # Handle invalid output type by defaulting to Message
+                frontend_node["outputs"].append(
+                    Output(
+                         display_name="Message Output", 
+                         name="message_output", 
+                         method="convert_to_message"
+                     ).to_dict()
+                )

         return frontend_node
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
"""Dynamically show only the relevant output based on the selected output type."""
if field_name == "output_type":
# Start with empty outputs
frontend_node["outputs"] = []
# Add only the selected output type
if field_value == "Message":
frontend_node["outputs"].append(
Output(display_name="Message Output", name="message_output", method="convert_to_message").to_dict()
)
elif field_value == "Data":
frontend_node["outputs"].append(
Output(display_name="Data Output", name="data_output", method="convert_to_data").to_dict()
)
elif field_value == "DataFrame":
frontend_node["outputs"].append(
Output(
display_name="DataFrame Output", name="dataframe_output", method="convert_to_dataframe"
).to_dict()
)
return frontend_node
def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
"""Dynamically show only the relevant output based on the selected output type."""
if field_name == "output_type":
# Start with empty outputs
frontend_node["outputs"] = []
# Add only the selected output type
if field_value == "Message":
frontend_node["outputs"].append(
Output(display_name="Message Output", name="message_output", method="convert_to_message").to_dict()
)
elif field_value == "Data":
frontend_node["outputs"].append(
Output(display_name="Data Output", name="data_output", method="convert_to_data").to_dict()
)
elif field_value == "DataFrame":
frontend_node["outputs"].append(
Output(
display_name="DataFrame Output", name="dataframe_output", method="convert_to_dataframe"
).to_dict()
)
else:
# Handle invalid output type by defaulting to Message
frontend_node["outputs"].append(
Output(display_name="Message Output", name="message_output", method="convert_to_message").to_dict()
)
return frontend_node
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 80-80: Line too long (119/100)

(C0301)


[convention] 84-84: Line too long (110/100)

(C0301)


[convention] 89-89: Line too long (111/100)

(C0301)

🤖 Prompt for AI Agents
In src/backend/base/langflow/components/processing/converter.py around lines 71
to 93, the update_outputs method lacks error handling for invalid output types
in the field_value parameter. To fix this, add a check after the existing
if-elif blocks to handle unexpected field_value values by either raising a
ValueError with a clear message or logging an error and leaving outputs empty.
This ensures the component does not enter an inconsistent state when given
invalid input.

@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Jun 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/backend/base/langflow/components/processing/converter.py (3)

48-51: Add comprehensive class docstring.

This issue was already identified in previous reviews. The class needs a docstring explaining its purpose and functionality.

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 48-48: Missing class docstring

(C0115)


73-95: Add error handling for invalid output types.

This issue was already identified in previous reviews. The update_outputs method lacks error handling for invalid field_value parameters.

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 82-82: Line too long (119/100)

(C0301)


[convention] 86-86: Line too long (110/100)

(C0301)


[convention] 91-91: Line too long (111/100)

(C0301)


97-107: Extract common input processing logic to reduce duplication.

This code duplication issue was already identified in previous reviews. All three conversion methods use identical logic to handle list inputs, violating the DRY principle.

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 99-99: Line too long (111/100)

(C0301)


[convention] 103-103: Line too long (108/100)

(C0301)


[convention] 107-107: Line too long (113/100)

(C0301)

🧹 Nitpick comments (3)
src/backend/base/langflow/components/processing/converter.py (3)

1-6: Add module docstring to document the converter functionality.

The module is missing a docstring that would help developers understand its purpose and the conversion capabilities it provides.

+"""
+Type conversion utilities for converting between Message, Data, and DataFrame types.
+
+This module provides converter functions and a TypeConverterComponent that enables
+dynamic conversion between the core data types used in the Langflow system.
+"""
 from typing import Any
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)


8-17: Add missing type hints for the parameter.

The function is missing proper type hints for the input parameter, which affects code clarity and IDE support.

-def convert_to_message(v) -> Message:
+def convert_to_message(v: Message | Data | DataFrame | dict) -> Message:

71-71: Address line length violations for better readability.

Multiple lines exceed the 100-character limit, affecting code readability and compliance with style guidelines.

Consider breaking long lines using appropriate line continuation or reformatting:

-    outputs = [Output(display_name="Message Output", name="message_output", method="convert_to_message")]
+    outputs = [
+        Output(
+            display_name="Message Output", 
+            name="message_output", 
+            method="convert_to_message"
+        )
+    ]

Apply similar formatting to other long lines in the update_outputs method and conversion methods.

Also applies to: 82-82, 86-86, 91-91, 99-99, 103-103, 107-107

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 71-71: Line too long (105/100)

(C0301)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84ed405 and 619cd6a.

📒 Files selected for processing (1)
  • src/backend/base/langflow/components/processing/converter.py (1 hunks)
🧰 Additional context used
🪛 Pylint (3.3.7)
src/backend/base/langflow/components/processing/converter.py

[convention] 71-71: Line too long (105/100)

(C0301)


[convention] 82-82: Line too long (119/100)

(C0301)


[convention] 86-86: Line too long (110/100)

(C0301)


[convention] 91-91: Line too long (111/100)

(C0301)


[convention] 99-99: Line too long (111/100)

(C0301)


[convention] 103-103: Line too long (108/100)

(C0301)


[convention] 107-107: Line too long (113/100)

(C0301)


[convention] 1-1: Missing module docstring

(C0114)


[convention] 48-48: Missing class docstring

(C0115)

⏰ Context from checks skipped due to timeout of 90000ms (21)
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 6/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 3/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 10/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 7/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 8/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 9/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 5/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 1/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 4/10
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 2/10
  • GitHub Check: Lint Backend / Run Mypy (3.10)
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Lint Backend / Run Mypy (3.13)
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Optimize new Python code in this PR
  • GitHub Check: Run Ruff Check and Format
  • GitHub Check: Update Starter Projects
🔇 Additional comments (1)
src/backend/base/langflow/components/processing/converter.py (1)

29-30:

Details

✅ Verification successful

Verify dictionary handling consistency across converter functions.

The dictionary handling differs between convert_to_data and convert_to_dataframe functions. Ensure this behavior aligns with the expected data structures.

Also applies to: 43-44


🏁 Script executed:

#!/bin/bash
# Search for Data and DataFrame constructor usage patterns to verify consistency
echo "=== Data constructor usage ==="
rg "Data\(" -A 2 -B 2

echo "=== DataFrame constructor usage ==="
rg "DataFrame\(" -A 2 -B 2

Length of output: 118195


🏁 Script executed:

#!/bin/bash
# Locate the convert_to_data and convert_to_dataframe functions
grep -R "def convert_to_data" -n src/backend/base/langflow/components/processing/converter.py
grep -R "def convert_to_dataframe" -n src/backend/base/langflow/components/processing/converter.py

# Show their implementations for review
sed -n '1,200p' src/backend/base/langflow/components/processing/converter.py
sed -n '200,400p' src/backend/base/langflow/components/processing/converter.py

Length of output: 4447


🏁 Script executed:

#!/bin/bash
# Inspect DataFrame implementation to confirm constructor behavior
grep -R "class DataFrame" -n src/backend/base/langflow/schema/dataframe.py
sed -n '1,200p' src/backend/base/langflow/schema/dataframe.py

Length of output: 7161


🏁 Script executed:

#!/bin/bash
# Inspect Data class constructor
grep -R "class Data" -n src/backend/base/langflow/schema/data.py
sed -n '1,200p' src/backend/base/langflow/schema/data.py

Length of output: 7620


Dictionary conversion behavior is consistent
Both convert_to_data and convert_to_dataframe correctly wrap a plain dict into the respective target type—Data(v) for a Data object and DataFrame([v]) for a single‐row DataFrame. This aligns with the intended conversion patterns, so no changes are required.

@github-actions github-actions bot added enhancement New feature or request and removed enhancement New feature or request labels Jun 2, 2025
@edwinjosechittilappilly edwinjosechittilappilly added this pull request to the merge queue Jun 2, 2025
Merged via the queue into main with commit 3608368 Jun 2, 2025
35 checks passed
@edwinjosechittilappilly edwinjosechittilappilly deleted the convert_component branch June 2, 2025 20:28
dev-thiago-oliver pushed a commit to vvidai/langflow that referenced this pull request Jun 3, 2025
…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 <[email protected]>
Co-authored-by: Carlos Coelho <[email protected]>
Co-authored-by: Yuqi Tang <[email protected]>
ogabrielluiz added a commit to bkatya2001/langflow that referenced this pull request Jun 24, 2025
…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 <[email protected]>
Co-authored-by: Carlos Coelho <[email protected]>
Co-authored-by: Yuqi Tang <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants