langflow
langflow copied to clipboard
⚡️ Speed up function `merge_build_configs` by 15% in PR #7741 (`mcp-server-backend`)
⚡️ 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.
-
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.
- Extracted the recursive merging logic into a helper function
-
Recursive Call.
- The recursive call within the
merge_dictsfunction directly updates thebasedictionary instead of iterating through nested keys separately within the main function.
- The recursive call within the
-
Simplification.
- The main function
merge_build_configsis simplified into a single line by utilizing themerge_dictsfunction, improving readability and maintainability.
- The main function
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.