feat: add versioned hash to component index by jordanrfrazier · Pull Request #11244 · langflow-ai/langflow (original) (raw)
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/build_component_index.py (1)
41-106: Remove trailing whitespace from blank lines.Multiple blank lines contain trailing whitespace (Ruff W293 at lines 47, 83, 86, 93, 97, 102). Run
ruff formator remove the trailing spaces to resolve these linting issues.
🤖 Fix all issues with AI agents
In @scripts/build_component_index.py:
- Around line 26-31: The logging configuration uses single-quoted strings which
violates the project's quote style (Ruff Q000); update the calls in
logging.basicConfig and the format argument to use double quotes instead of
single quotes (i.e., change format='%(levelname)s: %(message)s' to
format="%(levelname)s: %(message)s") and ensure any other string literals in
this block (level and stream args if present as strings) follow double-quote
style; keep the variable name logger = logging.getLogger(__name__) unchanged.
- Around line 16-23: Sort the names in the packaging import and fix the
exception handling: change the import to "from packaging.version import
InvalidVersion, Version" (alphabetical) and change "except ImportError as e" to
"except ImportError as err", then re-raise the ImportError using the caught
exception (e.g., raise ImportError("The 'packaging' library is required for
version comparison. Install it with: pip install packaging") from err) so Ruff
I001 and EM101/TRY003 are satisfied.
In @src/backend/tests/unit/test_component_index_hash_history.py:
- Around line 304-312: The version string in the test loop is incorrectly built
as f"1.7.0.dev2026010{day:02d}" which yields wrong dates for day >= 10; change
the base literal to "1.7.0.dev202601" so the formatted day (via :02d) produces
an 8-digit YYYYMMDD suffix (e.g., "1.7.0.dev20260110"); update the loop that
calls _merge_hash_history (and any related test expectations if necessary) to
use the corrected f"1.7.0.dev202601{day:02d}" format.
- Around line 275-286: The test test_hash_history_format_in_metadata is a no-op:
it imports build_component_index but never calls it and asserts a local
constant; replace the placeholder with a real assertion by invoking
build_component_index() (or a mocked version) and verifying the returned index
metadata contains "hash_history_format" == "inline_ranges_v1", or if integration
is infeasible, remove the test or mark it as skipped with a comment; to enable a
unit-style check, mock the internal component loader (e.g., _import_components
or whichever helper build_component_index calls) to produce a deterministic
index and assert the metadata field on the result.
🧹 Nitpick comments (4)
src/backend/tests/unit/test_component_index_hash_history.py (2)
711-711: Remove stray comment.This comment appears to be a leftover artifact and should be removed.
Suggested fix
1-18: Good test coverage for hash history management.The test file provides comprehensive coverage for the hash history utilities including:
- New component creation, hash extension, hash changes
- Nightly build version handling
- Old format migration
- Edge cases (empty/missing hash, version regression)
- Normalization and validation
Consider consolidating the repeated imports at the module level to reduce verbosity, though the current approach provides good test isolation.
scripts/build_component_index.py (2)
167-173: Remove redundant import block.The
packaging.version.Versionis already imported at module level (lines 18-23) with fail-fast behavior. This try/except block is now dead code.Suggested fix
- try:
from packaging.version import Version- except ImportError as e:
raise ImportError("The 'packaging' library is required for version comparison. ""Install it with: pip install packaging") from ev1 = Version(version1) v2 = Version(version2)
377-398: Redundant.copy()after slice operation.On line 380,
prev_history[:-1].copy()is redundant—slicing already returns a new list. This is a minor clarity issue.Suggested fix
# Hash unchanged - extend the version range if last_hash == current_hash: # Copy all previous entries except the last one
history = prev_history[:-1].copy() if len(prev_history) > 1 else []
history = prev_history[:-1] if len(prev_history) > 1 else []
📜 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 c728cde and 29e1273.
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock📒 Files selected for processing (3)scripts/build_component_index.pysrc/backend/tests/unit/test_component_index_hash_history.pysrc/lfx/src/lfx/_assets/component_index.json🧰 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 withawaitfor async operations in component execution methods
Useasyncio.create_task()for background tasks and implement proper cleanup with try/except forasyncio.CancelledError
Usequeue.put_nowait()for non-blocking queue operations andasyncio.wait_for()with timeouts for controlled get operations
Files:
src/backend/tests/unit/test_component_index_hash_history.pysrc/backend/**/*component*.py
📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)
In Python component classes, set the
iconattribute to a string matching the desired icon name (e.g.,icon = "AstraDB"). The string must match the frontend icon mapping exactly (case-sensitive).
Files:
src/backend/tests/unit/test_component_index_hash_history.pysrc/backend/tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
src/backend/tests/**/*.py: Place backend unit tests insrc/backend/tests/directory, component tests insrc/backend/tests/unit/components/organized by component subdirectory, and integration tests accessible viamake integration_tests
Use same filename as component with appropriate test prefix/suffix (e.g.,my_component.py→test_my_component.py)
Use theclientfixture (FastAPI Test Client) defined insrc/backend/tests/conftest.pyfor API tests; it provides an asynchttpx.AsyncClientwith automatic in-memory SQLite database and mocked environment variables. Skip client creation by marking test with@pytest.mark.noclient
Inherit from the correctComponentTestBasefamily class located insrc/backend/tests/base.pybased on API access needs:ComponentTestBase(no API),ComponentTestBaseWithClient(needs API), orComponentTestBaseWithoutClient(pure logic). Provide three required fixtures:component_class,default_kwargs, andfile_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.asynciodecorator for async component tests and ensure async methods are properly awaited
Test background tasks usingasyncio.create_task()and verify completion withasyncio.wait_for()with appropriate timeout constraints
Test queue operations using non-blockingqueue.put_nowait()andasyncio.wait_for(queue.get(), timeout=...)to verify queue processing without blocking
Use@pytest.mark.no_blockbustermarker to skip the blockbuster plugin in specific tests
For database tests that may fail in batch runs, run them sequentially usinguv run pytest src/backend/tests/unit/test_database.pyr...
Files:
src/backend/tests/unit/test_component_index_hash_history.py**/test_*.py
📄 CodeRabbit inference engine (Custom checks)
**/test_*.py: Review test files for excessive use of mocks that may indicate poor test design - check if tests have too many mock objects that obscure what's actually being tested
Warn when mocks are used instead of testing real behavior and interactions, and suggest using real objects or test doubles when mocks become excessive
Ensure mocks are used appropriately for external dependencies only, not for core logic
Backend test files should follow the naming convention test_*.py with proper pytest structure
Test files should have descriptive test function names that explain what is being tested
Tests should be organized logically with proper setup and teardown
Consider including edge cases and error conditions for comprehensive test coverage
Verify tests cover both positive and negative scenarios where appropriate
For async functions in backend tests, ensure proper async testing patterns are used with pytest
For API endpoints, verify both success and error response testing
Files:
src/backend/tests/unit/test_component_index_hash_history.py🧠 Learnings (11) 📚 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/test_component_index_hash_history.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 : 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`
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.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 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/test_component_index_hash_history.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 same filename as component with appropriate test prefix/suffix (e.g., `my_component.py` → `test_my_component.py`)
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.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 : 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`
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.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/test_component_index_hash_history.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 component build config updates by calling `to_frontend_node()` to get the node template, then calling `update_build_config()` to apply configuration changes
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.py📚 Learning: 2025-11-24T19:46:09.104Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-11-24T19:46:09.104Z
Learning: Applies to tests/unit/components/**/*.py : Create unit tests in `src/backend/tests/unit/components/` mirroring the component directory structure, using `ComponentTestBaseWithClient` or `ComponentTestBaseWithoutClient` base classes
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.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 `pytest.mark.api_key_required` and `pytest.mark.no_blockbuster` markers for components that need external APIs; use `MockLanguageModel` from `tests.unit.mock_language_model` for testing without external API keys
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.py📚 Learning: 2025-12-19T18:04:08.938Z
Learnt from: Jkavia
Repo: langflow-ai/langflow PR: 11111
File: src/backend/tests/unit/api/v2/test_workflow.py:10-11
Timestamp: 2025-12-19T18:04:08.938Z
Learning: In the langflow-ai/langflow repository, pytest-asyncio is configured with asyncio_mode = 'auto' in pyproject.toml. This means you do not need to decorate test functions or classes with pytest.mark.asyncio; async tests are auto-detected and run by pytest-asyncio. When reviewing tests, ensure they rely on this configuration (i.e., avoid unnecessary pytest.mark.asyncio decorators) and that tests living under any tests/ path (e.g., src/.../tests/**/*.py) follow this convention. If a test explicitly requires a different asyncio policy, document it and adjust the config accordingly.
Applied to files:
src/backend/tests/unit/test_component_index_hash_history.py📚 Learning: 2025-11-24T19:46:09.104Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-11-24T19:46:09.104Z
Learning: Applies to src/backend/base/langflow/components/**/__init__.py : Update `__init__.py` with alphabetically sorted imports when adding new components
Applied to files:
scripts/build_component_index.py🧬 Code graph analysis (1) src/backend/tests/unit/test_component_index_hash_history.py (2)
scripts/build_component_index.py (8)
build_component_index(458-540)_merge_hash_history(305-404)_load_index_from_file(81-106)_find_component_in_index(109-140)_strip_dynamic_fields(64-78)_compare_versions(143-183)_validate_version_range(186-209)_normalize_history_to_range_format(229-302) src/lfx/src/lfx/custom/custom_component/custom_component.py (1)index(507-520)
🪛 GitHub Actions: Ruff Style Check scripts/build_component_index.py
[error] 18-18: I001 Import block is un-sorted or un-formatted.
🪛 GitHub Check: Ruff Style Check (3.13) scripts/build_component_index.py
[failure] 28-28: Ruff (Q000)
scripts/build_component_index.py:28:12: Q000 Single quotes found but double quotes preferred
[failure] 21-22: Ruff (EM101)
scripts/build_component_index.py:21:9: EM101 Exception must not use a string literal, assign to variable first
[failure] 20-23: Ruff (TRY003)
scripts/build_component_index.py:20:11: TRY003 Avoid specifying long messages outside the exception class
[failure] 18-18: Ruff (I001)
scripts/build_component_index.py🔞5: I001 Import block is un-sorted or un-formatted
[failure] 47-47: Ruff (W293)
scripts/build_component_index.py:47:1: W293 Blank line contains whitespace
[failure] 102-102: Ruff (W293)
scripts/build_component_index.py:102:1: W293 Blank line contains whitespace
[failure] 97-97: Ruff (W293)
scripts/build_component_index.py:97:1: W293 Blank line contains whitespace
[failure] 93-93: Ruff (W293)
scripts/build_component_index.py:93:1: W293 Blank line contains whitespace
[failure] 86-86: Ruff (W293)
scripts/build_component_index.py:86:1: W293 Blank line contains whitespace
[failure] 83-83: Ruff (W293)
scripts/build_component_index.py:83:1: W293 Blank line contains whitespace
⏰ 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). (16)
- GitHub Check: Lint Backend / Run Mypy (3.11)
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
- GitHub Check: Lint Backend / Run Mypy (3.13)
- GitHub Check: Lint Backend / Run Mypy (3.10)
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
- GitHub Check: Lint Backend / Run Mypy (3.12)
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
- GitHub Check: Test Docker Images / Test docker images
- GitHub Check: Run Frontend Unit Tests / Frontend Jest Unit Tests
- GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
- GitHub Check: Run Frontend Tests / Determine Test Suites and Shard Distribution
- GitHub Check: Run Backend Tests / LFX Tests - Python 3.10
- GitHub Check: Test Starter Templates
- GitHub Check: Update Component Index 🔇 Additional comments (2)
scripts/build_component_index.py (2)
458-540: Well-structured index building with good defensive practices.The build function implements:
- Defensive copying to prevent mutation side effects (lines 494-495)
- Deterministic ordering via
sorted()for reproducible output- Correct SHA256 computation order (before adding the hash field)
- Proper error handling with informative messages
407-408: The nested path structuresrc/lfx/src/lfx/_assets/component_index.jsonis correct. Thecomponent_index.jsonfile exists at this location in the project, and thePathcalculation fromscripts/build_component_index.pyresolves correctly.