Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 126 commits into from

Conversation

codeflash-ai[bot]
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Apr 24, 2025

⚡️ 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

lucaseduoli and others added 30 commits April 15, 2025 12:49
edwinjosechittilappilly and others added 18 commits April 23, 2025 19:05
…(`mcp-server-backend`)

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.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Apr 24, 2025
@dosubot dosubot bot added size:XS This PR changes 0-9 lines, ignoring generated files. python Pull requests that update Python code labels Apr 24, 2025
Copy link

codspeed-hq bot commented Apr 24, 2025

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

⚠️ 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%

Base automatically changed from mcp-server-backend to main April 29, 2025 17:15
@dosubot dosubot bot removed the size:XS This PR changes 0-9 lines, ignoring generated files. label Apr 29, 2025
@codeflash-ai codeflash-ai bot closed this Apr 29, 2025
Copy link
Contributor Author

codeflash-ai bot commented Apr 29, 2025

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

@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Apr 29, 2025
@codeflash-ai codeflash-ai bot deleted the codeflash/optimize-pr7741-2025-04-24T17.06.21 branch April 29, 2025 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡️ codeflash Optimization PR opened by Codeflash AI python Pull requests that update Python code size:XXL This PR changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants