langflow icon indicating copy to clipboard operation
langflow copied to clipboard

⚡️ Speed up function `set_multiple_field_display` by 42% in PR #7741 (`mcp-server-backend`)

Open codeflash-ai[bot] opened this issue 7 months ago • 1 comments

⚡️ This pull request contains optimizations for PR #7741

If you approve this dependent PR, these changes will be merged into the original PR branch mcp-server-backend.

This PR will be automatically closed if the original PR is merged.


📄 42% (0.42x) speedup for set_multiple_field_display in src/backend/base/langflow/utils/component_utils.py

⏱️ Runtime : 1.09 millisecond 767 microseconds (best of 139 runs)

📝 Explanation and details

To optimize the given Python program for better runtime and memory efficiency, we can take the following steps.

  1. Avoid redundant checks and assignments: We can combine the logic to set the visibility of the fields in a more concise way.
  2. Optimize Looping: Use dictionary operations efficiently to minimize overhead.

Here's the optimized version of the program.

Explanation of changes.

  1. Inline Check in Loops: Instead of calling the set_field_display function within the loops which involves additional function call overhead, I directly inlined the check and assignment within the loops. This enhances the performance by avoiding redundant function calls.

  2. Return Type of set_field_display: Changed the return type of set_field_display to None since it makes more sense logically and is not utilized further in the code.

By performing these optimizations, the program should run faster and be more memory-efficient while maintaining its original functionality.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 30 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage
🌀 Generated Regression Tests Details
import pytest  # used for our unit tests
from langflow.utils.component_utils import set_multiple_field_display


# function to test
class dotdict(dict):  # noqa: N801
    """dotdict allows accessing dictionary elements using dot notation (e.g., dict.key instead of dict['key']).

    It automatically converts nested dictionaries into dotdict instances, enabling dot notation on them as well.

    Note:
        - Only keys that are valid attribute names (e.g., strings that could be variable names) are accessible via dot
          notation.
        - Keys which are not valid Python attribute names or collide with the dict method names (like 'items', 'keys')
          should be accessed using the traditional dict['key'] notation.
    """

    def __getattr__(self, attr):
        """Override dot access to behave like dictionary lookup. Automatically convert nested dicts to dotdicts.

        Args:
            attr (str): Attribute to access.

        Returns:
            The value associated with 'attr' in the dictionary, converted to dotdict if it is a dict.

        Raises:
            AttributeError: If the attribute is not found in the dictionary.
        """
        try:
            value = self[attr]
            if isinstance(value, dict) and not isinstance(value, dotdict):
                value = dotdict(value)
                self[attr] = value  # Update self to nest dotdict for future accesses
        except KeyError as e:
            msg = f"'dotdict' object has no attribute '{attr}'"
            raise AttributeError(msg) from e
        else:
            return value

    def __setattr__(self, key, value) -> None:
        """Override attribute setting to work as dictionary item assignment.

        Args:
            key (str): The key under which to store the value.
            value: The value to store in the dictionary.
        """
        if isinstance(value, dict) and not isinstance(value, dotdict):
            value = dotdict(value)
        self[key] = value

    def __delattr__(self, key) -> None:
        """Override attribute deletion to work as dictionary item deletion.

        Args:
            key (str): The key of the item to delete from the dictionary.

        Raises:
            AttributeError: If the key is not found in the dictionary.
        """
        try:
            del self[key]
        except KeyError as e:
            msg = f"'dotdict' object has no attribute '{key}'"
            raise AttributeError(msg) from e

    def __missing__(self, key):
        """Handle missing keys by returning an empty dotdict. This allows chaining access without raising KeyError.

        Args:
            key: The missing key.

        Returns:
            An empty dotdict instance for the given missing key.
        """
        return dotdict()
from langflow.utils.component_utils import set_multiple_field_display

# unit tests

# Basic Functionality
def test_single_field_update_with_fields():
    build_config = dotdict({'field1': {'show': False}})
    fields = {'field1': True}
    expected = dotdict({'field1': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_multiple_fields_update_with_fields():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    fields = {'field1': True, 'field2': False}
    expected = dotdict({'field1': {'show': True}, 'field2': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_single_field_update_with_field_list():
    build_config = dotdict({'field1': {'show': False}})
    field_list = ['field1']
    expected = dotdict({'field1': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True)

def test_multiple_fields_update_with_field_list():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    field_list = ['field1', 'field2']
    expected = dotdict({'field1': {'show': True}, 'field2': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True)

# Mixed Valid and Invalid Fields
def test_fields_not_present_in_build_config():
    build_config = dotdict({'field1': {'show': False}})
    fields = {'field1': True, 'nonexistent_field': False}
    expected = dotdict({'field1': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_fields_with_invalid_types_in_build_config():
    build_config = dotdict({'field1': {'show': False}, 'field2': 'invalid_type'})
    fields = {'field1': True, 'field2': False}
    expected = dotdict({'field1': {'show': True}, 'field2': 'invalid_type'})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

# Edge Cases
def test_empty_fields_dictionary():
    build_config = dotdict({'field1': {'show': False}})
    fields = {}
    expected = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_empty_field_list():
    build_config = dotdict({'field1': {'show': False}})
    field_list = []
    expected = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True)

def test_both_fields_and_field_list_none():
    build_config = dotdict({'field1': {'show': False}})
    expected = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config)

def test_conflicting_parameters():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    fields = {'field1': True}
    field_list = ['field2']
    expected = dotdict({'field1': {'show': True}, 'field2': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields, field_list=field_list, is_visible=False)

# Nested Dictionaries
def test_nested_dotdict_structures():
    build_config = dotdict({'nested': {'field1': {'show': False}}})
    fields = {'nested.field1': True}
    expected = dotdict({'nested': {'field1': {'show': True}}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_deeply_nested_structures():
    build_config = dotdict({'nested': {'level1': {'level2': {'field1': {'show': False}}}}})
    fields = {'nested.level1.level2.field1': True}
    expected = dotdict({'nested': {'level1': {'level2': {'field1': {'show': True}}}}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

# Large Scale Test Cases
def test_large_number_of_fields_in_fields_dictionary():
    build_config = dotdict({f'field{i}': {'show': False} for i in range(1000)})
    fields = {f'field{i}': True for i in range(1000)}
    expected = dotdict({f'field{i}': {'show': True} for i in range(1000)})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_large_number_of_fields_in_field_list():
    build_config = dotdict({f'field{i}': {'show': False} for i in range(1000)})
    field_list = [f'field{i}' for i in range(1000)]
    expected = dotdict({f'field{i}': {'show': True} for i in range(1000)})
    codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True)

# Complex Configurations
def test_mixed_nested_and_non_nested_fields():
    build_config = dotdict({'field1': {'show': False}, 'nested': {'field2': {'show': True}}})
    fields = {'field1': True, 'nested.field2': False}
    expected = dotdict({'field1': {'show': True}, 'nested': {'field2': {'show': False}}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)

def test_fields_with_different_types_of_values():
    build_config = dotdict({'field1': {'show': False}, 'field2': 123, 'field3': 'string'})
    field_list = ['field1', 'field2', 'field3']
    expected = dotdict({'field1': {'show': True}, 'field2': 123, 'field3': 'string'})
    codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True)

# Different Initial Visibility States
def test_initial_visibility_states():
    build_config = dotdict({'field1': {'show': True}, 'field2': {'show': False}})
    fields = {'field1': False, 'field2': True}
    expected = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields=fields)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

import pytest  # used for our unit tests
# function to test
from langflow.schema.dotdict import dotdict
from langflow.utils.component_utils import set_multiple_field_display


class dotdict(dict):  # noqa: N801
    """dotdict allows accessing dictionary elements using dot notation (e.g., dict.key instead of dict['key']).

    It automatically converts nested dictionaries into dotdict instances, enabling dot notation on them as well.

    Note:
        - Only keys that are valid attribute names (e.g., strings that could be variable names) are accessible via dot
          notation.
        - Keys which are not valid Python attribute names or collide with the dict method names (like 'items', 'keys')
          should be accessed using the traditional dict['key'] notation.
    """

    def __getattr__(self, attr):
        """Override dot access to behave like dictionary lookup. Automatically convert nested dicts to dotdicts.

        Args:
            attr (str): Attribute to access.

        Returns:
            The value associated with 'attr' in the dictionary, converted to dotdict if it is a dict.

        Raises:
            AttributeError: If the attribute is not found in the dictionary.
        """
        try:
            value = self[attr]
            if isinstance(value, dict) and not isinstance(value, dotdict):
                value = dotdict(value)
                self[attr] = value  # Update self to nest dotdict for future accesses
        except KeyError as e:
            msg = f"'dotdict' object has no attribute '{attr}'"
            raise AttributeError(msg) from e
        else:
            return value

    def __setattr__(self, key, value) -> None:
        """Override attribute setting to work as dictionary item assignment.

        Args:
            key (str): The key under which to store the value.
            value: The value to store in the dictionary.
        """
        if isinstance(value, dict) and not isinstance(value, dotdict):
            value = dotdict(value)
        self[key] = value

    def __delattr__(self, key) -> None:
        """Override attribute deletion to work as dictionary item deletion.

        Args:
            key (str): The key of the item to delete from the dictionary.

        Raises:
            AttributeError: If the key is not found in the dictionary.
        """
        try:
            del self[key]
        except KeyError as e:
            msg = f"'dotdict' object has no attribute '{key}'"
            raise AttributeError(msg) from e

    def __missing__(self, key):
        """Handle missing keys by returning an empty dotdict. This allows chaining access without raising KeyError.

        Args:
            key: The missing key.

        Returns:
            An empty dotdict instance for the given missing key.
        """
        return dotdict()
from langflow.utils.component_utils import set_multiple_field_display

# unit tests

def test_single_field_visibility_change():
    build_config = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields={'field1': True}); result = codeflash_output

def test_multiple_field_visibility_changes():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields={'field1': True, 'field2': False}); result = codeflash_output

def test_empty_inputs():
    build_config = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config); result = codeflash_output

def test_non_existent_fields():
    build_config = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields={'non_existent_field': True}); result = codeflash_output

def test_nested_field_visibility_change():
    build_config = dotdict({'parent': {'child': {'show': False}}})
    codeflash_output = set_multiple_field_display(build_config, fields={'parent.child': True}); result = codeflash_output

def test_large_number_of_fields():
    build_config = dotdict({f'field{i}': {'show': False} for i in range(1000)})
    fields = {f'field{i}': bool(i % 2) for i in range(1000)}
    codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
    for i in range(1000):
        pass

def test_mixed_valid_and_invalid_fields():
    build_config = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields={'field1': True, 'non_existent_field': False}); result = codeflash_output



def test_consistent_state_across_multiple_calls():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}})
    codeflash_output = set_multiple_field_display(build_config, fields={'field1': True}); result = codeflash_output
    codeflash_output = set_multiple_field_display(result, field_list=['field2'], is_visible=False); result = codeflash_output

def test_missing_keys():
    build_config = dotdict({'field1': {'show': False}})
    codeflash_output = set_multiple_field_display(build_config, fields={'missing_field': True}); result = codeflash_output

def test_boolean_edge_cases():
    build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}, 'field3': {'show': None}})
    codeflash_output = set_multiple_field_display(build_config, fields={'field1': True, 'field2': False, 'field3': None}); result = codeflash_output

def test_deeply_nested_structures():
    build_config = dotdict({'parent': {'child': {'show': False}}})
    codeflash_output = set_multiple_field_display(build_config, fields={'parent.child': True}); result = codeflash_output

def test_large_scale_performance():
    build_config = dotdict({f'field{i}': {'show': False} for i in range(1000)})
    fields = {f'field{i}': bool(i % 2) for i in range(1000)}
    codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
    for i in range(1000):
        pass
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-pr7741-2025-04-24T17.06.21 and push.

Codeflash

codeflash-ai[bot] avatar Apr 24 '25 17:04 codeflash-ai[bot]

CodSpeed Performance Report

Merging #7784 will degrade performances by 22.35%

Comparing codeflash/optimize-pr7741-2025-04-24T17.06.21 (d27dbb5) with main (cf16595)

Summary

❌ 1 regressions
✅ 18 untouched benchmarks

:warning: Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
test_build_flow_invalid_job_id 9.5 ms 12.3 ms -22.35%

codspeed-hq[bot] avatar Apr 24 '25 17:04 codspeed-hq[bot]

This PR has been automatically closed because the original PR #7741 by edwinjosechittilappilly was closed.

codeflash-ai[bot] avatar Apr 29 '25 17:04 codeflash-ai[bot]