Skip to content

Conversation

@Cristhianzl
Copy link
Member

@Cristhianzl Cristhianzl commented Nov 26, 2025

Summary

  • Fix frozen Loop components running infinitely instead of iterating correctly through their data
  • Add exception in build_vertex and vertex.build() to always execute Loop components even when frozen
  • Loop components must run their build() method to properly iterate through data, regardless of frozen state

Changes

  • src/lfx/src/lfx/graph/graph/base.py: Add check for Loop component before skipping build on frozen vertices
  • src/lfx/src/lfx/graph/vertex/base.py: Add check to prevent returning cached result for frozen Loop components
  • Add comprehensive unit tests covering all frozen/built state combinations

Test plan

  • Added unit tests for is_loop property detection
  • Added tests for build_vertex Loop exception logic
  • Added tests for vertex.build() Loop exception logic
  • Added tests for all frozen/built state combinations
  • Added edge case tests for Loop detection

Summary by CodeRabbit

  • Bug Fixes

    • Loop components now execute and iterate correctly even when frozen, bypassing previous cache behavior.
  • Tests

    • Added comprehensive unit test suite for loop component freeze behavior, including detection, build logic, output validation, and edge case scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds comprehensive unit test coverage for Loop component freeze behavior and modifies the build and evaluate logic to ensure frozen Loop components rebuild rather than using cached results, enabling proper iteration over their data.

Changes

Cohort / File(s) Summary
Test Coverage for Loop Freeze Behavior
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
Introduces unit tests covering Loop component detection via display_name or is_loop flags, frozen vs non-frozen build decisions, output configuration validation, stop_loop evaluation logic, and integration scenarios for frozen Loop behavior across multiple component combinations and edge cases.
Production Logic Updates
src/lfx/src/lfx/graph/graph/base.py, src/lfx/src/lfx/graph/vertex/base.py
Modifies build_vertex and vertex execution to special-case Loop components: frozen Loop components now force rebuild instead of using cache, while frozen non-Loop components retain cache-based behavior. Adds is_loop_component detection via display_name or is_loop flag check.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant BuildVertex as build_vertex()
    participant LoopCheck as is_loop_component<br/>(check)
    participant Cache as Cache Path
    participant Rebuild as Rebuild Path

    Caller->>BuildVertex: Build frozen vertex
    BuildVertex->>LoopCheck: Is vertex a Loop component?
    alt Loop Component
        LoopCheck-->>BuildVertex: Yes (is_loop flag or<br/>display_name="Loop")
        BuildVertex->>Rebuild: Force rebuild
        Rebuild-->>Caller: Return rebuilt result
    else Non-Loop Component
        LoopCheck-->>BuildVertex: No
        BuildVertex->>Cache: Use cached result
        Cache-->>Caller: Return cached result
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus areas for review:
    • Logic in build_vertex() that identifies and special-cases Loop components during freeze checks
    • Logic in vertex base's freeze handler that allows Loop components to bypass early return
    • Comprehensiveness and correctness of the test suite's edge cases (missing keys, unusual names, None/empty string values)
    • Interaction between is_loop_component detection and existing caching mechanisms

Suggested labels

bug, size:L

Suggested reviewers

  • jordanrfrazier
  • edwinjosechittilappilly

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Test Quality And Coverage ⚠️ Warning Test suite has good coverage breadth but contains quality issues: import ordering violations, unused variables, and assertions that don't accurately reflect production behavior. Fix import order, remove unused variables like should_build, revise assertions to accurately reflect None value handling, and use static analysis tools before submission.
Test File Naming And Structure ⚠️ Warning Import ordering violation: third-party pytest imported before standard library unittest.mock, violating PEP 8 conventions. Reorder imports so standard library (from unittest.mock import Mock) precedes third-party (import pytest) per PEP 8 guidelines.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: preventing infinite loops when Loop components are frozen, which aligns with the primary objectives and changes in the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 97.06% which is sufficient. The required threshold is 80.00%.
Test Coverage For New Implementations ✅ Passed PR includes comprehensive test file with 25 test methods and 97 asserts covering Loop component detection, freeze behavior, and edge cases across modified modules.
Excessive Mock Usage Warning ✅ Passed Test file demonstrates appropriate mock usage with 21 Mock objects across 30 test methods (0.70 ratio) using simple direct attribute assignment without complex nesting or sophisticated configurations.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 26, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 26, 2025

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 15%
15.24% (4188/27479) 8.46% (1778/20993) 9.57% (579/6049)

