langflow icon indicating copy to clipboard operation
langflow copied to clipboard

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

Open codeflash-ai[bot] opened this issue 7 months ago • 0 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.


📄 15% (0.15x) speedup for merge_build_configs in src/backend/base/langflow/utils/component_utils.py

⏱️ Runtime : 339 microseconds 294 microseconds (best of 202 runs)

📝 Explanation and details

Here is an optimized version of the provided program.

Modifications and Optimizations.

  1. Helper Function merge_dicts.

    • Extracted the recursive merging logic into a helper function merge_dicts.
    • This enhances reusability and separates concerns, making the code cleaner and easier to manage and test.
  2. Recursive Call.

    • The recursive call within the merge_dicts function directly updates the base dictionary instead of iterating through nested keys separately within the main function.
  3. Simplification.

    • The main function merge_build_configs is simplified into a single line by utilizing the merge_dicts function, improving readability and maintainability.

The functionality remains unchanged, but this version is more efficient and modular.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 25 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 merge_build_configs


# 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 merge_build_configs

# unit tests

def test_simple_overwrite():
    base_config = dotdict({'key1': 'value1'})
    override_config = dotdict({'key1': 'override_value1'})
    expected_result = dotdict({'key1': 'override_value1'})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_adding_new_key():
    base_config = dotdict({'key1': 'value1'})
    override_config = dotdict({'key2': 'value2'})
    expected_result = dotdict({'key1': 'value1', 'key2': 'value2'})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_simple_nested_merge():
    base_config = dotdict({'key1': {'subkey1': 'subvalue1'}})
    override_config = dotdict({'key1': {'subkey2': 'subvalue2'}})
    expected_result = dotdict({'key1': {'subkey1': 'subvalue1', 'subkey2': 'subvalue2'}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_nested_overwrite():
    base_config = dotdict({'key1': {'subkey1': 'subvalue1'}})
    override_config = dotdict({'key1': {'subkey1': 'override_subvalue1'}})
    expected_result = dotdict({'key1': {'subkey1': 'override_subvalue1'}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_multiple_levels_of_nesting():
    base_config = dotdict({'key1': {'subkey1': {'subsubkey1': 'subsubvalue1'}}})
    override_config = dotdict({'key1': {'subkey1': {'subsubkey2': 'subsubvalue2'}}})
    expected_result = dotdict({'key1': {'subkey1': {'subsubkey1': 'subsubvalue1', 'subsubkey2': 'subsubvalue2'}}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_mixed_types_in_nested_dictionaries():
    base_config = dotdict({'key1': {'subkey1': 'subvalue1', 'subkey2': {'subsubkey1': 'subsubvalue1'}}})
    override_config = dotdict({'key1': {'subkey2': 'override_subvalue2', 'subkey3': 'subvalue3'}})
    expected_result = dotdict({'key1': {'subkey1': 'subvalue1', 'subkey2': 'override_subvalue2', 'subkey3': 'subvalue3'}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_empty_base_config():
    base_config = dotdict({})
    override_config = dotdict({'key1': 'value1'})
    expected_result = dotdict({'key1': 'value1'})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_empty_override_config():
    base_config = dotdict({'key1': 'value1'})
    override_config = dotdict({})
    expected_result = dotdict({'key1': 'value1'})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_both_configs_empty():
    base_config = dotdict({})
    override_config = dotdict({})
    expected_result = dotdict({})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_non_dictionary_values():
    base_config = dotdict({'key1': 'value1'})
    override_config = dotdict({'key1': 123})
    expected_result = dotdict({'key1': 123})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_conflicting_types():
    base_config = dotdict({'key1': {'subkey1': 'subvalue1'}})
    override_config = dotdict({'key1': 'override_value1'})
    expected_result = dotdict({'key1': 'override_value1'})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_large_flat_dictionary():
    base_config = dotdict({f'key{i}': f'value{i}' for i in range(1000)})
    override_config = dotdict({f'key{i}': f'override_value{i}' for i in range(500, 1500)})
    expected_result = dotdict({f'key{i}': f'value{i}' for i in range(500)})
    expected_result.update({f'key{i}': f'override_value{i}' for i in range(500, 1500)})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_large_nested_dictionary():
    base_config = dotdict({f'key{i}': {'subkey': f'value{i}'} for i in range(100)})
    override_config = dotdict({f'key{i}': {'subkey': f'override_value{i}'} for i in range(50, 150)})
    expected_result = dotdict({f'key{i}': {'subkey': f'value{i}'} for i in range(50)})
    expected_result.update({f'key{i}': {'subkey': f'override_value{i}'} for i in range(50, 150)})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_mixed_structures():
    base_config = dotdict({'key1': 'value1', 'key2': {'subkey1': 'subvalue1'}, 'key3': [1, 2, 3]})
    override_config = dotdict({'key2': {'subkey2': 'subvalue2'}, 'key3': 'override_value3', 'key4': 4})
    expected_result = dotdict({'key1': 'value1', 'key2': {'subkey1': 'subvalue1', 'subkey2': 'subvalue2'}, 'key3': 'override_value3', 'key4': 4})
    codeflash_output = merge_build_configs(base_config, override_config)
# 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
from langflow.utils.component_utils import merge_build_configs


# 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 merge_build_configs

# unit tests

def test_simple_merge():
    base_config = dotdict({'a': 1, 'b': 2})
    override_config = dotdict({'b': 3, 'c': 4})
    expected = dotdict({'a': 1, 'b': 3, 'c': 4})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_non_overlapping_keys():
    base_config = dotdict({'a': 1, 'b': 2})
    override_config = dotdict({'c': 3, 'd': 4})
    expected = dotdict({'a': 1, 'b': 2, 'c': 3, 'd': 4})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_empty_base_config():
    base_config = dotdict({})
    override_config = dotdict({'a': 1, 'b': 2})
    expected = dotdict({'a': 1, 'b': 2})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_empty_override_config():
    base_config = dotdict({'a': 1, 'b': 2})
    override_config = dotdict({})
    expected = dotdict({'a': 1, 'b': 2})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_nested_dictionaries():
    base_config = dotdict({'a': {'x': 1}})
    override_config = dotdict({'a': {'y': 2}})
    expected = dotdict({'a': {'x': 1, 'y': 2}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_conflicting_types():
    base_config = dotdict({'a': 1})
    override_config = dotdict({'a': {'b': 2}})
    expected = dotdict({'a': {'b': 2}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_identical_configs():
    base_config = dotdict({'a': 1, 'b': 2})
    override_config = dotdict({'a': 1, 'b': 2})
    expected = dotdict({'a': 1, 'b': 2})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_large_number_of_keys():
    base_config = dotdict({f'key{i}': i for i in range(1000)})
    override_config = dotdict({f'key{i}': i + 1000 for i in range(1000, 2000)})
    expected = dotdict({f'key{i}': i for i in range(1000)})
    expected.update({f'key{i}': i + 1000 for i in range(1000, 2000)})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_deeply_nested_structures():
    base_config = dotdict({'a': {'b': {'c': {'d': {'e': 1}}}}})
    override_config = dotdict({'a': {'b': {'c': {'d': {'f': 2}}}}})
    expected = dotdict({'a': {'b': {'c': {'d': {'e': 1, 'f': 2}}}}})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_special_characters_in_keys():
    base_config = dotdict({'a-b': 1})
    override_config = dotdict({'a-b': 2})
    expected = dotdict({'a-b': 2})
    codeflash_output = merge_build_configs(base_config, override_config)

def test_mixed_types_in_nested_dictionaries():
    base_config = dotdict({'a': {'b': 1, 'c': [1, 2, 3]}})
    override_config = dotdict({'a': {'b': 2, 'd': 'string'}})
    expected = dotdict({'a': {'b': 2, 'c': [1, 2, 3], 'd': 'string'}})
    codeflash_output = merge_build_configs(base_config, override_config)
# 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-24T19.29.20 and push.

Codeflash

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