langflow
langflow copied to clipboard
⚡️ Speed up function `set_multiple_field_display` by 50% in PR #7755 (`feat-add-data-ops-component`)
⚡️ This pull request contains optimizations for PR #7755
If you approve this dependent PR, these changes will be merged into the original PR branch feat-add-data-ops-component.
This PR will be automatically closed if the original PR is merged.
📄 50% (0.50x) speedup for set_multiple_field_display in src/backend/base/langflow/utils/component_utils.py
⏱️ Runtime : 1.07 millisecond → 714 microseconds (best of 107 runs)
📝 Explanation and details
To optimize the provided code for better performance, we can reduce the number of lookups and validation checks, particularly by bypassing unnecessary dict and list operations. We can also handle the case where multiple fields need updating in a bulk operation more efficiently.
Here is the optimized version.
Changes Made.
-
set_field_display.
- Changed the return type to
Nonesince it simply modifies thebuild_configin place. - Used a
try-exceptblock for handling KeyError and TypeError to avoid unnecessary checks for field existence and type validation, which can slightly improve the speed.
- Changed the return type to
-
set_multiple_field_display.
- Removed the redundant assignment of
build_configsinceset_field_displaynow modifies it in place. - Optimized the
if-elifcondition checks by directly passing the parameters toset_field_displaywithout reassigningbuild_config.
- Removed the redundant assignment of
This will ensure that we are working efficiently with the structure of the build_config and reducing the overhead due to multiple lookups and assignments.
✅ Correctness verification report:
| Test | Status |
|---|---|
| ⚙️ Existing Unit Tests | 🔘 None Found |
| 🌀 Generated Regression Tests | ✅ 31 Passed |
| ⏪ Replay Tests | 🔘 None Found |
| 🔎 Concolic Coverage Tests | 🔘 None Found |
| 📊 Tests Coverage |
🌀 Generated Regression Tests Details
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_update():
build_config = dotdict({"field1": {"show": False}})
fields = {"field1": True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_multiple_field_updates():
build_config = dotdict({"field1": {"show": False}, "field2": {"show": True}})
fields = {"field1": True, "field2": False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_single_field_update_with_field_list():
build_config = dotdict({"field1": {"show": False}})
field_list = ["field1"]
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True); result = codeflash_output
def test_multiple_field_updates_with_field_list():
build_config = dotdict({"field1": {"show": False}, "field2": {"show": True}})
field_list = ["field1", "field2"]
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=False); result = codeflash_output
def test_mixed_valid_and_invalid_fields():
build_config = dotdict({"field1": {"show": False}})
fields = {"field1": True, "invalid_field": False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_nested_dotdict_structures():
build_config = dotdict({"nested": {"field1": {"show": False}}})
fields = {"nested.field1": True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_empty_fields_dictionary():
build_config = dotdict({"field1": {"show": False}})
fields = {}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_empty_field_list():
build_config = dotdict({"field1": {"show": False}})
field_list = []
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True); result = codeflash_output
def test_large_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)}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
for i in range(1000):
pass
def test_large_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)]
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True); result = codeflash_output
for i in range(1000):
pass
def test_conflicting_inputs():
build_config = dotdict({"field1": {"show": False}, "field2": {"show": True}})
fields = {"field1": True}
field_list = ["field2"]
codeflash_output = set_multiple_field_display(build_config, fields=fields, field_list=field_list, is_visible=False); result = codeflash_output
def test_non_boolean_is_visible_values():
build_config = dotdict({"field1": {"show": False}})
field_list = ["field1"]
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=None); result = codeflash_output
def test_fields_with_non_dictionary_values():
build_config = dotdict({"field1": "not_a_dict"})
fields = {"field1": True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_fields_missing_show_key():
build_config = dotdict({"field1": {}})
fields = {"field1": True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
# 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 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
def test_single_field_visibility_true():
build_config = dotdict({'field1': {'show': False}})
fields = {'field1': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_single_field_visibility_false():
build_config = dotdict({'field1': {'show': True}})
fields = {'field1': False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_multiple_fields_mixed_visibility():
build_config = dotdict({'field1': {'show': False}, 'field2': {'show': True}, 'field3': {'show': False}})
fields = {'field1': True, 'field2': False, 'field3': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_field_list_visibility_true():
build_config = dotdict({'field1': {'show': False}, 'field2': {'show': False}})
field_list = ['field1', 'field2']
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True); result = codeflash_output
def test_field_list_visibility_false():
build_config = dotdict({'field1': {'show': True}, 'field2': {'show': True}})
field_list = ['field1', 'field2']
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=False); result = codeflash_output
def test_empty_fields():
build_config = dotdict({'field1': {'show': True}})
fields = {}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_empty_field_list():
build_config = dotdict({'field1': {'show': True}})
field_list = []
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=False); result = codeflash_output
def test_non_existent_field():
build_config = dotdict({'field1': {'show': True}})
fields = {'non_existent_field': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_field_not_a_dict():
build_config = dotdict({'field1': 'not_a_dict'})
fields = {'field1': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_field_missing_show_key():
build_config = dotdict({'field1': {'other_key': 'value'}})
fields = {'field1': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); 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}': True 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_large_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)]
codeflash_output = set_multiple_field_display(build_config, field_list=field_list, is_visible=True); result = codeflash_output
for i in range(1000):
pass
def test_combination_valid_invalid_fields():
build_config = dotdict({'field1': {'show': False}})
fields = {'field1': True, 'invalid_field': False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_combination_valid_non_existent_fields():
build_config = dotdict({'field1': {'show': False}})
fields = {'field1': True, 'non_existent_field': False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_combination_valid_nested_fields():
build_config = dotdict({'field1': {'show': False}, 'nested': {'field2': {'show': True}}})
fields = {'field1': True, 'nested.field2': False}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result = codeflash_output
def test_deterministic_behavior():
build_config = dotdict({'field1': {'show': False}})
fields = {'field1': True}
codeflash_output = set_multiple_field_display(build_config, fields=fields); result1 = codeflash_output
codeflash_output = set_multiple_field_display(build_config, fields=fields); result2 = codeflash_output
# 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-pr7755-2025-04-23T07.14.50 and push.
⚡️ Codeflash found optimizations for this PR
📄 14% (0.14x) speedup for set_multiple_field_advanced in src/backend/base/langflow/utils/component_utils.py
⏱️ Runtime : 1.20 millisecond → 1.06 millisecond (best of 106 runs)
I created a new dependent PR with the suggested changes. Please review:
-
#7757
If you approve, it will be merged into this PR (branch codeflash/optimize-pr7755-2025-04-23T07.14.50).