Unit Test Results

Tests Skipped Failures Errors Time
1638 0 💤 0 ❌ 0 🔥 20.835s ⏱️

@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

❌ Patch coverage is 50.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 31.53%. Comparing base (96590e8) to head (bed08ac).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
src/lfx/src/lfx/graph/graph/base.py 50.00% 0 Missing and 1 partial ⚠️
src/lfx/src/lfx/graph/vertex/base.py 50.00% 0 Missing and 1 partial ⚠️

❌ Your project status has failed because the head coverage (40.04%) is below the target coverage (60.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #10736      +/-   ##
==========================================
- Coverage   32.40%   31.53%   -0.88%     
==========================================
  Files        1368     1368              
  Lines       63412    63414       +2     
  Branches     9373     9373              
==========================================
- Hits        20551    19998     -553     
- Misses      41829    42383     +554     
- Partials     1032     1033       +1     
Flag Coverage Δ
backend 47.95% <ø> (-3.36%) ⬇️
frontend 14.08% <ø> (ø)
lfx 40.04% <50.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/lfx/src/lfx/graph/graph/base.py 45.84% <50.00%> (+0.04%) ⬆️
src/lfx/src/lfx/graph/vertex/base.py 56.36% <50.00%> (+0.09%) ⬆️

... and 49 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 26, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2fb7b3 and cfb4a6c.

⛔ Files ignored due to path filters (1)
  • src/frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py (1 hunks)
  • src/lfx/src/lfx/graph/graph/base.py (1 hunks)
  • src/lfx/src/lfx/graph/vertex/base.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/backend/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

src/backend/**/*.py: Use FastAPI async patterns with await for async operations in component execution methods
Use asyncio.create_task() for background tasks and implement proper cleanup with try/except for asyncio.CancelledError
Use queue.put_nowait() for non-blocking queue operations and asyncio.wait_for() with timeouts for controlled get operations

Files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
src/backend/tests/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

src/backend/tests/**/*.py: Place backend unit tests in src/backend/tests/ directory, component tests in src/backend/tests/unit/components/ organized by component subdirectory, and integration tests accessible via make integration_tests
Use same filename as component with appropriate test prefix/suffix (e.g., my_component.pytest_my_component.py)
Use the client fixture (FastAPI Test Client) defined in src/backend/tests/conftest.py for API tests; it provides an async httpx.AsyncClient with automatic in-memory SQLite database and mocked environment variables. Skip client creation by marking test with @pytest.mark.noclient
Inherit from the correct ComponentTestBase family class located in src/backend/tests/base.py based on API access needs: ComponentTestBase (no API), ComponentTestBaseWithClient (needs API), or ComponentTestBaseWithoutClient (pure logic). Provide three required fixtures: component_class, default_kwargs, and file_names_mapping
Create comprehensive unit tests for all new backend components. If unit tests are incomplete, create a corresponding Markdown file documenting manual testing steps and expected outcomes
Test both sync and async code paths, mock external dependencies appropriately, test error handling and edge cases, validate input/output behavior, and test component initialization and configuration
Use @pytest.mark.asyncio decorator for async component tests and ensure async methods are properly awaited
Test background tasks using asyncio.create_task() and verify completion with asyncio.wait_for() with appropriate timeout constraints
Test queue operations using non-blocking queue.put_nowait() and asyncio.wait_for(queue.get(), timeout=...) to verify queue processing without blocking
Use @pytest.mark.no_blockbuster marker to skip the blockbuster plugin in specific tests
For database tests that may fail in batch runs, run them sequentially using uv run pytest src/backend/tests/unit/test_database.py r...

Files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
**/{test_*.py,*.test.ts,*.test.tsx}

📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)

