Skip to content

Conversation

@codeflash-ai
Copy link
Contributor

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

⚡️ This pull request contains optimizations for PR #7756

If you approve this dependent PR, these changes will be merged into the original PR branch codeflash/optimize-pr7755-2025-04-23T07.14.50.

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


📄 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)

📝 Explanation and details

To optimize the runtime and memory requirements, here are a few changes we can make.

  • Avoid reassigning build_config inside the loops. Updating the build_config directly will suffice since build_config is mutable and the changes will persist.
  • Instead of making repetitive function calls, perform the logic directly within the set_multiple_field_advanced function to minimize overhead.
  • Avoid unnecessary checks and simplify the conditional paths.

Summary of changes.

  1. The set_field_advanced function now performs the logic directly instead of repeating function calls inside loops.
  2. Both functions now operate directly on build_config without reassigning it in each iteration.
  3. Reduced redundant isinstance and membership tests within loops by moving logic directly within the set_multiple_field_advanced function.

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
from langflow.utils.component_utils import set_multiple_field_advanced


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

# unit tests

# Basic Functionality
def test_single_field_update_via_fields():
    build_config = dotdict({"field1": {}})
    fields = {"field1": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_multiple_field_update_via_fields():
    build_config = dotdict({"field1": {}, "field2": {}})
    fields = {"field1": True, "field2": False}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_single_field_update_via_field_list():
    build_config = dotdict({"field1": {}})
    field_list = ["field1"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

def test_multiple_field_update_via_field_list():
    build_config = dotdict({"field1": {}, "field2": {}})
    field_list = ["field1", "field2"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=False); result = codeflash_output

# Edge Cases
def test_empty_fields_dict():
    build_config = dotdict({"field1": {}})
    fields = {}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_empty_field_list():
    build_config = dotdict({"field1": {}})
    field_list = []
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

def test_non_existent_field_in_fields():
    build_config = dotdict({"field1": {}})
    fields = {"non_existent_field": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_non_existent_field_in_field_list():
    build_config = dotdict({"field1": {}})
    field_list = ["non_existent_field"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

# Large Scale Test Cases
def test_large_fields_dict():
    build_config = dotdict({f"field{i}": {} for i in range(1000)})
    fields = {f"field{i}": True for i in range(1000)}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output
    for i in range(1000):
        pass

def test_large_field_list():
    build_config = dotdict({f"field{i}": {} for i in range(1000)})
    field_list = [f"field{i}" for i in range(1000)]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output
    for i in range(1000):
        pass

# Mixed Scenarios
def test_mixed_valid_and_invalid_fields():
    build_config = dotdict({"field1": {}, "invalid_field": {}})
    fields = {"field1": True, "invalid_field": "not_a_boolean"}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_mixed_existing_and_non_existent_fields():
    build_config = dotdict({"field1": {}})
    field_list = ["field1", "non_existent_field"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

# Nested dotdict Structures
def test_nested_dotdict_multiple_field_updates():
    build_config = dotdict({"nested": {"field1": {}, "field2": {}}})
    fields = {"nested.field1": True, "nested.field2": False}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

# Default Parameters
def test_default_is_advanced_parameter():
    build_config = dotdict({"field1": {}})
    fields = {"field1": None}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_default_is_advanced_with_field_list():
    build_config = dotdict({"field1": {}})
    field_list = ["field1"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list); 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.schema.dotdict import dotdict
from langflow.utils.component_utils import set_multiple_field_advanced


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

# unit tests

def test_single_field_update_with_fields_dict():
    build_config = dotdict({"field1": {}})
    fields = {"field1": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_multiple_fields_update_with_fields_dict():
    build_config = dotdict({"field1": {}, "field2": {}})
    fields = {"field1": True, "field2": False}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_single_field_update_with_field_list():
    build_config = dotdict({"field1": {}})
    field_list = ["field1"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

def test_multiple_fields_update_with_field_list():
    build_config = dotdict({"field1": {}, "field2": {}})
    field_list = ["field1", "field2"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=False); result = codeflash_output

def test_both_fields_and_field_list_provided():
    build_config = dotdict({"field1": {}, "field2": {}, "field3": {}})
    fields = {"field1": True}
    field_list = ["field2"]
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields, field_list=field_list, is_advanced=False); result = codeflash_output

def test_neither_fields_nor_field_list_provided():
    build_config = dotdict({"field1": {}})
    codeflash_output = set_multiple_field_advanced(build_config); result = codeflash_output

def test_empty_fields_dict():
    build_config = dotdict({"field1": {}})
    fields = {}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_empty_field_list():
    build_config = dotdict({"field1": {}})
    field_list = []
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

def test_non_existent_field_in_fields():
    build_config = dotdict({"field1": {}})
    fields = {"non_existent_field": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_non_existent_field_in_field_list():
    build_config = dotdict({"field1": {}})
    field_list = ["non_existent_field"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output

def test_nested_field_in_fields():
    build_config = dotdict({"nested_field": {"inner_field": {}}})
    fields = {"nested_field": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_nested_field_in_field_list():
    build_config = dotdict({"nested_field": {"inner_field": {}}})
    field_list = ["nested_field"]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=False); result = codeflash_output

def test_large_fields_dict():
    build_config = dotdict({f"field{i}": {} for i in range(1000)})
    fields = {f"field{i}": i % 2 == 0 for i in range(1000)}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output
    for i in range(1000):
        pass

def test_large_field_list():
    build_config = dotdict({f"field{i}": {} for i in range(1000)})
    field_list = [f"field{i}" for i in range(1000)]
    codeflash_output = set_multiple_field_advanced(build_config, field_list=field_list, is_advanced=True); result = codeflash_output
    for i in range(1000):
        pass




def test_deeply_nested_fields():
    build_config = dotdict({"level1": {"level2": {"level3": {"field": {}}}}})
    fields = {"level1.level2.level3.field": True}
    codeflash_output = set_multiple_field_advanced(build_config, fields=fields); result = codeflash_output

def test_stress_test_with_max_input_size():
    build_config = dotdict({f"field{i}": {} for i in range(1000)})
    fields = {f"field{i}": i % 2 == 0 for i in range(1000)}
    codeflash_output = set_multiple_field_advanced(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-pr7756-2025-04-23T07.37.53 and push.

Codeflash

…(`codeflash/optimize-pr7755-2025-04-23T07.14.50`)

To optimize the runtime and memory requirements, here are a few changes we can make.
- Avoid reassigning `build_config` inside the loops. Updating the `build_config` directly will suffice since `build_config` is mutable and the changes will persist.
- Instead of making repetitive function calls, perform the logic directly within the `set_multiple_field_advanced` function to minimize overhead.
- Avoid unnecessary checks and simplify the conditional paths.



### Summary of changes.
1. The `set_field_advanced` function now performs the logic directly instead of repeating function calls inside loops.
2. Both functions now operate directly on `build_config` without reassigning it in each iteration.
3. Reduced redundant `isinstance` and membership tests within loops by moving logic directly within the `set_multiple_field_advanced` function.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Apr 23, 2025
@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Apr 23, 2025
@dosubot dosubot bot added the enhancement New feature or request label Apr 23, 2025
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 enhancement New feature or request size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant