feat: add static dependency analysis module and update metadata handling (#9192)

* feat: add dependency analysis utilities for custom components

- Introduced `dependency_analyzer.py` to analyze and classify dependencies in Python code.
- Implemented functions to extract import information and categorize dependencies as standard library, local, or external.
- Enhanced `build_component_metadata` to include dependency analysis results in component metadata.
- Added unit tests to validate the functionality of the dependency analysis features.

* refactor: streamline dependency analysis by filtering out stdlib and local imports

- Updated `dependency_analyzer.py` to focus on external dependencies only, removing standard library and local imports from analysis results.
- Simplified the `DependencyInfo` class by eliminating unnecessary attributes and adjusting the deduplication logic.
- Modified `build_component_metadata` to reflect changes in dependency structure, removing counts for stdlib and local dependencies.
- Enhanced unit tests to validate the new filtering behavior and ensure no duplicates in external dependencies.

* feat: update starter project metadata with dependency information

- Added dependency sections to multiple starter project JSON files, specifying required packages and their versions.
- Included `langflow` version `1.5.0.post1` and other relevant dependencies such as `orjson`, `fastapi`, and `pydantic` across various projects.
- Enhanced project metadata to improve clarity on external dependencies for better maintainability and user guidance.

* ️ Speed up function `_classify_dependency` by 7,582% in PR #9192 (`add-deps-metadata`) (#9193)

Co-authored-by: codeflash-ai[bot] <148906541+codeflash-ai[bot]@users.noreply.github.com>

* fix: ensure distribution version is returned correctly in `_get_distribution_version`

- Updated `_get_distribution_version` function to return the distribution version after successfully retrieving it, addressing a potential issue where `None` could be returned prematurely.

* fix: improve distribution version lookup in `_get_distribution_version`

* fix: handle distribution version lookup exceptions more gracefully

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* fix(apply_tweaks): skip tweaks to code field and log warning (#9467)

* fix: add security warning for overriding code field in tweaks

* test: add tests for preventing code field overrides in tweaks

* ref: Refactor vectorstore components structure (#9486)

* Refactor vectorstore components structure

Moved vectorstore components for Chroma, ClickHouse, Couchbase, DataStax, Elastic, Milvus, MongoDB, Pinecone, Qdrant, Supabase, Upstash, Vectara, and Weaviate into dedicated subfolders with __init__.py files for each. Updated Redis vectorstore implementation to reside in redis.py and removed the old vectorstores/redis.py. Adjusted starter project JSONs and frontend constants to reflect new module paths and sidebar entries for these vectorstores.

* Refactor vectorstore components and add lazy imports

Moved Datastax-related files from vectorstores to a dedicated datastax directory. Added lazy import logic to __init__.py files for chroma, clickhouse, couchbase, elastic, milvus, mongodb, pinecone, qdrant, supabase, upstash, vectara, and weaviate components. Cleaned up vectorstores/__init__.py to only include local and faiss components, improving modularity and import efficiency.

* [autofix.ci] apply automated fixes

* Refactor vectorstore components structure

Moved FAISS, Cassandra, and pgvector components to dedicated subdirectories with lazy-loading __init__.py files. Updated imports and references throughout the backend and frontend to reflect new locations. Removed obsolete datastax Cassandra component. Added new sidebar bundle entries for FAISS, Cassandra, and pgvector in frontend constants and style utilities.

* Add lazy imports and Redis chat memory component

Refactored the Redis module to support lazy imports for RedisIndexChatMemory and RedisVectorStoreComponent, improving import efficiency. Added a new redis_chat.py file implementing RedisIndexChatMemory for chat message storage and retrieval using Redis.

* Fix vector store astra imports

* Revert package lock changes

* More test fixes

* Update test_vector_store_rag.py

* Update test_dynamic_imports.py

* Update vector_store_rag.py

* Update test_dynamic_imports.py

* Refactor the cassandra chat component

* Fix frontend tests for bundle

* Mark Local DB as legacy

* Update inputComponent.spec.ts

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Hare <ericrhare@gmail.com>
Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>

* feat: add dependencies metadata to starter projects

* feat: add caching for packages_distributions to improve performance

* refactor: update test descriptions and remove unused imports in metadata tests

---------

Co-authored-by: codeflash-ai[bot] <148906541+codeflash-ai[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: Eric Hare <ericrhare@gmail.com>
Co-authored-by: Carlos Coelho <80289056+carlosrcoelho@users.noreply.github.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2025-08-25 20:32:44 -03:00 committed by GitHub
commit 933198d8be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 2311 additions and 23 deletions

View file

@ -0,0 +1,165 @@
"""Dependency analysis utilities for custom components."""
from __future__ import annotations
import ast
import importlib.metadata as md
import sys
from dataclasses import asdict, dataclass
from functools import lru_cache
try:
STDLIB_MODULES: set[str] = set(sys.stdlib_module_names) # 3.10+
except AttributeError:
# Fallback heuristic if running on <3.10
STDLIB_MODULES = set(sys.builtin_module_names)
@dataclass(frozen=True)
class DependencyInfo:
"""Information about a dependency imported in Python code."""
name: str # package name (e.g. "numpy", "requests")
version: str | None # package version if available
is_local: bool # True for relative imports (from .module import ...)
def _top_level(pkg: str) -> str:
"""Extract top-level package name."""
return pkg.split(".", 1)[0]
def _is_relative(module: str | None) -> bool:
"""Check if module is a relative import."""
return module is not None and module.startswith(".")
class _ImportVisitor(ast.NodeVisitor):
"""AST visitor to extract import information."""
def __init__(self):
self.results: list[DependencyInfo] = []
def visit_Import(self, node: ast.Import):
for alias in node.names:
full = alias.name
dep = DependencyInfo(
name=_top_level(full),
version=None,
is_local=False, # Regular imports are not local
)
self.results.append(dep)
def visit_ImportFrom(self, node: ast.ImportFrom):
# Reconstruct full module name with proper relative import handling
if node.level > 0:
# Relative import: from .module import x or from ..parent import x
dots = "." * node.level
full_module = dots + (node.module or "")
else:
# Absolute import: from module import x
full_module = node.module or ""
for _alias in node.names:
dep = DependencyInfo(
name=_top_level(full_module.lstrip(".")) if full_module else "",
version=None,
is_local=_is_relative(full_module), # Check if it's a relative import
)
self.results.append(dep)
def _classify_dependency(dep: DependencyInfo) -> DependencyInfo:
"""Resolve version information for external dependencies."""
version = None
if not dep.is_local and dep.name:
version = _get_distribution_version(dep.name)
return DependencyInfo(
name=dep.name,
version=version,
is_local=dep.is_local,
)
def analyze_dependencies(source: str, *, resolve_versions: bool = True) -> list[dict]:
"""Return a list[dict] of dependencies imported by the given Python source code.
Args:
source: Python source code string
resolve_versions: Whether to resolve version information
Returns:
List of dependency dictionaries
"""
code = source
# Parse the code and extract imports
tree = ast.parse(code)
visitor = _ImportVisitor()
visitor.visit(tree)
# Process and deduplicate dependencies by package name only
unique_packages: dict[str, DependencyInfo] = {}
for raw_dep in visitor.results:
processed_dep = _classify_dependency(raw_dep) if resolve_versions else raw_dep
# Skip stdlib imports and local imports - we only care about external dependencies
if processed_dep.name in STDLIB_MODULES or processed_dep.is_local:
continue
# Deduplicate by package name only (not full_module)
if processed_dep.name not in unique_packages:
unique_packages[processed_dep.name] = processed_dep
return [asdict(d) for d in unique_packages.values()]
def analyze_component_dependencies(component_code: str) -> dict:
"""Analyze dependencies for a custom component.
Args:
component_code: The component's source code
Returns:
Dictionary with dependency analysis results
"""
try:
deps = analyze_dependencies(component_code, resolve_versions=True)
return {
"total_dependencies": len(deps),
"dependencies": [{"name": d["name"], "version": d["version"]} for d in deps if d["name"]],
}
except (SyntaxError, TypeError, ValueError, ImportError):
# If analysis fails, return minimal info
return {
"total_dependencies": 0,
"dependencies": [],
}
# Cache the expensive packages_distributions() call globally
@lru_cache(maxsize=1)
def _get_packages_distributions():
"""Cache the expensive packages_distributions() call."""
try:
return md.packages_distributions()
except (OSError, AttributeError, ValueError):
return {}
# Helper function to cache version lookups for installed distributions
@lru_cache(maxsize=128)
def _get_distribution_version(import_name: str):
try:
# Reverse-lookup: which distribution(s) provide this importable name?
reverse_map = _get_packages_distributions()
dist_names = reverse_map.get(import_name)
if not dist_names:
return None
# Take the first matching distribution
dist_name = dist_names[0]
return md.distribution(dist_name).version
except (ImportError, AttributeError, OSError, ValueError):
return None

View file

@ -1,4 +1,6 @@
# mypy: ignore-errors
from __future__ import annotations
import ast
import asyncio
import contextlib
@ -7,14 +9,13 @@ import inspect
import re
import traceback
from pathlib import Path
from typing import Any
from uuid import UUID
from typing import TYPE_CHECKING, Any
from fastapi import HTTPException
from pydantic import BaseModel
from langflow.custom.custom_component.component import Component
from langflow.custom.custom_component.custom_component import CustomComponent
from langflow.custom.dependency_analyzer import analyze_component_dependencies
from langflow.custom.directory_reader.utils import (
abuild_custom_component_list_from_path,
build_custom_component_list_from_path,
@ -32,6 +33,11 @@ from langflow.type_extraction.type_extraction import extract_inner_type
from langflow.utils import validate
from langflow.utils.util import get_base_classes
if TYPE_CHECKING:
from uuid import UUID
from langflow.custom.custom_component.custom_component import CustomComponent
def _generate_code_hash(source_code: str, modname: str) -> str:
"""Generate a hash of the component source code.
@ -488,6 +494,15 @@ def build_custom_component_template_from_inputs(
# ! This should be removed when we have a better way to handle this
frontend_node.set_base_classes_from_outputs()
reorder_fields(frontend_node, cc_instance._get_field_order())
frontend_node = build_component_metadata(frontend_node, cc_instance, module_name, ctype_name)
return frontend_node.to_dict(keep_name=False), cc_instance
def build_component_metadata(
frontend_node: CustomComponentFrontendNode, custom_component: CustomComponent, module_name: str, ctype_name: str
):
"""Build the metadata for a custom component."""
if module_name:
frontend_node.metadata["module"] = module_name
else:
@ -502,7 +517,19 @@ def build_custom_component_template_from_inputs(
except Exception as exc: # noqa: BLE001
logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc)
return frontend_node.to_dict(keep_name=False), cc_instance
# Analyze component dependencies
try:
dependency_info = analyze_component_dependencies(custom_component._code)
frontend_node.metadata["dependencies"] = dependency_info
except (SyntaxError, TypeError, ValueError, ImportError) as exc:
logger.warning(f"Failed to analyze dependencies for component {ctype_name}: {exc}")
# Set minimal dependency info on failure
frontend_node.metadata["dependencies"] = {
"total_dependencies": 0,
"dependencies": [],
}
return frontend_node
def build_custom_component_template(
@ -562,18 +589,9 @@ def build_custom_component_template(
reorder_fields(frontend_node, custom_instance._get_field_order())
if module_name:
frontend_node.metadata["module"] = module_name
else:
module_name = get_module_name_from_display_name(frontend_node.display_name)
frontend_node.metadata["module"] = f"custom_components.{module_name}"
# Generate code hash for cache invalidation and debugging
try:
code_hash = _generate_code_hash(custom_component._code, module_name)
if code_hash:
frontend_node.metadata["code_hash"] = code_hash
except Exception as exc: # noqa: BLE001
logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc)
frontend_node = build_component_metadata(
frontend_node, custom_component, module_name, custom_component.__class__.__name__
)
return frontend_node.to_dict(keep_name=False), custom_instance
except Exception as exc:

View file

@ -363,6 +363,15 @@
"lf_version": "1.5.0",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -664,6 +673,23 @@
"lf_version": "1.5.0",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],

View file

@ -118,6 +118,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -616,6 +625,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],

View file

@ -353,6 +353,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -469,6 +478,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -792,6 +818,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "556209520650",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.processing.parser.ParserComponent"
},
"minimized": false,
@ -979,6 +1014,27 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "252132357639",
"dependencies": {
"dependencies": [
{
"name": "requests",
"version": "2.32.4"
},
{
"name": "bs4",
"version": "4.12.3"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.data.url.URLComponent"
},
"minimized": false,

View file

@ -238,6 +238,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "464cc8b8fdd2",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.memory.MemoryComponent"
},
"output_types": [],
@ -1926,6 +1935,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -2243,6 +2261,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -148,6 +148,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -443,6 +452,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],

View file

@ -151,6 +151,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -466,6 +483,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -1294,6 +1320,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "ad2a6f4552c0",
"dependencies": {
"dependencies": [
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "trustcall",
"version": "0.0.39"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.structured_output.StructuredOutputComponent"
},
"minimized": false,

View file

@ -206,6 +206,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -516,6 +525,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "556209520650",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.processing.parser.ParserComponent"
},
"minimized": false,
@ -698,6 +716,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1003,6 +1038,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "556209520650",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.processing.parser.ParserComponent"
},
"minimized": false,
@ -1199,6 +1243,27 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "23fbe9daca09",
"dependencies": {
"dependencies": [
{
"name": "astrapy",
"version": "2.0.1"
},
{
"name": "langchain_astradb",
"version": "0.6.0"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent"
},
"minimized": false,
@ -2583,6 +2648,23 @@
"legacy": false,
"metadata": {
"code_hash": "ad2a6f4552c0",
"dependencies": {
"dependencies": [
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "trustcall",
"version": "0.0.39"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.structured_output.StructuredOutputComponent"
},
"minimized": false,

View file

@ -235,6 +235,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -543,6 +552,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -1010,6 +1036,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "ad2a6f4552c0",
"dependencies": {
"dependencies": [
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "trustcall",
"version": "0.0.39"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.structured_output.StructuredOutputComponent"
},
"minimized": false,

View file

@ -318,6 +318,15 @@
"lf_version": "1.1.1",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -790,6 +799,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -1065,6 +1083,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -1588,6 +1623,19 @@
"legacy": false,
"metadata": {
"code_hash": "4c76fb76d395",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.tavily.tavily_search.TavilySearchComponent"
},
"minimized": false,

View file

@ -306,6 +306,23 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -670,6 +687,19 @@
"legacy": false,
"metadata": {
"code_hash": "57d868cb067b",
"dependencies": {
"dependencies": [
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.needle.needle.NeedleComponent"
},
"minimized": false,
@ -878,6 +908,15 @@
"legacy": false,
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,

View file

@ -89,6 +89,19 @@
"lf_version": "1.5.0.post1",
"metadata": {
"code_hash": "dbf2e9d2319d",
"dependencies": {
"dependencies": [
{
"name": "langchain_text_splitters",
"version": "0.3.8"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.processing.split_text.SplitTextComponent"
},
"minimized": false,
@ -340,6 +353,27 @@
"lf_version": "1.5.0.post1",
"metadata": {
"code_hash": "252132357639",
"dependencies": {
"dependencies": [
{
"name": "requests",
"version": "2.32.4"
},
{
"name": "bs4",
"version": "4.12.3"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.data.url.URLComponent"
},
"minimized": false,
@ -703,6 +737,43 @@
"legacy": false,
"metadata": {
"code_hash": "6c62063f2c09",
"dependencies": {
"dependencies": [
{
"name": "pandas",
"version": "2.2.3"
},
{
"name": "cryptography",
"version": "43.0.3"
},
{
"name": "langchain_chroma",
"version": "0.1.4"
},
{
"name": "loguru",
"version": "0.7.3"
},
{
"name": "langflow",
"version": null
},
{
"name": "langchain_openai",
"version": "0.3.23"
},
{
"name": "langchain_huggingface",
"version": "0.3.1"
},
{
"name": "langchain_cohere",
"version": "0.3.3"
}
],
"total_dependencies": 8
},
"module": "langflow.components.data.kb_ingest.KBIngestionComponent"
},
"minimized": false,

View file

@ -109,6 +109,15 @@
"lf_version": "1.5.0.post1",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"minimized": false,
@ -226,6 +235,23 @@
"lf_version": "1.5.0.post1",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -533,6 +559,43 @@
"legacy": false,
"metadata": {
"code_hash": "6fcf86be1aca",
"dependencies": {
"dependencies": [
{
"name": "cryptography",
"version": "43.0.3"
},
{
"name": "langchain_chroma",
"version": "0.1.4"
},
{
"name": "loguru",
"version": "0.7.3"
},
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "langflow",
"version": null
},
{
"name": "langchain_openai",
"version": "0.3.23"
},
{
"name": "langchain_huggingface",
"version": "0.3.1"
},
{
"name": "langchain_cohere",
"version": "0.3.3"
}
],
"total_dependencies": 8
},
"module": "langflow.components.data.kb_retrieval.KBRetrievalComponent"
},
"minimized": false,

View file

@ -197,6 +197,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -498,6 +507,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -840,6 +866,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "ad2a6f4552c0",
"dependencies": {
"dependencies": [
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "trustcall",
"version": "0.0.39"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.structured_output.StructuredOutputComponent"
},
"minimized": false,
@ -1191,6 +1234,19 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "4c76fb76d395",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.tavily.tavily_search.TavilySearchComponent"
},
"minimized": false,

View file

@ -315,6 +315,19 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "3e67a5940263",
"dependencies": {
"dependencies": [
{
"name": "assemblyai",
"version": "0.35.1"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.assemblyai.assemblyai_poll_transcript.AssemblyAITranscriptionJobPoller"
},
"minimized": false,
@ -627,6 +640,23 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -932,6 +962,23 @@
"lf_version": "1.1.1",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1237,6 +1284,23 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1719,6 +1783,15 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "464cc8b8fdd2",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.memory.MemoryComponent"
},
"minimized": false,
@ -2049,6 +2122,15 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -2467,6 +2549,19 @@
"legacy": false,
"metadata": {
"code_hash": "03d20eaf49f4",
"dependencies": {
"dependencies": [
{
"name": "assemblyai",
"version": "0.35.1"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.assemblyai.assemblyai_start_transcript.AssemblyAITranscriptionJobCreator"
},
"minimized": false,

View file

@ -149,6 +149,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -458,6 +467,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -960,6 +986,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "464cc8b8fdd2",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.memory.MemoryComponent"
},
"minimized": false,

View file

@ -206,6 +206,19 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "ab828f4cdff2",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.agentql.agentql_api.AgentQL"
},
"minimized": false,
@ -562,6 +575,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -904,6 +926,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1209,6 +1248,27 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "1bcc6faaaa62",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "pandas",
"version": "2.2.3"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.processing.save_file.SaveToFileComponent"
},
"minimized": false,

View file

@ -233,6 +233,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -549,6 +558,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1890,6 +1916,19 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "93faf11517da",
"dependencies": {
"dependencies": [
{
"name": "langchain_openai",
"version": "0.3.23"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.models.embedding_model.EmbeddingModelComponent"
},
"minimized": false,
@ -2183,6 +2222,19 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "ed38680af3a6",
"dependencies": {
"dependencies": [
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.FAISS.faiss.FaissVectorStoreComponent"
},
"minimized": false,
@ -2519,6 +2571,19 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "bd0c4250c82c",
"dependencies": {
"dependencies": [
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.agents.mcp_component.MCPToolsComponent"
},
"minimized": false,

View file

@ -113,6 +113,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -430,6 +439,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -832,6 +858,27 @@
"legacy": false,
"metadata": {
"code_hash": "a648ad26f226",
"dependencies": {
"dependencies": [
{
"name": "aiofiles",
"version": "24.1.0"
},
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "validators",
"version": "0.34.0"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.data.api_request.APIRequestComponent"
},
"minimized": false,

View file

@ -193,6 +193,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"minimized": false,
@ -312,6 +321,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -767,6 +793,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "ad2a6f4552c0",
"dependencies": {
"dependencies": [
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "trustcall",
"version": "0.0.39"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.structured_output.StructuredOutputComponent"
},
"minimized": false,

View file

@ -138,6 +138,15 @@
"lf_version": "1.3.2",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -454,6 +463,23 @@
"lf_version": "1.3.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -768,6 +794,19 @@
"lf_version": "1.3.2",
"metadata": {
"code_hash": "4c76fb76d395",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.tavily.tavily_search.TavilySearchComponent"
},
"minimized": false,
@ -1169,6 +1208,19 @@
"lf_version": "1.3.2",
"metadata": {
"code_hash": "ab828f4cdff2",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.agentql.agentql_api.AgentQL"
},
"minimized": false,

View file

@ -478,6 +478,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -1259,6 +1268,19 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "4c76fb76d395",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.tavily.tavily_search.TavilySearchComponent"
},
"minimized": false,
@ -1660,6 +1682,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -229,6 +229,19 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "b61405ff011f",
"dependencies": {
"dependencies": [
{
"name": "defusedxml",
"version": "0.7.1"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.arxiv.arxiv.ArXivComponent"
},
"minimized": false,
@ -390,6 +403,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -701,6 +731,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -1038,6 +1077,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "556209520650",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.processing.parser.ParserComponent"
},
"minimized": false,
@ -1213,6 +1261,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "5b234f78c942",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.logic.loop.LoopComponent"
},
"minimized": false,
@ -1626,6 +1683,15 @@
"legacy": false,
"metadata": {
"code_hash": "38e56a852063",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.processing.converter.TypeConverterComponent"
},
"minimized": false,

View file

@ -563,6 +563,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],

View file

@ -371,6 +371,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -716,6 +733,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "3139fe9e04a5",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.calculator_core.CalculatorComponent"
},
"minimized": false,

View file

@ -104,6 +104,19 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "99b8b89dc4ca",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
},
{
"name": "scrapegraph_py",
"version": "1.12.0"
}
],
"total_dependencies": 2
},
"module": "langflow.components.scrapegraph.scrapegraph_search_api.ScrapeGraphSearchApi"
},
"minimized": false,
@ -278,6 +291,15 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -592,6 +614,23 @@
"lf_version": "1.1.5",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -1911,6 +1911,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -2801,6 +2810,27 @@
"legacy": false,
"metadata": {
"code_hash": "6e61ed5ad81b",
"dependencies": {
"dependencies": [
{
"name": "yfinance",
"version": "0.2.50"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.yahoosearch.yahoo.YfinanceComponent"
},
"minimized": false,
@ -3015,6 +3045,15 @@
"legacy": false,
"metadata": {
"code_hash": "3139fe9e04a5",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.calculator_core.CalculatorComponent"
},
"minimized": false,
@ -3172,6 +3211,19 @@
"legacy": false,
"metadata": {
"code_hash": "4c76fb76d395",
"dependencies": {
"dependencies": [
{
"name": "httpx",
"version": "0.27.2"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.tavily.tavily_search.TavilySearchComponent"
},
"minimized": false,
@ -3572,6 +3624,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -192,6 +192,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "3139fe9e04a5",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.calculator_core.CalculatorComponent"
},
"minimized": false,
@ -350,6 +359,15 @@
"legacy": false,
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -668,6 +686,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1526,6 +1561,27 @@
"legacy": false,
"metadata": {
"code_hash": "252132357639",
"dependencies": {
"dependencies": [
{
"name": "requests",
"version": "2.32.4"
},
{
"name": "bs4",
"version": "4.12.3"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.data.url.URLComponent"
},
"minimized": false,

View file

@ -145,6 +145,31 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "233d7ef687d5",
"dependencies": {
"dependencies": [
{
"name": "apify_client",
"version": "1.11.0"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 5
},
"module": "langflow.components.apify.apify_actor.ApifyActorsComponent"
},
"minimized": false,
@ -351,6 +376,31 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "233d7ef687d5",
"dependencies": {
"dependencies": [
{
"name": "apify_client",
"version": "1.11.0"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "pydantic",
"version": "2.10.6"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 5
},
"module": "langflow.components.apify.apify_actor.ApifyActorsComponent"
},
"minimized": false,
@ -644,6 +694,15 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -959,6 +1018,23 @@
"lf_version": "1.4.2",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -714,6 +714,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1025,6 +1042,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,

View file

@ -229,6 +229,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -530,6 +539,23 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -1277,6 +1303,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "3139fe9e04a5",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.helpers.calculator_core.CalculatorComponent"
},
"minimized": false,
@ -1435,6 +1470,19 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "c561e416205b",
"dependencies": {
"dependencies": [
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.searchapi.search.SearchComponent"
},
"minimized": false,

View file

@ -284,6 +284,15 @@
"legacy": false,
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,
@ -596,6 +605,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -714,6 +732,23 @@
"legacy": false,
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1023,6 +1058,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -1131,6 +1175,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -1239,6 +1292,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -1347,6 +1409,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],
@ -1455,6 +1526,15 @@
"lf_version": "1.0.19.post2",
"metadata": {
"code_hash": "efdcba3771af",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.text.TextInputComponent"
},
"output_types": [],

View file

@ -321,6 +321,15 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"output_types": [],
@ -795,6 +804,19 @@
"lf_version": "1.1.1",
"metadata": {
"code_hash": "dbf2e9d2319d",
"dependencies": {
"dependencies": [
{
"name": "langchain_text_splitters",
"version": "0.3.8"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.processing.split_text.SplitTextComponent"
},
"output_types": [],
@ -1084,6 +1106,23 @@
"lf_version": "1.1.1",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"output_types": [],
@ -1401,6 +1440,19 @@
"lf_version": "1.2.0",
"metadata": {
"code_hash": "2691dee277c9",
"dependencies": {
"dependencies": [
{
"name": "langchain_openai",
"version": "0.3.23"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.openai.openai.OpenAIEmbeddingsComponent"
},
"output_types": [],
@ -1937,6 +1989,19 @@
"lf_version": "1.1.1",
"metadata": {
"code_hash": "2691dee277c9",
"dependencies": {
"dependencies": [
{
"name": "langchain_openai",
"version": "0.3.23"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 2
},
"module": "langflow.components.openai.openai.OpenAIEmbeddingsComponent"
},
"output_types": [],
@ -2710,6 +2775,27 @@
"legacy": false,
"metadata": {
"code_hash": "23fbe9daca09",
"dependencies": {
"dependencies": [
{
"name": "astrapy",
"version": "2.0.1"
},
{
"name": "langchain_astradb",
"version": "0.6.0"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent"
},
"minimized": false,
@ -3486,6 +3572,27 @@
"legacy": false,
"metadata": {
"code_hash": "23fbe9daca09",
"dependencies": {
"dependencies": [
{
"name": "astrapy",
"version": "2.0.1"
},
{
"name": "langchain_astradb",
"version": "0.6.0"
},
{
"name": "langchain_core",
"version": "0.3.72"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent"
},
"minimized": false,

View file

@ -286,6 +286,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "ee50d5005321",
"dependencies": {
"dependencies": [
{
"name": "toml",
"version": "0.10.2"
},
{
"name": "langflow",
"version": null
},
{
"name": "langchain_core",
"version": "0.3.72"
}
],
"total_dependencies": 3
},
"module": "langflow.components.processing.batch_run.BatchRunComponent"
},
"minimized": false,
@ -504,6 +521,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "aeda2975f4aa",
"dependencies": {
"dependencies": [
{
"name": "pandas",
"version": "2.2.3"
},
{
"name": "googleapiclient",
"version": "2.154.0"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.youtube.comments.YouTubeCommentsComponent"
},
"minimized": false,
@ -1440,6 +1474,23 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "6f74e04e39d5",
"dependencies": {
"dependencies": [
{
"name": "orjson",
"version": "3.10.15"
},
{
"name": "fastapi",
"version": "0.115.13"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 3
},
"module": "langflow.components.input_output.chat_output.ChatOutput"
},
"minimized": true,
@ -1751,6 +1802,27 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "c9f0262ff0b6",
"dependencies": {
"dependencies": [
{
"name": "pandas",
"version": "2.2.3"
},
{
"name": "youtube_transcript_api",
"version": "0.6.3"
},
{
"name": "langchain_community",
"version": "0.3.21"
},
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 4
},
"module": "langflow.components.youtube.youtube_transcripts.YouTubeTranscriptsComponent"
},
"minimized": false,
@ -2501,6 +2573,15 @@
"lf_version": "1.4.3",
"metadata": {
"code_hash": "192913db3453",
"dependencies": {
"dependencies": [
{
"name": "langflow",
"version": null
}
],
"total_dependencies": 1
},
"module": "langflow.components.input_output.chat.ChatInput"
},
"minimized": true,

View file

@ -3,7 +3,11 @@
from unittest.mock import Mock, patch
import pytest
from langflow.custom.utils import _generate_code_hash
from langflow.custom.utils import (
_generate_code_hash,
build_component_metadata,
build_custom_component_template_from_inputs,
)
class TestCodeHashGeneration:
@ -141,21 +145,373 @@ class TestMetadataInTemplateBuilders:
assert len(result) == 12
assert all(c in "0123456789abcdef" for c in result)
@patch("langflow.custom.utils.ComponentFrontendNode")
def test_build_from_inputs_without_module_generates_default(self, mock_frontend_class):
"""Test that build_custom_component_template_from_inputs generates default module when module_name is None."""
class TestDependencyAnalyzer:
"""Test dependency analysis functionality."""
def test_top_level_basic(self):
"""Test extracting top level package name."""
from langflow.custom.dependency_analyzer import _top_level
assert _top_level("numpy") == "numpy"
assert _top_level("numpy.array") == "numpy"
assert _top_level("requests.adapters.HTTPAdapter") == "requests"
def test_is_relative(self):
"""Test relative import detection."""
from langflow.custom.dependency_analyzer import _is_relative
assert _is_relative(".module") is True
assert _is_relative("..parent") is True
assert _is_relative("...grandparent") is True
assert _is_relative("module") is False
assert _is_relative(None) is False
def test_analyze_dependencies_basic(self):
"""Test basic dependency analysis."""
from langflow.custom.dependency_analyzer import analyze_dependencies
code = """
import os
import sys
from typing import List
import numpy as np
from requests import get
"""
deps = analyze_dependencies(code, resolve_versions=False)
# Should find external dependencies only (stdlib imports filtered out)
assert len(deps) == 2
# Check external dependencies
dep_names = [d["name"] for d in deps]
assert "numpy" in dep_names
assert "requests" in dep_names
# Stdlib imports should be filtered out
assert "os" not in dep_names
assert "sys" not in dep_names
assert "typing" not in dep_names
def test_analyze_dependencies_optional_detection(self):
"""Test that all dependencies are treated as required (no optional detection)."""
from langflow.custom.dependency_analyzer import analyze_dependencies
code = """
import os
try:
import optional_package
HAS_OPTIONAL = True
except ImportError:
HAS_OPTIONAL = False
try:
from another_optional import something
except ImportError:
pass # This is now treated as a regular dependency
"""
deps = analyze_dependencies(code, resolve_versions=False)
# Should find external dependencies only (stdlib imports filtered out)
assert len(deps) == 2 # optional_package, another_optional
dep_names = [d["name"] for d in deps]
assert "optional_package" in dep_names
assert "another_optional" in dep_names
# Stdlib imports should be filtered out
assert "os" not in dep_names
def test_analyze_component_dependencies(self):
"""Test component-specific dependency analysis."""
from langflow.custom.dependency_analyzer import analyze_component_dependencies
component_code = """
import os
import sys
from typing import Dict, List
from langflow.custom import CustomComponent
import numpy as np
class TestComponent(CustomComponent):
def build(self):
return {"test": "value"}
"""
result = analyze_component_dependencies(component_code)
# Check structure
assert "total_dependencies" in result
assert "dependencies" in result
# Should have some dependencies (only external dependencies)
assert result["total_dependencies"] > 0
# Should have dependencies list
assert isinstance(result["dependencies"], list)
# Verify no duplicate packages in dependencies
package_names = [pkg["name"] for pkg in result["dependencies"]]
assert len(package_names) == len(set(package_names)), "No duplicate packages should exist"
def test_analyze_component_dependencies_error_handling(self):
"""Test error handling in component dependency analysis."""
from langflow.custom.dependency_analyzer import analyze_component_dependencies
# Test with invalid Python code
invalid_code = "import os\nthis is not valid python syntax!!!"
result = analyze_component_dependencies(invalid_code)
# Should return minimal info on error
assert result["total_dependencies"] == 0
assert result["dependencies"] == []
def test_dependency_info_dataclass(self):
"""Test DependencyInfo dataclass creation."""
from langflow.custom.dependency_analyzer import DependencyInfo
dep = DependencyInfo(
name="numpy",
version="1.21.0",
is_local=False,
)
assert dep.name == "numpy"
assert dep.version == "1.21.0"
assert not dep.is_local
def test_no_optional_dependency_classification(self):
"""Test that the simplified analyzer doesn't classify any dependencies as optional."""
from langflow.custom.dependency_analyzer import analyze_dependencies
# Code with various import patterns that previously might have been considered optional
code = """
import os
try:
import package_a
HAS_A = True
except ImportError:
HAS_A = False
try:
import package_b
except ImportError:
pass
try:
from package_c import something
except (ImportError, ModuleNotFoundError):
something = None
"""
deps = analyze_dependencies(code, resolve_versions=False)
# Should find external dependencies only (stdlib filtered out)
dep_names = [d["name"] for d in deps]
assert "package_a" in dep_names
assert "package_b" in dep_names
assert "package_c" in dep_names
# Stdlib imports should be filtered out
assert "os" not in dep_names
# All found dependencies should be external (not local)
for dep in deps:
assert not dep["is_local"], f"Dependency {dep['name']} should not be local"
class TestMetadataWithDependencies:
"""Test metadata functionality including dependencies."""
def test_build_component_metadata_includes_dependencies(self):
"""Test that build_component_metadata includes dependency analysis."""
def test_build_from_inputs_without_module_generates_default(self):
"""Test that build_component_metadata includes dependency analysis results."""
from langflow.custom.custom_component.component import Component
from langflow.custom.utils import build_custom_component_template_from_inputs
# Setup mock frontend node
mock_frontend = Mock()
mock_frontend.metadata = {}
# Create test component with real code
test_component = Mock(spec=Component)
test_component._code = """
import os
import sys
from typing import List
class TestComponent:
def build(self):
return {"test": "value"}
"""
# Call the function
build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent")
# Verify metadata was added
assert "module" in mock_frontend.metadata
assert "code_hash" in mock_frontend.metadata
assert "dependencies" in mock_frontend.metadata
# Verify dependency analysis results
dep_info = mock_frontend.metadata["dependencies"]
# Only external dependencies are tracked now (stdlib filtered out)
assert dep_info["total_dependencies"] == 0 # No external deps in this test code
assert "dependencies" in dep_info
assert isinstance(dep_info["dependencies"], list)
def test_build_component_metadata_handles_analysis_error(self):
"""Test that build_component_metadata handles dependency analysis errors gracefully."""
from langflow.custom.custom_component.component import Component
# Setup mock frontend node
mock_frontend = Mock()
mock_frontend.metadata = {}
# Create test component with invalid Python code
test_component = Mock(spec=Component)
test_component._code = "import os\nthis is not valid python syntax!!!"
# Call the function - should not raise exception
build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent")
# Should not raise exception and should set minimal dependency info
assert "dependencies" in mock_frontend.metadata
dep_info = mock_frontend.metadata["dependencies"]
assert dep_info["total_dependencies"] == 0
assert dep_info["dependencies"] == []
def test_build_component_metadata_with_external_dependencies(self):
"""Test dependency analysis with external packages."""
from langflow.custom.custom_component.component import Component
# Setup mock frontend node
mock_frontend = Mock()
mock_frontend.metadata = {}
# Create test component with external dependencies
test_component = Mock(spec=Component)
test_component._code = """
import os
from langflow.custom import CustomComponent
class TestComponent(CustomComponent):
def build(self):
return {"test": "value"}
"""
# Call the function
build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent")
# Verify dependency analysis results
dep_info = mock_frontend.metadata["dependencies"]
assert dep_info["total_dependencies"] == 1 # Only langflow (os is stdlib, filtered out)
# Check for dependencies
package_names = [pkg["name"] for pkg in dep_info["dependencies"]]
assert "langflow" in package_names # langflow should be detected as external
assert "os" not in package_names # os is stdlib, should be filtered out
def test_build_component_metadata_with_optional_dependencies(self):
"""Test dependency analysis with optional dependencies."""
from langflow.custom.custom_component.component import Component
# Setup mock frontend node
mock_frontend = Mock()
mock_frontend.metadata = {}
# Create test component with optional dependencies
test_component = Mock(spec=Component)
test_component._code = """
import os
try:
import some_optional_package
HAS_OPTIONAL = True
except ImportError:
HAS_OPTIONAL = False
class TestComponent:
def build(self):
return {"test": "value"}
"""
# Call the function
build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent")
# Verify dependency analysis results
dep_info = mock_frontend.metadata["dependencies"]
assert dep_info["total_dependencies"] == 1 # Only some_optional_package (os is stdlib, filtered out)
# Verify the dependencies are found
package_names = [pkg["name"] for pkg in dep_info["dependencies"]]
assert "some_optional_package" in package_names
assert "os" not in package_names # os is stdlib, should be filtered out
def test_build_component_metadata_with_real_component(self):
"""Test dependency analysis with a real component."""
from langflow.custom.custom_component.component import Component
from langflow.custom.utils import build_component_metadata
# Setup mock frontend node
mock_frontend = Mock()
mock_frontend.metadata = {}
# Use real component code based on LMStudio component
real_component_code = """from typing import Any
from urllib.parse import urljoin
import httpx
from langchain_openai import ChatOpenAI
from langflow.base.models.model import LCModelComponent
from langflow.field_typing import LanguageModel
class LMStudioModelComponent(LCModelComponent):
display_name = "LM Studio"
description = "Generate text using LM Studio Local LLMs."
icon = "LMStudio"
name = "LMStudioModel"
def build(self):
return {"test": "value"}
"""
# Create test component
test_component = Mock(spec=Component)
test_component._code = real_component_code
# Call the function
build_component_metadata(
mock_frontend, test_component, "langflow.components.lmstudio", "LMStudioModelComponent"
)
# Verify metadata was added
assert "module" in mock_frontend.metadata
assert "code_hash" in mock_frontend.metadata
assert "dependencies" in mock_frontend.metadata
# Verify dependency analysis results
dep_info = mock_frontend.metadata["dependencies"]
assert dep_info["total_dependencies"] > 0
# Check that external dependencies are found (stdlib filtered out)
package_names = [pkg["name"] for pkg in dep_info["dependencies"]]
# External packages should be found
assert "httpx" in package_names # external
assert "langchain_openai" in package_names # external
assert "langflow" in package_names # project dependency
# Stdlib imports should be filtered out
assert "typing" not in package_names
assert "urllib" not in package_names
mock_frontend.outputs = []
mock_frontend.to_dict = Mock(return_value={"test": "data"})
mock_frontend.validate_component = Mock()
mock_frontend.set_base_classes_from_outputs = Mock()
mock_frontend.display_name = "My Test Component"
mock_frontend_class.from_inputs.return_value = mock_frontend
# Create test component
test_component = Mock(spec=Component)
@ -176,7 +532,7 @@ class TestMetadataInTemplateBuilders:
patch("langflow.custom.utils.reorder_fields"),
):
# Call the function without module_name
template, _ = build_custom_component_template_from_inputs(test_component, module_name=None)
_, _ = build_custom_component_template_from_inputs(test_component, module_name=None)
# Verify metadata was added with generated module name
assert "module" in mock_frontend.metadata