Check that test files follow the project's naming conventions (test_*.py for backend, *.test.ts for frontend)

Files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
**/test_*.py

📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)

**/test_*.py: Backend tests should follow pytest structure with proper test_*.py naming
For async functions, ensure proper async testing patterns are used with pytest for backend

Files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
🧠 Learnings (4)
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test component versioning and backward compatibility using `file_names_mapping` fixture with `VersionComponentMapping` objects mapping component files across Langflow versions

Applied to files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test both sync and async code paths, mock external dependencies appropriately, test error handling and edge cases, validate input/output behavior, and test component initialization and configuration

Applied to files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Create comprehensive unit tests for all new backend components. If unit tests are incomplete, create a corresponding Markdown file documenting manual testing steps and expected outcomes

Applied to files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Use predefined JSON flows and utility functions from `tests.unit.build_utils` (create_flow, build_flow, get_build_events, consume_and_assert_stream) for flow execution testing

Applied to files:

  • src/backend/tests/unit/components/flow_controls/test_loop_freeze.py
🧬 Code graph analysis (2)
src/lfx/src/lfx/graph/graph/base.py (1)
src/lfx/src/lfx/graph/vertex/base.py (1)
  • is_loop (123-127)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py (2)
src/lfx/src/lfx/graph/vertex/base.py (1)
  • is_loop (123-127)
src/lfx/src/lfx/components/flow_controls/loop.py (3)
  • LoopComponent (10-163)
  • item_output (91-112)
  • done_output (123-135)
🪛 GitHub Actions: Ruff Style Check
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py

[error] 10-10: Ruff I001 Import block is un-sorted or un-formatted.

🪛 GitHub Check: Ruff Style Check (3.13)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py

[failure] 466-466: Ruff (F841)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py:466:9: F841 Local variable should_build is assigned to but never used


[failure] 10-11: Ruff (I001)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py:10:1: I001 Import block is un-sorted or un-formatted

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Test Docker Images / Test docker images
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Run Backend Tests / LFX Tests - Python 3.10
  • GitHub Check: Run Frontend Unit Tests / Frontend Jest Unit Tests
  • GitHub Check: Test Starter Templates
🔇 Additional comments (3)
src/lfx/src/lfx/graph/vertex/base.py (1)

738-742: LGTM! Correctly prevents frozen Loop components from using cached results.

The logic correctly identifies Loop components using both display_name == "Loop" and the is_loop property (which checks for allows_loop=True in outputs). This ensures Loop components always execute their build() method to iterate through data correctly.

The detection logic matches the corresponding change in src/lfx/src/lfx/graph/graph/base.py, maintaining consistency across both build paths.

src/lfx/src/lfx/graph/graph/base.py (1)

1522-1525: LGTM! Correctly forces rebuild for frozen Loop components at the graph level.

The logic is consistent with the corresponding change in vertex/base.py. This ensures that at both the graph build decision point and the vertex build execution point, Loop components always rebuild to properly iterate through their data.

src/backend/tests/unit/components/flow_controls/test_loop_freeze.py (1)

1-8: Good test coverage for the Loop freeze fix.

The test module provides comprehensive coverage including:

  • Property detection logic
  • Build decision logic at both graph and vertex levels
  • All combinations of frozen/built/is_loop states
  • Real component output configuration validation
  • Edge cases for unusual inputs

The tests effectively validate the fix for frozen Loop components running infinitely.

Comment on lines 10 to 11
import pytest
from unittest.mock import Mock
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix import order to resolve pipeline failure.

The imports are not sorted correctly. Standard library imports should come before third-party imports.

Apply this diff:

-import pytest
-from unittest.mock import Mock
+from unittest.mock import Mock
+
+import pytest
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import pytest
from unittest.mock import Mock
from unittest.mock import Mock
import pytest
🧰 Tools
🪛 GitHub Actions: Ruff Style Check

[error] 10-10: Ruff I001 Import block is un-sorted or un-formatted.

🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 10-11: Ruff (I001)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py:10:1: I001 Import block is un-sorted or un-formatted

🤖 Prompt for AI Agents
In src/backend/tests/unit/components/flow_controls/test_loop_freeze.py around
lines 10 to 11, the import order is incorrect: standard library imports must
precede third-party imports. Reorder imports so any Python stdlib modules (e.g.,
unittest.mock) come before third-party ones (e.g., pytest); in this case import
Mock from unittest.mock before importing pytest, and ensure imports are sorted
and grouped consistently with project style.

Comment on lines 456 to 471
def test_none_values_handled(self):
"""Test that None values are handled gracefully."""
vertex = Mock()
vertex.display_name = None
vertex.is_loop = None
vertex.frozen = True
vertex.built = True

# Should not crash, should not be detected as loop
is_loop_component = vertex.display_name == "Loop" or vertex.is_loop
should_build = not vertex.frozen or is_loop_component

assert is_loop_component is None # None or None = None
# But in boolean context, None is falsy
should_build_bool = not vertex.frozen or bool(is_loop_component)
assert should_build_bool is False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix unused variable and clarify test intent.

The static analysis correctly flagged that should_build on line 466 is assigned but never used. Additionally, this test may not accurately reflect production behavior since the production code would treat None as falsy in boolean context.

Consider removing the unused variable or asserting on it directly:

     def test_none_values_handled(self):
         """Test that None values are handled gracefully."""
         vertex = Mock()
         vertex.display_name = None
         vertex.is_loop = None
         vertex.frozen = True
         vertex.built = True

         # Should not crash, should not be detected as loop
         is_loop_component = vertex.display_name == "Loop" or vertex.is_loop
-        should_build = not vertex.frozen or is_loop_component
 
         assert is_loop_component is None  # None or None = None
         # But in boolean context, None is falsy
-        should_build_bool = not vertex.frozen or bool(is_loop_component)
-        assert should_build_bool is False
+        should_build = not vertex.frozen or is_loop_component
+        # In production, `not True or None` evaluates to None, which is falsy
+        assert not should_build  # None is falsy, so frozen non-loop won't build
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)

[failure] 466-466: Ruff (F841)
src/backend/tests/unit/components/flow_controls/test_loop_freeze.py:466:9: F841 Local variable should_build is assigned to but never used

🤖 Prompt for AI Agents
In src/backend/tests/unit/components/flow_controls/test_loop_freeze.py around
lines 456-471, the local variable should_build is assigned but never used;
either remove the unused assignment or assert its expected value to reflect real
evaluation (not vertex.frozen evaluates to False so should_build becomes None
because False or None yields None). Update the test to either delete the
should_build line and keep the boolean-context assertion, or replace the unused
assignment with an assertion like assert should_build is None so the variable is
exercised and the test intent is explicit.

Copy link
Collaborator

@erichare erichare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Only question @Cristhianzl is do we need the package-lock.json update? maybe not a big deal?

@github-actions github-actions bot added the lgtm This PR has been approved by a maintainer label Nov 26, 2025
@Cristhianzl
Copy link
Member Author

@erichare not a big deal.
that's ok this one. :)
thank you!

@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 27, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 27, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 27, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 27, 2025
@github-actions github-actions bot removed the bug Something isn't working label Nov 27, 2025
@github-actions github-actions bot added the bug Something isn't working label Nov 27, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 28, 2025
@github-actions github-actions bot added bug Something isn't working and removed bug Something isn't working labels Nov 28, 2025
@Cristhianzl Cristhianzl added this pull request to the merge queue Nov 28, 2025
Merged via the queue into main with commit 271c7ff Nov 28, 2025
88 of 91 checks passed
@Cristhianzl Cristhianzl deleted the cz/fix-freeze-loop branch November 28, 2025 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants