refactor(core): implement centralized dynamic lazy import system for components (#8932)

* feat: add import utilities for LangFlow components

- Introduced a new module `_importing.py` containing the `import_mod` function.
- This function dynamically imports attributes from specified modules, enhancing modularity and flexibility in component initialization.
- Comprehensive docstring added for clarity on usage and parameters.

* feat: implement dynamic imports for LangFlow components

- Added dynamic import functionality to various LangFlow components, allowing for lazy loading of attributes on access.
- Introduced  mapping in each component's  to manage imports efficiently.
- Enhanced error handling for import failures, providing clearer messages for missing attributes.
- Updated  method to reflect available attributes for better introspection and tab-completion support.
- Comprehensive docstrings added to improve documentation and usability.

* test: add comprehensive tests for dynamic imports and component accessibility

- Introduced integration tests for dynamic import functionality, ensuring components are discoverable and instantiable post-refactor.
- Added unit tests for the `_import_utils` module, validating the `import_mod` function's behavior and error handling.
- Implemented tests to confirm all component modules are importable and maintain backward compatibility with existing import patterns.
- Enhanced performance tests to measure lazy loading efficiency and memory usage during component access.
- Ensured that all components have the required attributes for dynamic loading and that circular imports are prevented.

* chore: update ruff pre-commit hook to version 0.12.2 in configuration file

* refactor: update warning handling for dynamic imports

- Moved the warning suppression for LangChainDeprecationWarning into the dynamic import context to ensure it only applies during the import process.
- This change enhances clarity and maintains the original functionality while improving the robustness of the import mechanism.

* test: enhance dynamic import integration tests for component attributes

- Removed unnecessary import of AgentComponent and added assertions to verify essential attributes of OpenAIModelComponent, including display_name, description, icon, and inputs.
- Ensured that each input field has the required attributes for better validation of component integrity during dynamic imports.

* refactor: update import paths for Message class in conversation utilities

- Changed the import of the Message class from langflow.field_typing to langflow.schema.message across multiple utility files, ensuring consistency and alignment with the updated module structure.
- This refactor enhances code clarity and maintains compatibility with the latest schema definitions.

* refactor: remove Vectara components from LangFlow

- Deleted the Vectara components module from the codebase, streamlining the component structure.
- This change helps to reduce complexity and maintain focus on core functionalities.

* refactor: remove Vectara references from LangFlow component imports

- Eliminated Vectara from both the import statements and dynamic imports mapping, streamlining the component structure.
- This change contributes to reducing complexity and maintaining focus on core functionalities within the LangFlow framework.

* [autofix.ci] apply automated fixes

* fix: remove 'vectara' from __all__ in components module

* refactor: improve error handling tests for dynamic imports

* test: add tests for ModuleNotFoundError handling with None and special module names

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2025-08-05 17:48:59 -03:00 committed by GitHub
commit 80ebe03d94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 3174 additions and 232 deletions

View file

@ -0,0 +1,273 @@
"""LangFlow Components module."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components import (
Notion,
agentql,
agents,
aiml,
amazon,
anthropic,
apify,
arxiv,
assemblyai,
azure,
baidu,
bing,
cleanlab,
cloudflare,
cohere,
composio,
confluence,
crewai,
custom_component,
data,
datastax,
deepseek,
docling,
duckduckgo,
embeddings,
exa,
firecrawl,
git,
glean,
google,
groq,
helpers,
homeassistant,
huggingface,
ibm,
icosacomputing,
input_output,
langchain_utilities,
langwatch,
lmstudio,
logic,
maritalk,
mem0,
mistral,
models,
needle,
notdiamond,
novita,
nvidia,
olivya,
ollama,
openai,
openrouter,
perplexity,
processing,
prototypes,
redis,
sambanova,
scrapegraph,
searchapi,
serpapi,
tavily,
tools,
twelvelabs,
unstructured,
vectorstores,
vertexai,
wikipedia,
wolframalpha,
xai,
yahoosearch,
youtube,
zep,
)
_dynamic_imports = {
"agents": "langflow.components.agents",
"data": "langflow.components.data",
"processing": "langflow.components.processing",
"vectorstores": "langflow.components.vectorstores",
"tools": "langflow.components.tools",
"models": "langflow.components.models",
"embeddings": "langflow.components.embeddings",
"helpers": "langflow.components.helpers",
"input_output": "langflow.components.input_output",
"logic": "langflow.components.logic",
"custom_component": "langflow.components.custom_component",
"prototypes": "langflow.components.prototypes",
"openai": "langflow.components.openai",
"anthropic": "langflow.components.anthropic",
"google": "langflow.components.google",
"azure": "langflow.components.azure",
"huggingface": "langflow.components.huggingface",
"ollama": "langflow.components.ollama",
"groq": "langflow.components.groq",
"cohere": "langflow.components.cohere",
"mistral": "langflow.components.mistral",
"deepseek": "langflow.components.deepseek",
"nvidia": "langflow.components.nvidia",
"amazon": "langflow.components.amazon",
"vertexai": "langflow.components.vertexai",
"xai": "langflow.components.xai",
"perplexity": "langflow.components.perplexity",
"openrouter": "langflow.components.openrouter",
"lmstudio": "langflow.components.lmstudio",
"sambanova": "langflow.components.sambanova",
"maritalk": "langflow.components.maritalk",
"novita": "langflow.components.novita",
"olivya": "langflow.components.olivya",
"notdiamond": "langflow.components.notdiamond",
"needle": "langflow.components.needle",
"cloudflare": "langflow.components.cloudflare",
"baidu": "langflow.components.baidu",
"aiml": "langflow.components.aiml",
"ibm": "langflow.components.ibm",
"langchain_utilities": "langflow.components.langchain_utilities",
"crewai": "langflow.components.crewai",
"composio": "langflow.components.composio",
"mem0": "langflow.components.mem0",
"datastax": "langflow.components.datastax",
"cleanlab": "langflow.components.cleanlab",
"langwatch": "langflow.components.langwatch",
"icosacomputing": "langflow.components.icosacomputing",
"homeassistant": "langflow.components.homeassistant",
"agentql": "langflow.components.agentql",
"assemblyai": "langflow.components.assemblyai",
"twelvelabs": "langflow.components.twelvelabs",
"docling": "langflow.components.docling",
"unstructured": "langflow.components.unstructured",
"redis": "langflow.components.redis",
"zep": "langflow.components.zep",
"bing": "langflow.components.bing",
"duckduckgo": "langflow.components.duckduckgo",
"serpapi": "langflow.components.serpapi",
"searchapi": "langflow.components.searchapi",
"tavily": "langflow.components.tavily",
"exa": "langflow.components.exa",
"glean": "langflow.components.glean",
"yahoosearch": "langflow.components.yahoosearch",
"apify": "langflow.components.apify",
"arxiv": "langflow.components.arxiv",
"confluence": "langflow.components.confluence",
"firecrawl": "langflow.components.firecrawl",
"git": "langflow.components.git",
"wikipedia": "langflow.components.wikipedia",
"youtube": "langflow.components.youtube",
"scrapegraph": "langflow.components.scrapegraph",
"Notion": "langflow.components.Notion",
"wolframalpha": "langflow.components.wolframalpha",
}
__all__: list[str] = [
"Notion",
"agentql",
"agents",
"aiml",
"amazon",
"anthropic",
"apify",
"arxiv",
"assemblyai",
"azure",
"baidu",
"bing",
"cleanlab",
"cloudflare",
"cohere",
"composio",
"confluence",
"crewai",
"custom_component",
"data",
"datastax",
"deepseek",
"docling",
"duckduckgo",
"embeddings",
"exa",
"firecrawl",
"git",
"glean",
"google",
"groq",
"helpers",
"homeassistant",
"huggingface",
"ibm",
"icosacomputing",
"input_output",
"langchain_utilities",
"langwatch",
"lmstudio",
"logic",
"maritalk",
"mem0",
"mistral",
"models",
"needle",
"notdiamond",
"novita",
"nvidia",
"olivya",
"ollama",
"openai",
"openrouter",
"perplexity",
"processing",
"prototypes",
"redis",
"sambanova",
"scrapegraph",
"searchapi",
"serpapi",
"tavily",
"tools",
"twelvelabs",
"unstructured",
"vectorstores",
"vertexai",
"wikipedia",
"wolframalpha",
"xai",
"yahoosearch",
"youtube",
"zep",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import component modules on attribute access.
Args:
attr_name (str): The attribute/module name to import.
Returns:
Any: The imported module or attribute.
Raises:
AttributeError: If the attribute is not a known component or cannot be imported.
"""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
# Use import_mod as in LangChain, passing the module name and package
result = import_mod(attr_name, "__module__", __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result # Cache for future access
return result
def __dir__() -> list[str]:
"""Return list of available attributes for tab-completion and dir()."""
return list(__all__)
# Optional: Consistency check (can be removed in production)
_missing = set(__all__) - set(_dynamic_imports)
if _missing:
msg = f"Missing dynamic import mapping for: {', '.join(_missing)}"
raise ImportError(msg)

View file

@ -0,0 +1,37 @@
"""Import utilities for LangFlow components."""
from __future__ import annotations
from importlib import import_module
def import_mod(
attr_name: str,
module_name: str | None,
package: str | None,
) -> object:
"""Import an attribute from a module located in a package.
This utility function is used in custom __getattr__ methods within __init__.py
files to dynamically import attributes.
Args:
attr_name: The name of the attribute to import.
module_name: The name of the module to import from. If None, the attribute
is imported from the package itself.
package: The name of the package where the module is located.
"""
if module_name == "__module__" or module_name is None:
try:
result = import_module(f".{attr_name}", package=package)
except ModuleNotFoundError:
msg = f"module '{package!r}' has no attribute {attr_name!r}"
raise AttributeError(msg) from None
else:
try:
module = import_module(f".{module_name}", package=package)
except ModuleNotFoundError:
msg = f"module '{package!r}.{module_name!r}' not found"
raise ImportError(msg) from None
result = getattr(module, attr_name)
return result

View file

@ -1,7 +1,37 @@
from .aiml import AIMLModelComponent
from .aiml_embeddings import AIMLEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.aiml.aiml import AIMLModelComponent
from langflow.components.aiml.aiml_embeddings import AIMLEmbeddingsComponent
_dynamic_imports = {
"AIMLModelComponent": "aiml",
"AIMLEmbeddingsComponent": "aiml_embeddings",
}
__all__ = [
"AIMLEmbeddingsComponent",
"AIMLModelComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import aiml components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,36 @@
from .amazon_bedrock_embedding import AmazonBedrockEmbeddingsComponent
from .amazon_bedrock_model import AmazonBedrockComponent
from .s3_bucket_uploader import S3BucketUploaderComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.amazon.amazon_bedrock_embedding import AmazonBedrockEmbeddingsComponent
from langflow.components.amazon.amazon_bedrock_model import AmazonBedrockComponent
from langflow.components.amazon.s3_bucket_uploader import S3BucketUploaderComponent
_dynamic_imports = {
"AmazonBedrockEmbeddingsComponent": "amazon_bedrock_embedding",
"AmazonBedrockComponent": "amazon_bedrock_model",
"S3BucketUploaderComponent": "s3_bucket_uploader",
}
__all__ = ["AmazonBedrockComponent", "AmazonBedrockEmbeddingsComponent", "S3BucketUploaderComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import amazon components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,34 @@
from .anthropic import AnthropicModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.anthropic.anthropic import AnthropicModelComponent
_dynamic_imports = {
"AnthropicModelComponent": "anthropic",
}
__all__ = [
"AnthropicModelComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import Anthropic components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,8 +1,23 @@
from .assemblyai_get_subtitles import AssemblyAIGetSubtitles
from .assemblyai_lemur import AssemblyAILeMUR
from .assemblyai_list_transcripts import AssemblyAIListTranscripts
from .assemblyai_poll_transcript import AssemblyAITranscriptionJobPoller
from .assemblyai_start_transcript import AssemblyAITranscriptionJobCreator
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .assemblyai_get_subtitles import AssemblyAIGetSubtitles
from .assemblyai_lemur import AssemblyAILeMUR
from .assemblyai_list_transcripts import AssemblyAIListTranscripts
from .assemblyai_poll_transcript import AssemblyAITranscriptionJobPoller
from .assemblyai_start_transcript import AssemblyAITranscriptionJobCreator
_dynamic_imports = {
"AssemblyAIGetSubtitles": "assemblyai_get_subtitles",
"AssemblyAILeMUR": "assemblyai_lemur",
"AssemblyAIListTranscripts": "assemblyai_list_transcripts",
"AssemblyAITranscriptionJobCreator": "assemblyai_start_transcript",
"AssemblyAITranscriptionJobPoller": "assemblyai_poll_transcript",
}
__all__ = [
"AssemblyAIGetSubtitles",
@ -11,3 +26,21 @@ __all__ = [
"AssemblyAITranscriptionJobCreator",
"AssemblyAITranscriptionJobPoller",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import assemblyai components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,37 @@
from .azure_openai import AzureChatOpenAIComponent
from .azure_openai_embeddings import AzureOpenAIEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .azure_openai import AzureChatOpenAIComponent
from .azure_openai_embeddings import AzureOpenAIEmbeddingsComponent
_dynamic_imports = {
"AzureChatOpenAIComponent": "azure_openai",
"AzureOpenAIEmbeddingsComponent": "azure_openai_embeddings",
}
__all__ = [
"AzureChatOpenAIComponent",
"AzureOpenAIEmbeddingsComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import azure components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .baidu_qianfan_chat import QianfanChatEndpoint
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.baidu.baidu_qianfan_chat import QianfanChatEndpoint
_dynamic_imports = {
"QianfanChatEndpoint": "baidu_qianfan_chat",
}
__all__ = ["QianfanChatEndpoint"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import baidu components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,40 @@
from .cleanlab_evaluator import CleanlabEvaluator
from .cleanlab_rag_evaluator import CleanlabRAGEvaluator
from .cleanlab_remediator import CleanlabRemediator
from __future__ import annotations
__all__ = ["CleanlabEvaluator", "CleanlabRAGEvaluator", "CleanlabRemediator"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .cleanlab_evaluator import CleanlabEvaluator
from .cleanlab_rag_evaluator import CleanlabRAGEvaluator
from .cleanlab_remediator import CleanlabRemediator
_dynamic_imports = {
"CleanlabEvaluator": "cleanlab_evaluator",
"CleanlabRAGEvaluator": "cleanlab_rag_evaluator",
"CleanlabRemediator": "cleanlab_remediator",
}
__all__ = [
"CleanlabEvaluator",
"CleanlabRAGEvaluator",
"CleanlabRemediator",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import cleanlab components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .cloudflare import CloudflareWorkersAIEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.cloudflare.cloudflare import CloudflareWorkersAIEmbeddingsComponent
_dynamic_imports = {
"CloudflareWorkersAIEmbeddingsComponent": "cloudflare",
}
__all__ = ["CloudflareWorkersAIEmbeddingsComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import cloudflare components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,40 @@
from .cohere_embeddings import CohereEmbeddingsComponent
from .cohere_models import CohereComponent
from .cohere_rerank import CohereRerankComponent
from __future__ import annotations
__all__ = ["CohereComponent", "CohereEmbeddingsComponent", "CohereRerankComponent"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .cohere_embeddings import CohereEmbeddingsComponent
from .cohere_models import CohereComponent
from .cohere_rerank import CohereRerankComponent
_dynamic_imports = {
"CohereComponent": "cohere_models",
"CohereEmbeddingsComponent": "cohere_embeddings",
"CohereRerankComponent": "cohere_rerank",
}
__all__ = [
"CohereComponent",
"CohereEmbeddingsComponent",
"CohereRerankComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import cohere components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,9 +1,25 @@
from .composio_api import ComposioAPIComponent
from .github_composio import ComposioGitHubAPIComponent
from .gmail_composio import ComposioGmailAPIComponent
from .googlecalendar_composio import ComposioGoogleCalendarAPIComponent
from .outlook_composio import ComposioOutlookAPIComponent
from .slack_composio import ComposioSlackAPIComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .composio_api import ComposioAPIComponent
from .github_composio import ComposioGitHubAPIComponent
from .gmail_composio import ComposioGmailAPIComponent
from .googlecalendar_composio import ComposioGoogleCalendarAPIComponent
from .outlook_composio import ComposioOutlookAPIComponent
from .slack_composio import ComposioSlackAPIComponent
_dynamic_imports = {
"ComposioAPIComponent": "composio_api",
"ComposioGitHubAPIComponent": "github_composio",
"ComposioGmailAPIComponent": "gmail_composio",
"ComposioGoogleCalendarAPIComponent": "googlecalendar_composio",
"ComposioOutlookAPIComponent": "outlook_composio",
"ComposioSlackAPIComponent": "slack_composio",
}
__all__ = [
"ComposioAPIComponent",
@ -13,3 +29,21 @@ __all__ = [
"ComposioOutlookAPIComponent",
"ComposioSlackAPIComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import composio components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,9 +1,25 @@
from .crewai import CrewAIAgentComponent
from .hierarchical_crew import HierarchicalCrewComponent
from .hierarchical_task import HierarchicalTaskComponent
from .sequential_crew import SequentialCrewComponent
from .sequential_task import SequentialTaskComponent
from .sequential_task_agent import SequentialTaskAgentComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .crewai import CrewAIAgentComponent
from .hierarchical_crew import HierarchicalCrewComponent
from .hierarchical_task import HierarchicalTaskComponent
from .sequential_crew import SequentialCrewComponent
from .sequential_task import SequentialTaskComponent
from .sequential_task_agent import SequentialTaskAgentComponent
_dynamic_imports = {
"CrewAIAgentComponent": "crewai",
"HierarchicalCrewComponent": "hierarchical_crew",
"HierarchicalTaskComponent": "hierarchical_task",
"SequentialCrewComponent": "sequential_crew",
"SequentialTaskAgentComponent": "sequential_task_agent",
"SequentialTaskComponent": "sequential_task",
}
__all__ = [
"CrewAIAgentComponent",
@ -13,3 +29,21 @@ __all__ = [
"SequentialTaskAgentComponent",
"SequentialTaskComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import crewai components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,34 @@
from .custom_component import CustomComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .custom_component import CustomComponent
_dynamic_imports = {
"CustomComponent": "custom_component",
}
__all__ = [
"CustomComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import custom components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,16 +1,39 @@
from .astra_assistant_manager import AstraAssistantManager
from .astra_db import AstraDBChatMemory
from .astra_vectorize import AstraVectorizeComponent
from .astradb_cql import AstraDBCQLToolComponent
from .astradb_tool import AstraDBToolComponent
from .cassandra import CassandraChatMemory
from .create_assistant import AssistantsCreateAssistant
from .create_thread import AssistantsCreateThread
from .dotenv import Dotenv
from .get_assistant import AssistantsGetAssistantName
from .getenvvar import GetEnvVar
from .list_assistants import AssistantsListAssistants
from .run import AssistantsRun
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .astra_assistant_manager import AstraAssistantManager
from .astra_db import AstraDBChatMemory
from .astra_vectorize import AstraVectorizeComponent
from .astradb_cql import AstraDBCQLToolComponent
from .astradb_tool import AstraDBToolComponent
from .cassandra import CassandraChatMemory
from .create_assistant import AssistantsCreateAssistant
from .create_thread import AssistantsCreateThread
from .dotenv import Dotenv
from .get_assistant import AssistantsGetAssistantName
from .getenvvar import GetEnvVar
from .list_assistants import AssistantsListAssistants
from .run import AssistantsRun
_dynamic_imports = {
"AssistantsCreateAssistant": "create_assistant",
"AssistantsCreateThread": "create_thread",
"AssistantsGetAssistantName": "get_assistant",
"AssistantsListAssistants": "list_assistants",
"AssistantsRun": "run",
"AstraAssistantManager": "astra_assistant_manager",
"AstraDBCQLToolComponent": "astradb_cql",
"AstraDBChatMemory": "astra_db",
"AstraDBToolComponent": "astradb_tool",
"AstraVectorizeComponent": "astra_vectorize",
"CassandraChatMemory": "cassandra",
"Dotenv": "dotenv",
"GetEnvVar": "getenvvar",
}
__all__ = [
"AssistantsCreateAssistant",
@ -27,3 +50,21 @@ __all__ = [
"Dotenv",
"GetEnvVar",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import datastax components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,34 @@
from .deepseek import DeepSeekModelComponent
from __future__ import annotations
__all__ = ["DeepSeekModelComponent"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .deepseek import DeepSeekModelComponent
_dynamic_imports = {
"DeepSeekModelComponent": "deepseek",
}
__all__ = [
"DeepSeekModelComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import deepseek components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,21 @@
from .chunk_docling_document import ChunkDoclingDocumentComponent
from .docling_inline import DoclingInlineComponent
from .docling_remote import DoclingRemoteComponent
from .export_docling_document import ExportDoclingDocumentComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .chunk_docling_document import ChunkDoclingDocumentComponent
from .docling_inline import DoclingInlineComponent
from .docling_remote import DoclingRemoteComponent
from .export_docling_document import ExportDoclingDocumentComponent
_dynamic_imports = {
"ChunkDoclingDocumentComponent": "chunk_docling_document",
"DoclingInlineComponent": "docling_inline",
"DoclingRemoteComponent": "docling_remote",
"ExportDoclingDocumentComponent": "export_docling_document",
}
__all__ = [
"ChunkDoclingDocumentComponent",
@ -9,3 +23,21 @@ __all__ = [
"DoclingRemoteComponent",
"ExportDoclingDocumentComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import docling components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,9 +1,37 @@
from .similarity import EmbeddingSimilarityComponent
from .text_embedder import TextEmbedderComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.embeddings.similarity import EmbeddingSimilarityComponent
from langflow.components.embeddings.text_embedder import TextEmbedderComponent
_dynamic_imports = {
"EmbeddingSimilarityComponent": "similarity",
"TextEmbedderComponent": "text_embedder",
}
__all__ = [
"CloudflareWorkersAIEmbeddingsComponent",
"EmbeddingSimilarityComponent",
"MistralAIEmbeddingsComponent",
"TextEmbedderComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import embedding components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,6 +1,43 @@
from .firecrawl_crawl_api import FirecrawlCrawlApi
from .firecrawl_extract_api import FirecrawlExtractApi
from .firecrawl_map_api import FirecrawlMapApi
from .firecrawl_scrape_api import FirecrawlScrapeApi
from __future__ import annotations
__all__ = ["FirecrawlCrawlApi", "FirecrawlExtractApi", "FirecrawlMapApi", "FirecrawlScrapeApi"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .firecrawl_crawl_api import FirecrawlCrawlApi
from .firecrawl_extract_api import FirecrawlExtractApi
from .firecrawl_map_api import FirecrawlMapApi
from .firecrawl_scrape_api import FirecrawlScrapeApi
_dynamic_imports = {
"FirecrawlCrawlApi": "firecrawl_crawl_api",
"FirecrawlExtractApi": "firecrawl_extract_api",
"FirecrawlMapApi": "firecrawl_map_api",
"FirecrawlScrapeApi": "firecrawl_scrape_api",
}
__all__ = [
"FirecrawlCrawlApi",
"FirecrawlExtractApi",
"FirecrawlMapApi",
"FirecrawlScrapeApi",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import firecrawl components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,34 @@
from .groq import GroqModel
from __future__ import annotations
__all__ = ["GroqModel"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .groq import GroqModel
_dynamic_imports = {
"GroqModel": "groq",
}
__all__ = [
"GroqModel",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import groq components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,10 +1,27 @@
from .calculator_core import CalculatorComponent
from .create_list import CreateListComponent
from .current_date import CurrentDateComponent
from .id_generator import IDGeneratorComponent
from .memory import MemoryComponent
from .output_parser import OutputParserComponent
from .store_message import MessageStoreComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.helpers.calculator_core import CalculatorComponent
from langflow.components.helpers.create_list import CreateListComponent
from langflow.components.helpers.current_date import CurrentDateComponent
from langflow.components.helpers.id_generator import IDGeneratorComponent
from langflow.components.helpers.memory import MemoryComponent
from langflow.components.helpers.output_parser import OutputParserComponent
from langflow.components.helpers.store_message import MessageStoreComponent
_dynamic_imports = {
"CalculatorComponent": "calculator_core",
"CreateListComponent": "create_list",
"CurrentDateComponent": "current_date",
"IDGeneratorComponent": "id_generator",
"MemoryComponent": "memory",
"OutputParserComponent": "output_parser",
"MessageStoreComponent": "store_message",
}
__all__ = [
"CalculatorComponent",
@ -15,3 +32,21 @@ __all__ = [
"MessageStoreComponent",
"OutputParserComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import helper components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,37 @@
from .huggingface import HuggingFaceEndpointsComponent
from .huggingface_inference_api import HuggingFaceInferenceAPIEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .huggingface import HuggingFaceEndpointsComponent
from .huggingface_inference_api import HuggingFaceInferenceAPIEmbeddingsComponent
_dynamic_imports = {
"HuggingFaceEndpointsComponent": "huggingface",
"HuggingFaceInferenceAPIEmbeddingsComponent": "huggingface_inference_api",
}
__all__ = [
"HuggingFaceEndpointsComponent",
"HuggingFaceInferenceAPIEmbeddingsComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import huggingface components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,4 +1,34 @@
from .watsonx import WatsonxAIComponent
from .watsonx_embeddings import WatsonxEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.ibm.watsonx import WatsonxAIComponent
from langflow.components.ibm.watsonx_embeddings import WatsonxEmbeddingsComponent
_dynamic_imports = {
"WatsonxAIComponent": "watsonx",
"WatsonxEmbeddingsComponent": "watsonx_embeddings",
}
__all__ = ["WatsonxAIComponent", "WatsonxEmbeddingsComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import ibm components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,6 +1,38 @@
from .chat import ChatInput
from .chat_output import ChatOutput
from .text import TextInputComponent
from .text_output import TextOutputComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.input_output.chat import ChatInput
from langflow.components.input_output.chat_output import ChatOutput
from langflow.components.input_output.text import TextInputComponent
from langflow.components.input_output.text_output import TextOutputComponent
_dynamic_imports = {
"ChatInput": "chat",
"ChatOutput": "chat_output",
"TextInputComponent": "text",
"TextOutputComponent": "text_output",
}
__all__ = ["ChatInput", "ChatOutput", "TextInputComponent", "TextOutputComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import input/output components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,29 +1,65 @@
from .character import CharacterTextSplitterComponent
from .conversation import ConversationChainComponent
from .csv_agent import CSVAgentComponent
from .fake_embeddings import FakeEmbeddingsComponent
from .html_link_extractor import HtmlLinkExtractorComponent
from .json_agent import JsonAgentComponent
from .langchain_hub import LangChainHubPromptComponent
from .language_recursive import LanguageRecursiveTextSplitterComponent
from .language_semantic import SemanticTextSplitterComponent
from .llm_checker import LLMCheckerChainComponent
from .llm_math import LLMMathChainComponent
from .natural_language import NaturalLanguageTextSplitterComponent
from .openai_tools import OpenAIToolsAgentComponent
from .openapi import OpenAPIAgentComponent
from .recursive_character import RecursiveCharacterTextSplitterComponent
from .retrieval_qa import RetrievalQAComponent
from .runnable_executor import RunnableExecComponent
from .self_query import SelfQueryRetrieverComponent
from .spider import SpiderTool
from .sql import SQLAgentComponent
from .sql_database import SQLDatabaseComponent
from .sql_generator import SQLGeneratorComponent
from .tool_calling import ToolCallingAgentComponent
from .vector_store_info import VectorStoreInfoComponent
from .vector_store_router import VectorStoreRouterAgentComponent
from .xml_agent import XMLAgentComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .character import CharacterTextSplitterComponent
from .conversation import ConversationChainComponent
from .csv_agent import CSVAgentComponent
from .fake_embeddings import FakeEmbeddingsComponent
from .html_link_extractor import HtmlLinkExtractorComponent
from .json_agent import JsonAgentComponent
from .langchain_hub import LangChainHubPromptComponent
from .language_recursive import LanguageRecursiveTextSplitterComponent
from .language_semantic import SemanticTextSplitterComponent
from .llm_checker import LLMCheckerChainComponent
from .llm_math import LLMMathChainComponent
from .natural_language import NaturalLanguageTextSplitterComponent
from .openai_tools import OpenAIToolsAgentComponent
from .openapi import OpenAPIAgentComponent
from .recursive_character import RecursiveCharacterTextSplitterComponent
from .retrieval_qa import RetrievalQAComponent
from .runnable_executor import RunnableExecComponent
from .self_query import SelfQueryRetrieverComponent
from .spider import SpiderTool
from .sql import SQLAgentComponent
from .sql_database import SQLDatabaseComponent
from .sql_generator import SQLGeneratorComponent
from .tool_calling import ToolCallingAgentComponent
from .vector_store_info import VectorStoreInfoComponent
from .vector_store_router import VectorStoreRouterAgentComponent
from .xml_agent import XMLAgentComponent
_dynamic_imports = {
"CharacterTextSplitterComponent": "character",
"ConversationChainComponent": "conversation",
"CSVAgentComponent": "csv_agent",
"FakeEmbeddingsComponent": "fake_embeddings",
"HtmlLinkExtractorComponent": "html_link_extractor",
"JsonAgentComponent": "json_agent",
"LangChainHubPromptComponent": "langchain_hub",
"LanguageRecursiveTextSplitterComponent": "language_recursive",
"LLMCheckerChainComponent": "llm_checker",
"LLMMathChainComponent": "llm_math",
"NaturalLanguageTextSplitterComponent": "natural_language",
"OpenAIToolsAgentComponent": "openai_tools",
"OpenAPIAgentComponent": "openapi",
"RecursiveCharacterTextSplitterComponent": "recursive_character",
"RetrievalQAComponent": "retrieval_qa",
"RunnableExecComponent": "runnable_executor",
"SelfQueryRetrieverComponent": "self_query",
"SemanticTextSplitterComponent": "language_semantic",
"SpiderTool": "spider",
"SQLAgentComponent": "sql",
"SQLDatabaseComponent": "sql_database",
"SQLGeneratorComponent": "sql_generator",
"ToolCallingAgentComponent": "tool_calling",
"VectorStoreInfoComponent": "vector_store_info",
"VectorStoreRouterAgentComponent": "vector_store_router",
"XMLAgentComponent": "xml_agent",
}
__all__ = [
"CSVAgentComponent",
@ -53,3 +89,21 @@ __all__ = [
"VectorStoreRouterAgentComponent",
"XMLAgentComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import langchain utility components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,8 +1,8 @@
from langchain.chains import ConversationChain
from langflow.base.chains.model import LCChainComponent
from langflow.field_typing import Message
from langflow.inputs.inputs import HandleInput, MultilineInput
from langflow.schema.message import Message
class ConversationChainComponent(LCChainComponent):

View file

@ -1,8 +1,8 @@
from langchain.chains import LLMCheckerChain
from langflow.base.chains.model import LCChainComponent
from langflow.field_typing import Message
from langflow.inputs.inputs import HandleInput, MultilineInput
from langflow.schema.message import Message
class LLMCheckerChainComponent(LCChainComponent):

View file

@ -1,8 +1,8 @@
from langchain.chains import LLMMathChain
from langflow.base.chains.model import LCChainComponent
from langflow.field_typing import Message
from langflow.inputs.inputs import HandleInput, MultilineInput
from langflow.schema.message import Message
from langflow.template.field.base import Output

View file

@ -1,8 +1,10 @@
from typing import cast
from langchain.chains import RetrievalQA
from langflow.base.chains.model import LCChainComponent
from langflow.field_typing import Message
from langflow.inputs.inputs import BoolInput, DropdownInput, HandleInput, MultilineInput
from langflow.schema.message import Message
class RetrievalQAComponent(LCChainComponent):
@ -78,4 +80,4 @@ class RetrievalQAComponent(LCChainComponent):
result_str = f"{result_str}\n{references_str}"
# put the entire result to debug history, query and content
self.status = {**result, "source_documents": source_docs, "output": result_str}
return result_str
return cast("Message", result_str)

View file

@ -4,8 +4,8 @@ from langchain.chains import create_sql_query_chain
from langchain_core.prompts import PromptTemplate
from langflow.base.chains.model import LCChainComponent
from langflow.field_typing import Message
from langflow.inputs.inputs import HandleInput, IntInput, MultilineInput
from langflow.schema.message import Message
from langflow.template.field.base import Output
if TYPE_CHECKING:

View file

@ -1,4 +1,34 @@
from .lmstudioembeddings import LMStudioEmbeddingsComponent
from .lmstudiomodel import LMStudioModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.lmstudio.lmstudioembeddings import LMStudioEmbeddingsComponent
from langflow.components.lmstudio.lmstudiomodel import LMStudioModelComponent
_dynamic_imports = {
"LMStudioEmbeddingsComponent": "lmstudioembeddings",
"LMStudioModelComponent": "lmstudiomodel",
}
__all__ = ["LMStudioEmbeddingsComponent", "LMStudioModelComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import lmstudio components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,10 +1,27 @@
from .conditional_router import ConditionalRouterComponent
from .data_conditional_router import DataConditionalRouterComponent
from .flow_tool import FlowToolComponent
from .loop import LoopComponent
from .pass_message import PassMessageComponent
from .run_flow import RunFlowComponent
from .sub_flow import SubFlowComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.logic.conditional_router import ConditionalRouterComponent
from langflow.components.logic.data_conditional_router import DataConditionalRouterComponent
from langflow.components.logic.flow_tool import FlowToolComponent
from langflow.components.logic.loop import LoopComponent
from langflow.components.logic.pass_message import PassMessageComponent
from langflow.components.logic.run_flow import RunFlowComponent
from langflow.components.logic.sub_flow import SubFlowComponent
_dynamic_imports = {
"ConditionalRouterComponent": "conditional_router",
"DataConditionalRouterComponent": "data_conditional_router",
"FlowToolComponent": "flow_tool",
"LoopComponent": "loop",
"PassMessageComponent": "pass_message",
"RunFlowComponent": "run_flow",
"SubFlowComponent": "sub_flow",
}
__all__ = [
"ConditionalRouterComponent",
@ -15,3 +32,21 @@ __all__ = [
"RunFlowComponent",
"SubFlowComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import logic components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .maritalk import MaritalkModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.maritalk.maritalk import MaritalkModelComponent
_dynamic_imports = {
"MaritalkModelComponent": "maritalk",
}
__all__ = ["MaritalkModelComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import maritalk components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,4 +1,37 @@
from .mistral import MistralAIModelComponent
from .mistral_embeddings import MistralAIEmbeddingsComponent
from __future__ import annotations
__all__ = ["MistralAIEmbeddingsComponent", "MistralAIModelComponent"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .mistral import MistralAIModelComponent
from .mistral_embeddings import MistralAIEmbeddingsComponent
_dynamic_imports = {
"MistralAIModelComponent": "mistral",
"MistralAIEmbeddingsComponent": "mistral_embeddings",
}
__all__ = [
"MistralAIEmbeddingsComponent",
"MistralAIModelComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import mistral components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,4 +1,34 @@
from .embedding_model import EmbeddingModelComponent
from .language_model import LanguageModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.models.embedding_model import EmbeddingModelComponent
from langflow.components.models.language_model import LanguageModelComponent
_dynamic_imports = {
"EmbeddingModelComponent": "embedding_model",
"LanguageModelComponent": "language_model",
}
__all__ = ["EmbeddingModelComponent", "LanguageModelComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import model components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -0,0 +1,36 @@
"""NotDiamond components for LangFlow."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.notdiamond.notdiamond import NotDiamondComponent
_dynamic_imports = {
"NotDiamondComponent": "notdiamond",
}
__all__ = [
"NotDiamondComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import notdiamond components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .novita import NovitaModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.novita.novita import NovitaModelComponent
_dynamic_imports = {
"NovitaModelComponent": "novita",
}
__all__ = ["NovitaModelComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import novita components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,13 +1,28 @@
import sys
from __future__ import annotations
from .nvidia import NVIDIAModelComponent
from .nvidia_embedding import NVIDIAEmbeddingsComponent
from .nvidia_ingest import NvidiaIngestComponent
from .nvidia_rerank import NvidiaRerankComponent
import sys
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .nvidia import NVIDIAModelComponent
from .nvidia_embedding import NVIDIAEmbeddingsComponent
from .nvidia_ingest import NvidiaIngestComponent
from .nvidia_rerank import NvidiaRerankComponent
if sys.platform == "win32":
from .system_assist import NvidiaSystemAssistComponent
_dynamic_imports = {
"NVIDIAModelComponent": "nvidia",
"NVIDIAEmbeddingsComponent": "nvidia_embedding",
"NvidiaIngestComponent": "nvidia_ingest",
"NvidiaRerankComponent": "nvidia_rerank",
}
if sys.platform == "win32":
from .system_assist import NvidiaSystemAssistComponent
_dynamic_imports["NvidiaSystemAssistComponent"] = "system_assist"
__all__ = [
"NVIDIAEmbeddingsComponent",
"NVIDIAModelComponent",
@ -16,4 +31,27 @@ if sys.platform == "win32":
"NvidiaSystemAssistComponent",
]
else:
__all__ = ["NVIDIAEmbeddingsComponent", "NVIDIAModelComponent", "NvidiaIngestComponent", "NvidiaRerankComponent"]
__all__ = [
"NVIDIAEmbeddingsComponent",
"NVIDIAModelComponent",
"NvidiaIngestComponent",
"NvidiaRerankComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import nvidia components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,37 @@
from .ollama import ChatOllamaComponent
from .ollama_embeddings import OllamaEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .ollama import ChatOllamaComponent
from .ollama_embeddings import OllamaEmbeddingsComponent
_dynamic_imports = {
"ChatOllamaComponent": "ollama",
"OllamaEmbeddingsComponent": "ollama_embeddings",
}
__all__ = [
"ChatOllamaComponent",
"OllamaEmbeddingsComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import ollama components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,37 @@
from .openai import OpenAIEmbeddingsComponent
from .openai_chat_model import OpenAIModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.openai.openai import OpenAIEmbeddingsComponent
from langflow.components.openai.openai_chat_model import OpenAIModelComponent
_dynamic_imports = {
"OpenAIEmbeddingsComponent": "openai",
"OpenAIModelComponent": "openai_chat_model",
}
__all__ = [
"OpenAIEmbeddingsComponent",
"OpenAIModelComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import OpenAI components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .openrouter import OpenRouterComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.openrouter.openrouter import OpenRouterComponent
_dynamic_imports = {
"OpenRouterComponent": "openrouter",
}
__all__ = ["OpenRouterComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import openrouter components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,34 @@
from .perplexity import PerplexityComponent
from __future__ import annotations
__all__ = ["PerplexityComponent"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .perplexity import PerplexityComponent
_dynamic_imports = {
"PerplexityComponent": "perplexity",
}
__all__ = [
"PerplexityComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import perplexity components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,26 +1,71 @@
from .alter_metadata import AlterMetadataComponent
from .batch_run import BatchRunComponent
from .combine_text import CombineTextComponent
from .converter import TypeConverterComponent
from .create_data import CreateDataComponent
from .data_operations import DataOperationsComponent
from .extract_key import ExtractDataKeyComponent
from .filter_data_values import DataFilterComponent
from .json_cleaner import JSONCleaner
from .lambda_filter import LambdaFilterComponent
from .llm_router import LLMRouterComponent
from .merge_data import MergeDataComponent
from .message_to_data import MessageToDataComponent
from .parse_data import ParseDataComponent
from .parse_json_data import ParseJSONDataComponent
from .parser import ParserComponent
from .prompt import PromptComponent
from .python_repl_core import PythonREPLComponent
from .regex import RegexExtractorComponent
from .select_data import SelectDataComponent
from .split_text import SplitTextComponent
from .structured_output import StructuredOutputComponent
from .update_data import UpdateDataComponent
"""Processing components for LangFlow."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.processing.alter_metadata import AlterMetadataComponent
from langflow.components.processing.batch_run import BatchRunComponent
from langflow.components.processing.combine_text import CombineTextComponent
from langflow.components.processing.converter import TypeConverterComponent
from langflow.components.processing.create_data import CreateDataComponent
from langflow.components.processing.data_operations import DataOperationsComponent
from langflow.components.processing.data_to_dataframe import DataToDataFrameComponent
from langflow.components.processing.dataframe_operations import DataFrameOperationsComponent
from langflow.components.processing.extract_key import ExtractDataKeyComponent
from langflow.components.processing.filter_data import FilterDataComponent
from langflow.components.processing.filter_data_values import DataFilterComponent
from langflow.components.processing.json_cleaner import JSONCleaner
from langflow.components.processing.lambda_filter import LambdaFilterComponent
from langflow.components.processing.llm_router import LLMRouterComponent
from langflow.components.processing.merge_data import MergeDataComponent
from langflow.components.processing.message_to_data import MessageToDataComponent
from langflow.components.processing.parse_data import ParseDataComponent
from langflow.components.processing.parse_dataframe import ParseDataFrameComponent
from langflow.components.processing.parse_json_data import ParseJSONDataComponent
from langflow.components.processing.parser import ParserComponent
from langflow.components.processing.prompt import PromptComponent
from langflow.components.processing.python_repl_core import PythonREPLComponent
from langflow.components.processing.regex import RegexExtractorComponent
from langflow.components.processing.save_file import SaveToFileComponent
from langflow.components.processing.select_data import SelectDataComponent
from langflow.components.processing.split_text import SplitTextComponent
from langflow.components.processing.structured_output import StructuredOutputComponent
from langflow.components.processing.update_data import UpdateDataComponent
_dynamic_imports = {
"AlterMetadataComponent": "alter_metadata",
"BatchRunComponent": "batch_run",
"CombineTextComponent": "combine_text",
"TypeConverterComponent": "converter",
"CreateDataComponent": "create_data",
"DataOperationsComponent": "data_operations",
"DataToDataFrameComponent": "data_to_dataframe",
"DataFrameOperationsComponent": "dataframe_operations",
"ExtractDataKeyComponent": "extract_key",
"FilterDataComponent": "filter_data",
"DataFilterComponent": "filter_data_values",
"JSONCleaner": "json_cleaner",
"LambdaFilterComponent": "lambda_filter",
"LLMRouterComponent": "llm_router",
"MergeDataComponent": "merge_data",
"MessageToDataComponent": "message_to_data",
"ParseDataComponent": "parse_data",
"ParseDataFrameComponent": "parse_dataframe",
"ParseJSONDataComponent": "parse_json_data",
"ParserComponent": "parser",
"PromptComponent": "prompt",
"PythonREPLComponent": "python_repl_core",
"RegexExtractorComponent": "regex",
"SaveToFileComponent": "save_file",
"SelectDataComponent": "select_data",
"SplitTextComponent": "split_text",
"StructuredOutputComponent": "structured_output",
"UpdateDataComponent": "update_data",
}
__all__ = [
"AlterMetadataComponent",
@ -28,8 +73,11 @@ __all__ = [
"CombineTextComponent",
"CreateDataComponent",
"DataFilterComponent",
"DataFrameOperationsComponent",
"DataOperationsComponent",
"DataToDataFrameComponent",
"ExtractDataKeyComponent",
"FilterDataComponent",
"JSONCleaner",
"LLMRouterComponent",
"LambdaFilterComponent",
@ -42,9 +90,28 @@ __all__ = [
"PromptComponent",
"PythonREPLComponent",
"RegexExtractorComponent",
"SaveToFileComponent",
"SelectDataComponent",
"SplitTextComponent",
"StructuredOutputComponent",
"TypeConverterComponent",
"UpdateDataComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import processing components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,34 @@
from .python_function import PythonFunctionComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .python_function import PythonFunctionComponent
_dynamic_imports = {
"PythonFunctionComponent": "python_function",
}
__all__ = [
"PythonFunctionComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import prototype components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .sambanova import SambaNovaComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.sambanova.sambanova import SambaNovaComponent
_dynamic_imports = {
"SambaNovaComponent": "sambanova",
}
__all__ = ["SambaNovaComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import sambanova components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,5 +1,40 @@
from .scrapegraph_markdownify_api import ScrapeGraphMarkdownifyApi
from .scrapegraph_search_api import ScrapeGraphSearchApi
from .scrapegraph_smart_scraper_api import ScrapeGraphSmartScraperApi
from __future__ import annotations
__all__ = ["ScrapeGraphMarkdownifyApi", "ScrapeGraphSearchApi", "ScrapeGraphSmartScraperApi"]
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .scrapegraph_markdownify_api import ScrapeGraphMarkdownifyApi
from .scrapegraph_search_api import ScrapeGraphSearchApi
from .scrapegraph_smart_scraper_api import ScrapeGraphSmartScraperApi
_dynamic_imports = {
"ScrapeGraphMarkdownifyApi": "scrapegraph_markdownify_api",
"ScrapeGraphSearchApi": "scrapegraph_search_api",
"ScrapeGraphSmartScraperApi": "scrapegraph_smart_scraper_api",
}
__all__ = [
"ScrapeGraphMarkdownifyApi",
"ScrapeGraphSearchApi",
"ScrapeGraphSmartScraperApi",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import scrapegraph components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -0,0 +1,36 @@
"""SearchAPI components for LangFlow."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.searchapi.search import SearchComponent
_dynamic_imports = {
"SearchComponent": "search",
}
__all__ = [
"SearchComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import searchapi components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,29 +1,43 @@
from __future__ import annotations
import warnings
from typing import TYPE_CHECKING, Any
from langchain_core._api.deprecation import LangChainDeprecationWarning
from .calculator import CalculatorToolComponent
from .google_search_api import GoogleSearchAPIComponent
from .google_serper_api import GoogleSerperAPIComponent
from .python_code_structured_tool import PythonCodeStructuredTool
from .python_repl import PythonREPLToolComponent
from .search_api import SearchAPIComponent
from .searxng import SearXNGToolComponent
from .serp_api import SerpAPIComponent
from .wikidata_api import WikidataAPIComponent
from .wikipedia_api import WikipediaAPIComponent
from .yahoo_finance import YfinanceToolComponent
from langflow.components._importing import import_mod
with warnings.catch_warnings():
warnings.simplefilter("ignore", LangChainDeprecationWarning)
if TYPE_CHECKING:
from .calculator import CalculatorToolComponent
from .google_search_api import GoogleSearchAPIComponent
from .google_serper_api import GoogleSerperAPIComponent
from .python_code_structured_tool import PythonCodeStructuredTool
from .python_repl import PythonREPLToolComponent
from .search_api import SearchAPIComponent
from .searxng import SearXNGToolComponent
from .serp_api import SerpAPIComponent
from .tavily_search_tool import TavilySearchToolComponent
from .wikidata_api import WikidataAPIComponent
from .wikipedia_api import WikipediaAPIComponent
from .yahoo_finance import YfinanceToolComponent
_dynamic_imports = {
"CalculatorToolComponent": "calculator",
"GoogleSearchAPIComponent": "google_search_api",
"GoogleSerperAPIComponent": "google_serper_api",
"PythonCodeStructuredTool": "python_code_structured_tool",
"PythonREPLToolComponent": "python_repl",
"SearchAPIComponent": "search_api",
"SearXNGToolComponent": "searxng",
"SerpAPIComponent": "serp_api",
"TavilySearchToolComponent": "tavily_search_tool",
"WikidataAPIComponent": "wikidata_api",
"WikipediaAPIComponent": "wikipedia_api",
"YfinanceToolComponent": "yahoo_finance",
}
__all__ = [
"AstraDBCQLToolComponent",
"AstraDBToolComponent",
"CalculatorToolComponent",
"DuckDuckGoSearchComponent",
"ExaSearchToolkit",
"GleanSearchAPIComponent",
"GoogleSearchAPIComponent",
"GoogleSerperAPIComponent",
"PythonCodeStructuredTool",
@ -31,7 +45,28 @@ __all__ = [
"SearXNGToolComponent",
"SearchAPIComponent",
"SerpAPIComponent",
"TavilySearchToolComponent",
"WikidataAPIComponent",
"WikipediaAPIComponent",
"YfinanceToolComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import tool components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore", LangChainDeprecationWarning)
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,10 +1,27 @@
from .convert_astra_results import ConvertAstraToTwelveLabs
from .pegasus_index import PegasusIndexVideo
from .split_video import SplitVideoComponent
from .text_embeddings import TwelveLabsTextEmbeddingsComponent
from .twelvelabs_pegasus import TwelveLabsPegasus
from .video_embeddings import TwelveLabsVideoEmbeddingsComponent
from .video_file import VideoFileComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .convert_astra_results import ConvertAstraToTwelveLabs
from .pegasus_index import PegasusIndexVideo
from .split_video import SplitVideoComponent
from .text_embeddings import TwelveLabsTextEmbeddingsComponent
from .twelvelabs_pegasus import TwelveLabsPegasus
from .video_embeddings import TwelveLabsVideoEmbeddingsComponent
from .video_file import VideoFileComponent
_dynamic_imports = {
"ConvertAstraToTwelveLabs": "convert_astra_results",
"PegasusIndexVideo": "pegasus_index",
"SplitVideoComponent": "split_video",
"TwelveLabsPegasus": "twelvelabs_pegasus",
"TwelveLabsTextEmbeddingsComponent": "text_embeddings",
"TwelveLabsVideoEmbeddingsComponent": "video_embeddings",
"VideoFileComponent": "video_file",
}
__all__ = [
"ConvertAstraToTwelveLabs",
@ -15,3 +32,21 @@ __all__ = [
"TwelveLabsVideoEmbeddingsComponent",
"VideoFileComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import twelvelabs components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,27 +1,61 @@
from .astradb import AstraDBVectorStoreComponent
from .astradb_graph import AstraDBGraphVectorStoreComponent
from .cassandra import CassandraVectorStoreComponent
from .cassandra_graph import CassandraGraphVectorStoreComponent
from .chroma import ChromaVectorStoreComponent
from .clickhouse import ClickhouseVectorStoreComponent
from .couchbase import CouchbaseVectorStoreComponent
from .elasticsearch import ElasticsearchVectorStoreComponent
from .faiss import FaissVectorStoreComponent
from .graph_rag import GraphRAGComponent
from .hcd import HCDVectorStoreComponent
from .local_db import LocalDBComponent
from .milvus import MilvusVectorStoreComponent
from .mongodb_atlas import MongoVectorStoreComponent
from .opensearch import OpenSearchVectorStoreComponent
from .pgvector import PGVectorStoreComponent
from .pinecone import PineconeVectorStoreComponent
from .qdrant import QdrantVectorStoreComponent
from .redis import RedisVectorStoreComponent
from .supabase import SupabaseVectorStoreComponent
from .upstash import UpstashVectorStoreComponent
from .vectara import VectaraVectorStoreComponent
from .vectara_rag import VectaraRagComponent
from .weaviate import WeaviateVectorStoreComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .astradb import AstraDBVectorStoreComponent
from .astradb_graph import AstraDBGraphVectorStoreComponent
from .cassandra import CassandraVectorStoreComponent
from .cassandra_graph import CassandraGraphVectorStoreComponent
from .chroma import ChromaVectorStoreComponent
from .clickhouse import ClickhouseVectorStoreComponent
from .couchbase import CouchbaseVectorStoreComponent
from .elasticsearch import ElasticsearchVectorStoreComponent
from .faiss import FaissVectorStoreComponent
from .graph_rag import GraphRAGComponent
from .hcd import HCDVectorStoreComponent
from .local_db import LocalDBComponent
from .milvus import MilvusVectorStoreComponent
from .mongodb_atlas import MongoVectorStoreComponent
from .opensearch import OpenSearchVectorStoreComponent
from .pgvector import PGVectorStoreComponent
from .pinecone import PineconeVectorStoreComponent
from .qdrant import QdrantVectorStoreComponent
from .redis import RedisVectorStoreComponent
from .supabase import SupabaseVectorStoreComponent
from .upstash import UpstashVectorStoreComponent
from .vectara import VectaraVectorStoreComponent
from .vectara_rag import VectaraRagComponent
from .weaviate import WeaviateVectorStoreComponent
_dynamic_imports = {
"AstraDBVectorStoreComponent": "astradb",
"AstraDBGraphVectorStoreComponent": "astradb_graph",
"CassandraVectorStoreComponent": "cassandra",
"CassandraGraphVectorStoreComponent": "cassandra_graph",
"ChromaVectorStoreComponent": "chroma",
"ClickhouseVectorStoreComponent": "clickhouse",
"CouchbaseVectorStoreComponent": "couchbase",
"ElasticsearchVectorStoreComponent": "elasticsearch",
"FaissVectorStoreComponent": "faiss",
"GraphRAGComponent": "graph_rag",
"HCDVectorStoreComponent": "hcd",
"LocalDBComponent": "local_db",
"MilvusVectorStoreComponent": "milvus",
"MongoVectorStoreComponent": "mongodb_atlas",
"OpenSearchVectorStoreComponent": "opensearch",
"PGVectorStoreComponent": "pgvector",
"PineconeVectorStoreComponent": "pinecone",
"QdrantVectorStoreComponent": "qdrant",
"RedisVectorStoreComponent": "redis",
"SupabaseVectorStoreComponent": "supabase",
"UpstashVectorStoreComponent": "upstash",
"VectaraVectorStoreComponent": "vectara",
"VectaraRagComponent": "vectara_rag",
"WeaviateVectorStoreComponent": "weaviate",
}
__all__ = [
"AstraDBGraphVectorStoreComponent",
@ -49,3 +83,21 @@ __all__ = [
"VectaraVectorStoreComponent",
"WeaviateVectorStoreComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import vectorstore components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,7 +1,37 @@
from .vertexai import ChatVertexAIComponent
from .vertexai_embeddings import VertexAIEmbeddingsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .vertexai import ChatVertexAIComponent
from .vertexai_embeddings import VertexAIEmbeddingsComponent
_dynamic_imports = {
"ChatVertexAIComponent": "vertexai",
"VertexAIEmbeddingsComponent": "vertexai_embeddings",
}
__all__ = [
"ChatVertexAIComponent",
"VertexAIEmbeddingsComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import vertexai components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,3 +1,32 @@
from .xai import XAIModelComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from langflow.components.xai.xai import XAIModelComponent
_dynamic_imports = {
"XAIModelComponent": "xai",
}
__all__ = ["XAIModelComponent"]
def __getattr__(attr_name: str) -> Any:
"""Lazily import xai components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -1,10 +1,27 @@
from .channel import YouTubeChannelComponent
from .comments import YouTubeCommentsComponent
from .playlist import YouTubePlaylistComponent
from .search import YouTubeSearchComponent
from .trending import YouTubeTrendingComponent
from .video_details import YouTubeVideoDetailsComponent
from .youtube_transcripts import YouTubeTranscriptsComponent
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from langflow.components._importing import import_mod
if TYPE_CHECKING:
from .channel import YouTubeChannelComponent
from .comments import YouTubeCommentsComponent
from .playlist import YouTubePlaylistComponent
from .search import YouTubeSearchComponent
from .trending import YouTubeTrendingComponent
from .video_details import YouTubeVideoDetailsComponent
from .youtube_transcripts import YouTubeTranscriptsComponent
_dynamic_imports = {
"YouTubeChannelComponent": "channel",
"YouTubeCommentsComponent": "comments",
"YouTubePlaylistComponent": "playlist",
"YouTubeSearchComponent": "search",
"YouTubeTranscriptsComponent": "youtube_transcripts",
"YouTubeTrendingComponent": "trending",
"YouTubeVideoDetailsComponent": "video_details",
}
__all__ = [
"YouTubeChannelComponent",
@ -15,3 +32,21 @@ __all__ = [
"YouTubeTrendingComponent",
"YouTubeVideoDetailsComponent",
]
def __getattr__(attr_name: str) -> Any:
"""Lazily import youtube components on attribute access."""
if attr_name not in _dynamic_imports:
msg = f"module '{__name__}' has no attribute '{attr_name}'"
raise AttributeError(msg)
try:
result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
except (ModuleNotFoundError, ImportError, AttributeError) as e:
msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
raise AttributeError(msg) from e
globals()[attr_name] = result
return result
def __dir__() -> list[str]:
return list(__all__)

View file

@ -0,0 +1,299 @@
"""Integration tests for dynamic import refactor.
Tests the dynamic import system in realistic usage scenarios to ensure
the refactor doesn't break existing functionality.
"""
import sys
import time
import pytest
from langflow.components.agents import AgentComponent
from langflow.components.data import APIRequestComponent
from langflow.components.openai import OpenAIModelComponent
class TestDynamicImportIntegration:
"""Integration tests for the dynamic import system."""
def test_component_discovery_still_works(self):
"""Test that component discovery mechanisms still work after refactor."""
# This tests that the existing component discovery logic
# can still find and load components
from langflow import components
# Test that we can discover components through the main module
openai_module = components.openai
assert hasattr(openai_module, "OpenAIModelComponent")
data_module = components.data
assert hasattr(data_module, "APIRequestComponent")
def test_existing_import_patterns_work(self):
"""Test that all existing import patterns continue to work."""
# Test direct imports
import langflow.components.data as data_comp
# Test module imports
import langflow.components.openai as openai_comp
# All should work
assert OpenAIModelComponent is not None
assert APIRequestComponent is not None
assert AgentComponent is not None
assert openai_comp.OpenAIModelComponent is not None
assert data_comp.APIRequestComponent is not None
def test_component_instantiation_works(self):
"""Test that components can still be instantiated normally."""
# Test that we can create component instances
# (Note: Some components may require specific initialization parameters)
from langflow.components.helpers import CalculatorComponent
# Should be able to access the class
assert CalculatorComponent is not None
assert callable(CalculatorComponent)
def test_template_creation_compatibility(self):
"""Test that template creation still works with dynamic imports."""
# Test accessing component attributes needed for templates
# Components should have all necessary attributes for template creation
assert hasattr(OpenAIModelComponent, "__name__")
assert hasattr(OpenAIModelComponent, "__module__")
assert hasattr(OpenAIModelComponent, "display_name")
assert isinstance(OpenAIModelComponent.display_name, str)
assert OpenAIModelComponent.display_name
assert hasattr(OpenAIModelComponent, "description")
assert isinstance(OpenAIModelComponent.description, str)
assert OpenAIModelComponent.description
assert hasattr(OpenAIModelComponent, "icon")
assert isinstance(OpenAIModelComponent.icon, str)
assert OpenAIModelComponent.icon
assert hasattr(OpenAIModelComponent, "inputs")
assert isinstance(OpenAIModelComponent.inputs, list)
assert len(OpenAIModelComponent.inputs) > 0
# Check that each input has required attributes
for input_field in OpenAIModelComponent.inputs:
assert hasattr(input_field, "name"), f"Input {input_field} missing 'name' attribute"
assert hasattr(input_field, "display_name"), f"Input {input_field} missing 'display_name' attribute"
def test_multiple_import_styles_same_result(self):
"""Test that different import styles yield the same component."""
# Import the same component in different ways
from langflow import components
from langflow.components.openai import OpenAIModelComponent as DirectImport
dynamic_import = components.openai.OpenAIModelComponent
import langflow.components.openai as openai_module
module_import = openai_module.OpenAIModelComponent
# All three should be the exact same class object
assert DirectImport is dynamic_import
assert dynamic_import is module_import
assert DirectImport is module_import
def test_startup_performance_improvement(self):
"""Test that startup time is improved with lazy loading."""
# This test measures the difference in import time
# Fresh modules to test startup behavior
modules_to_clean = [
"langflow.components.vectorstores",
"langflow.components.tools",
"langflow.components.langchain_utilities",
]
for module_name in modules_to_clean:
if module_name in sys.modules:
del sys.modules[module_name]
# Time the import of a large module
start_time = time.time()
from langflow.components import vectorstores
import_time = time.time() - start_time
# Import time should be very fast (just loading the __init__.py)
assert import_time < 0.1 # Should be well under 100ms
# Test that we can access a component (it may already be cached from previous tests)
# This is expected behavior in a test suite where components get cached
# Now access a component - this should trigger loading
start_time = time.time()
chroma_component = vectorstores.ChromaVectorStoreComponent
access_time = time.time() - start_time
assert chroma_component is not None
# Access time should still be reasonable
assert access_time < 2.0 # Should be under 2 seconds
def test_memory_usage_efficiency(self):
"""Test that memory usage is more efficient with lazy loading."""
from langflow.components import processing
# Count currently loaded components
initial_component_count = len([k for k in processing.__dict__ if k.endswith("Component")])
# Access just one component
combine_text = processing.CombineTextComponent
assert combine_text is not None
# At least one more component should be loaded now
after_one_access = len([k for k in processing.__dict__ if k.endswith("Component")])
assert after_one_access >= initial_component_count
# Access another component
split_text = processing.SplitTextComponent
assert split_text is not None
# Should have at least one more component loaded
after_two_access = len([k for k in processing.__dict__ if k.endswith("Component")])
assert after_two_access >= after_one_access
def test_error_handling_in_realistic_scenarios(self):
"""Test error handling in realistic usage scenarios."""
from langflow import components
# Test accessing non-existent component category
with pytest.raises(AttributeError):
_ = components.nonexistent_category
# Test accessing non-existent component in valid category
with pytest.raises(AttributeError):
_ = components.openai.NonExistentComponent
def test_ide_autocomplete_support(self):
"""Test that IDE autocomplete support still works."""
import langflow.components.openai as openai_components
from langflow import components
# __dir__ should return all available components/modules
main_dir = dir(components)
assert "openai" in main_dir
assert "data" in main_dir
assert "agents" in main_dir
openai_dir = dir(openai_components)
assert "OpenAIModelComponent" in openai_dir
assert "OpenAIEmbeddingsComponent" in openai_dir
def test_concurrent_access(self):
"""Test that concurrent access to components works correctly."""
import threading
from langflow.components import helpers
results = []
errors = []
def access_component():
try:
component = helpers.CalculatorComponent
results.append(component)
except Exception as e:
errors.append(e)
# Create multiple threads accessing the same component
threads = []
for _ in range(5):
thread = threading.Thread(target=access_component)
threads.append(thread)
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
# Should have no errors
assert len(errors) == 0
assert len(results) == 5
# All results should be the same component class
first_result = results[0]
for result in results[1:]:
assert result is first_result
def test_circular_import_prevention(self):
"""Test that the refactor doesn't introduce circular imports."""
# This test ensures that importing components doesn't create
# circular dependency issues
# These imports should work without circular import errors
from langflow import components
from langflow.components import openai
# Access components in different orders
model1 = components.openai.OpenAIModelComponent
model2 = openai.OpenAIModelComponent
model3 = OpenAIModelComponent
# All should be the same
assert model1 is model2 is model3
def test_large_scale_component_access(self):
"""Test accessing many components doesn't cause issues."""
from langflow.components import vectorstores
# Access multiple components rapidly
components_accessed = []
component_names = [
"ChromaVectorStoreComponent",
"PineconeVectorStoreComponent",
"FaissVectorStoreComponent",
"WeaviateVectorStoreComponent",
"QdrantVectorStoreComponent",
]
for name in component_names:
if hasattr(vectorstores, name):
component = getattr(vectorstores, name)
components_accessed.append(component)
# Should have accessed multiple components without issues
assert len(components_accessed) > 0
# All should be different classes
assert len(set(components_accessed)) == len(components_accessed)
def test_component_metadata_preservation(self):
"""Test that component metadata is preserved after dynamic loading."""
# Component should have all expected metadata
assert hasattr(OpenAIModelComponent, "__name__")
assert hasattr(OpenAIModelComponent, "__module__")
assert hasattr(OpenAIModelComponent, "__doc__")
# Module path should be correct
assert "openai" in OpenAIModelComponent.__module__
def test_backwards_compatibility_comprehensive(self):
"""Comprehensive test of backwards compatibility."""
# Test all major import patterns that should still work
# 1. Direct component imports
from langflow.components.data import APIRequestComponent
assert AgentComponent is not None
assert APIRequestComponent is not None
# 2. Module imports
# 3. Main module access
import langflow.components as comp
import langflow.components.helpers as helpers_mod
import langflow.components.openai as openai_mod
# 4. Nested access
nested_component = comp.openai.OpenAIModelComponent
direct_component = openai_mod.OpenAIModelComponent
# All patterns should work and yield consistent results
assert openai_mod.OpenAIModelComponent is not None
assert helpers_mod.CalculatorComponent is not None
assert nested_component is direct_component
if __name__ == "__main__":
pytest.main([__file__, "-v"])

View file

@ -0,0 +1,307 @@
"""Test to ensure all component modules are importable after dynamic import refactor.
This test validates that every component module can be imported successfully
and that all components listed in __all__ can be accessed.
"""
import importlib
import pytest
from langflow import components
class TestAllModulesImportable:
"""Test that all component modules are importable."""
def test_all_component_categories_importable(self):
"""Test that all component categories in __all__ can be imported."""
failed_imports = []
for category_name in components.__all__:
try:
category_module = getattr(components, category_name)
assert category_module is not None, f"Category {category_name} is None"
# Verify it's actually a module
assert hasattr(category_module, "__name__"), f"Category {category_name} is not a module"
except Exception as e:
failed_imports.append(f"{category_name}: {e!s}")
if failed_imports:
pytest.fail(f"Failed to import categories: {failed_imports}")
def test_all_components_in_categories_importable(self):
"""Test that all components in each category's __all__ can be imported."""
failed_imports = []
successful_imports = 0
for category_name in components.__all__:
try:
category_module = getattr(components, category_name)
if hasattr(category_module, "__all__"):
for component_name in category_module.__all__:
try:
component = getattr(category_module, component_name)
assert component is not None, f"Component {component_name} is None"
assert callable(component), f"Component {component_name} is not callable"
successful_imports += 1
except Exception as e:
failed_imports.append(f"{category_name}.{component_name}: {e!s}")
else:
# Category doesn't have __all__, skip
continue
except Exception as e:
failed_imports.append(f"Category {category_name}: {e!s}")
print(f"Successfully imported {successful_imports} components") # noqa: T201
if failed_imports:
print(f"Failed imports ({len(failed_imports)}):") # noqa: T201
for failure in failed_imports[:10]: # Show first 10 failures
print(f" - {failure}") # noqa: T201
if len(failed_imports) > 10:
print(f" ... and {len(failed_imports) - 10} more") # noqa: T201
pytest.fail(f"Failed to import {len(failed_imports)} components")
def test_dynamic_imports_mapping_complete(self):
"""Test that _dynamic_imports mapping is complete for all categories."""
failed_mappings = []
for category_name in components.__all__:
try:
category_module = getattr(components, category_name)
if hasattr(category_module, "__all__") and hasattr(category_module, "_dynamic_imports"):
category_all = set(category_module.__all__)
dynamic_imports_keys = set(category_module._dynamic_imports.keys())
# Check that all items in __all__ have corresponding _dynamic_imports entries
missing_in_dynamic = category_all - dynamic_imports_keys
if missing_in_dynamic:
failed_mappings.append(f"{category_name}: Missing in _dynamic_imports: {missing_in_dynamic}")
# Check that all _dynamic_imports keys are in __all__
missing_in_all = dynamic_imports_keys - category_all
if missing_in_all:
failed_mappings.append(f"{category_name}: Missing in __all__: {missing_in_all}")
except Exception as e:
failed_mappings.append(f"{category_name}: Error checking mappings: {e!s}")
if failed_mappings:
pytest.fail(f"Inconsistent mappings: {failed_mappings}")
def test_backward_compatibility_imports(self):
"""Test that traditional import patterns still work."""
# Test some key imports that should always work
traditional_imports = [
("langflow.components.openai", "OpenAIModelComponent"),
("langflow.components.anthropic", "AnthropicModelComponent"),
("langflow.components.data", "APIRequestComponent"),
("langflow.components.agents", "AgentComponent"),
("langflow.components.helpers", "CalculatorComponent"),
]
failed_imports = []
for module_name, component_name in traditional_imports:
try:
module = importlib.import_module(module_name)
component = getattr(module, component_name)
assert component is not None
assert callable(component)
except Exception as e:
failed_imports.append(f"{module_name}.{component_name}: {e!s}")
if failed_imports:
pytest.fail(f"Traditional imports failed: {failed_imports}")
def test_component_modules_have_required_attributes(self):
"""Test that component modules have required attributes for dynamic loading."""
failed_modules = []
for category_name in components.__all__:
try:
category_module = getattr(components, category_name)
# Check for required attributes
required_attrs = ["__all__"]
failed_modules.extend(
f"{category_name}: Missing required attribute {attr}"
for attr in required_attrs
if not hasattr(category_module, attr)
)
# Check that if it has dynamic imports, it has the pattern
if hasattr(category_module, "_dynamic_imports"):
if not hasattr(category_module, "__getattr__"):
failed_modules.append(f"{category_name}: Has _dynamic_imports but no __getattr__")
if not hasattr(category_module, "__dir__"):
failed_modules.append(f"{category_name}: Has _dynamic_imports but no __dir__")
except Exception as e:
failed_modules.append(f"{category_name}: Error checking attributes: {e!s}")
if failed_modules:
pytest.fail(f"Module attribute issues: {failed_modules}")
def test_no_circular_imports(self):
"""Test that there are no circular import issues."""
# Test importing in different orders to catch circular imports
import_orders = [
["agents", "data", "openai"],
["openai", "agents", "data"],
["data", "openai", "agents"],
]
for order in import_orders:
try:
for category_name in order:
category_module = getattr(components, category_name)
# Access a component to trigger dynamic import
if hasattr(category_module, "__all__") and category_module.__all__:
first_component_name = category_module.__all__[0]
getattr(category_module, first_component_name)
except Exception as e:
pytest.fail(f"Circular import issue with order {order}: {e!s}")
def test_component_access_caching(self):
"""Test that component access caching works correctly."""
# Access the same component multiple times and ensure caching works
test_cases = [
("openai", "OpenAIModelComponent"),
("data", "APIRequestComponent"),
("helpers", "CalculatorComponent"),
]
for category_name, component_name in test_cases:
category_module = getattr(components, category_name)
# First access
component1 = getattr(category_module, component_name)
# Component should now be cached in module globals
assert component_name in category_module.__dict__
# Second access should return the same object
component2 = getattr(category_module, component_name)
assert component1 is component2, f"Caching failed for {category_name}.{component_name}"
def test_error_handling_for_missing_components(self):
"""Test that appropriate errors are raised for missing components."""
test_cases = [
("openai", "NonExistentComponent"),
("data", "AnotherNonExistentComponent"),
]
for category_name, component_name in test_cases:
category_module = getattr(components, category_name)
with pytest.raises(AttributeError, match=f"has no attribute '{component_name}'"):
getattr(category_module, component_name)
def test_dir_functionality(self):
"""Test that __dir__ functionality works for all modules."""
# Test main components module
main_dir = dir(components)
assert "openai" in main_dir
assert "data" in main_dir
assert "agents" in main_dir
# Test category modules
for category_name in ["openai", "data", "helpers"]:
category_module = getattr(components, category_name)
category_dir = dir(category_module)
# Should include all components from __all__
if hasattr(category_module, "__all__"):
for component_name in category_module.__all__:
assert component_name in category_dir, f"{component_name} missing from dir({category_name})"
def test_module_metadata_preservation(self):
"""Test that module metadata is preserved after dynamic loading."""
test_components = [
("openai", "OpenAIModelComponent"),
("anthropic", "AnthropicModelComponent"),
("data", "APIRequestComponent"),
]
for category_name, component_name in test_components:
category_module = getattr(components, category_name)
component = getattr(category_module, component_name)
# Check that component has expected metadata
assert hasattr(component, "__name__")
assert hasattr(component, "__module__")
assert component.__name__ == component_name
assert category_name in component.__module__
class TestSpecificModulePatterns:
"""Test specific module patterns and edge cases."""
def test_empty_init_modules(self):
"""Test modules that might have empty __init__.py files."""
# These modules might have empty __init__.py files in the original structure
potentially_empty_modules = [
"chains",
"output_parsers",
"textsplitters",
"toolkits",
"link_extractors",
"documentloaders",
]
for module_name in potentially_empty_modules:
if module_name in components.__all__:
try:
module = getattr(components, module_name)
# Should be able to import even if empty
assert module is not None
except Exception as e:
pytest.fail(f"Failed to import potentially empty module {module_name}: {e}")
def test_platform_specific_imports(self):
"""Test platform-specific imports like NVIDIA Windows components."""
# Test NVIDIA module which has platform-specific logic
nvidia_module = components.nvidia
assert nvidia_module is not None
# Should have basic components regardless of platform
assert "NVIDIAModelComponent" in nvidia_module.__all__
# Should be able to access components
nvidia_model = nvidia_module.NVIDIAModelComponent
assert nvidia_model is not None
def test_large_modules_import_efficiently(self):
"""Test that large modules with many components import efficiently."""
import time
# Test large modules
large_modules = ["vectorstores", "processing", "langchain_utilities"]
for module_name in large_modules:
if module_name in components.__all__:
start_time = time.time()
module = getattr(components, module_name)
import_time = time.time() - start_time
# Initial import should be fast (just loading __init__.py)
assert import_time < 0.5, f"Module {module_name} took too long to import: {import_time}s"
# Should have components available
assert hasattr(module, "__all__")
assert len(module.__all__) > 0
if __name__ == "__main__":
pytest.main([__file__, "-v"])

View file

@ -0,0 +1,297 @@
"""Tests for dynamic import refactor in langflow components.
This module tests the new langchain-style dynamic import system to ensure:
1. Lazy loading works correctly
2. Components are imported only when accessed
3. Caching works properly
4. Error handling for missing components
5. __dir__ functionality for IDE autocomplete
6. Backward compatibility with existing imports
"""
from unittest.mock import patch
import pytest
from langflow.components._importing import import_mod
class TestImportUtils:
"""Test the import_mod utility function."""
def test_import_mod_with_module_name(self):
"""Test importing specific attribute from a module."""
# Test importing a specific class from a module
result = import_mod("OpenAIModelComponent", "openai_chat_model", "langflow.components.openai")
assert result is not None
assert hasattr(result, "__name__")
assert "OpenAI" in result.__name__
def test_import_mod_without_module_name(self):
"""Test importing entire module when module_name is None."""
result = import_mod("agents", "__module__", "langflow.components")
assert result is not None
# Should return the agents module
assert hasattr(result, "__all__")
def test_import_mod_module_not_found(self):
"""Test error handling when module doesn't exist."""
with pytest.raises(ImportError, match="not found"):
import_mod("NonExistentComponent", "nonexistent_module", "langflow.components.openai")
def test_import_mod_attribute_not_found(self):
"""Test error handling when attribute doesn't exist in module."""
with pytest.raises(AttributeError):
import_mod("NonExistentComponent", "openai_chat_model", "langflow.components.openai")
class TestComponentDynamicImports:
"""Test dynamic import behavior in component modules."""
def test_main_components_module_dynamic_import(self):
"""Test that main components module imports submodules dynamically."""
# Import the main components module
from langflow import components
# Test that submodules are in __all__
assert "agents" in components.__all__
assert "data" in components.__all__
assert "openai" in components.__all__
# Access agents module - this should work via dynamic import
agents_module = components.agents
assert agents_module is not None
# Should be cached in globals after access
assert "agents" in components.__dict__
assert components.__dict__["agents"] is agents_module
# Second access should return cached version
agents_module_2 = components.agents
assert agents_module_2 is agents_module
def test_main_components_module_dir(self):
"""Test __dir__ functionality for main components module."""
from langflow import components
dir_result = dir(components)
# Should include all component categories
assert "agents" in dir_result
assert "data" in dir_result
assert "openai" in dir_result
assert "vectorstores" in dir_result
def test_main_components_module_missing_attribute(self):
"""Test error handling for non-existent component category."""
from langflow import components
with pytest.raises(AttributeError, match="has no attribute 'nonexistent_category'"):
_ = components.nonexistent_category
def test_category_module_dynamic_import(self):
"""Test dynamic import behavior in category modules like openai."""
import langflow.components.openai as openai_components
# Test that components are in __all__
assert "OpenAIModelComponent" in openai_components.__all__
assert "OpenAIEmbeddingsComponent" in openai_components.__all__
# Access component - this should work via dynamic import
openai_model = openai_components.OpenAIModelComponent
assert openai_model is not None
# Should be cached in globals after access
assert "OpenAIModelComponent" in openai_components.__dict__
assert openai_components.__dict__["OpenAIModelComponent"] is openai_model
# Second access should return cached version
openai_model_2 = openai_components.OpenAIModelComponent
assert openai_model_2 is openai_model
def test_category_module_dir(self):
"""Test __dir__ functionality for category modules."""
import langflow.components.openai as openai_components
dir_result = dir(openai_components)
assert "OpenAIModelComponent" in dir_result
assert "OpenAIEmbeddingsComponent" in dir_result
def test_category_module_missing_component(self):
"""Test error handling for non-existent component in category."""
import langflow.components.openai as openai_components
with pytest.raises(AttributeError, match="has no attribute 'NonExistentComponent'"):
_ = openai_components.NonExistentComponent
def test_multiple_category_modules(self):
"""Test dynamic imports work across multiple category modules."""
import langflow.components.anthropic as anthropic_components
import langflow.components.data as data_components
# Test different categories work independently
anthropic_model = anthropic_components.AnthropicModelComponent
api_request = data_components.APIRequestComponent
assert anthropic_model is not None
assert api_request is not None
# Test they're cached in their respective modules
assert "AnthropicModelComponent" in anthropic_components.__dict__
assert "APIRequestComponent" in data_components.__dict__
def test_backward_compatibility(self):
"""Test that existing import patterns still work."""
# These imports should work the same as before
from langflow.components.agents import AgentComponent
from langflow.components.data import APIRequestComponent
from langflow.components.openai import OpenAIModelComponent
assert OpenAIModelComponent is not None
assert APIRequestComponent is not None
assert AgentComponent is not None
def test_component_instantiation(self):
"""Test that dynamically imported components can be instantiated."""
from langflow.components import helpers
# Import component dynamically
calculator_class = helpers.CalculatorComponent
# Should be able to instantiate (even if it requires parameters)
assert callable(calculator_class)
assert hasattr(calculator_class, "__init__")
def test_import_error_handling(self):
"""Test error handling when import fails."""
import langflow.components.notdiamond as notdiamond_components
# Patch the import_mod function directly
with patch("langflow.components.notdiamond.import_mod") as mock_import_mod:
# Mock import_mod to raise ImportError
mock_import_mod.side_effect = ImportError("Module not found")
# Clear any cached attribute
if "NotDiamondComponent" in notdiamond_components.__dict__:
del notdiamond_components.__dict__["NotDiamondComponent"]
with pytest.raises(AttributeError, match="Could not import"):
_ = notdiamond_components.NotDiamondComponent
def test_consistency_check(self):
"""Test that __all__ and _dynamic_imports are consistent."""
import langflow.components.openai as openai_components
# All items in __all__ should have corresponding entries in _dynamic_imports
for component_name in openai_components.__all__:
assert component_name in openai_components._dynamic_imports
# All keys in _dynamic_imports should be in __all__
for component_name in openai_components._dynamic_imports:
assert component_name in openai_components.__all__
def test_type_checking_imports(self):
"""Test that TYPE_CHECKING imports work correctly with dynamic loading."""
# This test ensures that imports in TYPE_CHECKING blocks
# work correctly with the dynamic import system
import langflow.components.searchapi as searchapi_components
# Components should be available for dynamic loading
assert "SearchComponent" in searchapi_components.__all__
assert "SearchComponent" in searchapi_components._dynamic_imports
# Accessing should trigger dynamic import and caching
component = searchapi_components.SearchComponent
assert component is not None
assert "SearchComponent" in searchapi_components.__dict__
class TestPerformanceCharacteristics:
"""Test performance characteristics of dynamic imports."""
def test_lazy_loading_performance(self):
"""Test that components can be accessed and cached properly."""
from langflow.components import vectorstores
# Test that we can access a component
chroma = vectorstores.ChromaVectorStoreComponent
assert chroma is not None
# After access, it should be cached in the module's globals
assert "ChromaVectorStoreComponent" in vectorstores.__dict__
# Subsequent access should return the same cached object
chroma_2 = vectorstores.ChromaVectorStoreComponent
assert chroma_2 is chroma
def test_caching_behavior(self):
"""Test that components are cached after first access."""
from langflow.components import models
# First access
embedding_model_1 = models.EmbeddingModelComponent
# Second access should return the exact same object (cached)
embedding_model_2 = models.EmbeddingModelComponent
assert embedding_model_1 is embedding_model_2
def test_memory_usage_multiple_accesses(self):
"""Test memory behavior with multiple component accesses."""
from langflow.components import processing
# Access multiple components
components = []
component_names = ["CombineTextComponent", "SplitTextComponent", "JSONCleaner", "RegexExtractorComponent"]
for name in component_names:
component = getattr(processing, name)
components.append(component)
# Each should be cached
assert name in processing.__dict__
# All should be different classes
assert len(set(components)) == len(components)
class TestSpecialCases:
"""Test special cases and edge conditions."""
def test_empty_init_files(self):
"""Test that empty __init__.py files are handled gracefully."""
# Test accessing components from categories that might have empty __init__.py
from langflow import components
# These should work even if some categories have empty __init__.py files
agents = components.agents
assert agents is not None
def test_platform_specific_components(self):
"""Test platform-specific component handling (like NVIDIA Windows components)."""
import langflow.components.nvidia as nvidia_components
# NVIDIA components should be available
nvidia_model = nvidia_components.NVIDIAModelComponent
assert nvidia_model is not None
# Platform-specific components should be handled correctly
# (This test will pass regardless of platform since the import structure handles it)
assert "NVIDIAModelComponent" in nvidia_components.__all__
def test_import_structure_integrity(self):
"""Test that the import structure maintains integrity."""
from langflow import components
# Test that we can access nested components through the hierarchy
openai_model = components.openai.OpenAIModelComponent
data_api = components.data.APIRequestComponent
assert openai_model is not None
assert data_api is not None
# Test that both main module and submodules are properly cached
assert "openai" in components.__dict__
assert "data" in components.__dict__
if __name__ == "__main__":
# Run tests
pytest.main([__file__, "-v"])

View file

@ -0,0 +1,176 @@
"""Unit tests for the _import_utils module.
Tests the core import_mod function used throughout the dynamic import system.
"""
from unittest.mock import patch
import pytest
from langflow.components._importing import import_mod
class TestImportAttr:
"""Test the import_mod utility function in detail."""
def test_import_module_with_none_module_name(self):
"""Test importing a module when module_name is None."""
# This should import the module directly using the attr_name
result = import_mod("agents", None, "langflow.components")
# Should return the agents module
assert result is not None
assert hasattr(result, "__all__")
def test_import_module_with_module_name(self):
"""Test importing a module when module_name is __module__."""
# This should import the module directly using the attr_name
result = import_mod("agents", "__module__", "langflow.components")
# Should return the agents module
assert result is not None
assert hasattr(result, "__all__")
def test_import_modibute_from_module(self):
"""Test importing a specific attribute from a module."""
# Test importing a class from a specific module
result = import_mod("AnthropicModelComponent", "anthropic", "langflow.components.anthropic")
assert result is not None
assert hasattr(result, "__name__")
assert "Component" in result.__name__
def test_import_nonexistent_module(self):
"""Test error handling when module doesn't exist."""
with pytest.raises(ImportError, match="not found"):
import_mod("SomeComponent", "nonexistent_module", "langflow.components.openai")
def test_module_not_found_with_none_module_name(self):
"""Test ModuleNotFoundError handling when module_name is None."""
with pytest.raises(AttributeError, match="has no attribute"):
import_mod("nonexistent_module", None, "langflow.components")
def test_module_not_found_with_module_special_name(self):
"""Test ModuleNotFoundError handling when module_name is '__module__'."""
with pytest.raises(AttributeError, match="has no attribute"):
import_mod("nonexistent_module", "__module__", "langflow.components")
def test_import_nonexistent_attribute(self):
"""Test error handling when attribute doesn't exist in module."""
with pytest.raises(AttributeError):
import_mod("NonExistentComponent", "anthropic", "langflow.components.anthropic")
def test_import_with_none_package(self):
"""Test behavior when package is None."""
# This should raise TypeError because relative imports require a package
with pytest.raises(TypeError, match="package.*required"):
import_mod("something", "some_module", None)
def test_module_not_found_error_handling(self):
"""Test specific ModuleNotFoundError handling."""
with patch("importlib.import_module") as mock_import_module:
mock_import_module.side_effect = ModuleNotFoundError("No module named 'test'")
with pytest.raises(ImportError, match="not found"):
import_mod("TestComponent", "test_module", "test.package")
def test_getattr_error_handling(self):
"""Test AttributeError handling when getting attribute from module."""
# Test the case where the module exists but doesn't have the attribute
# Use a real module that exists
with pytest.raises(AttributeError):
# os module exists but doesn't have 'NonExistentAttribute'
import_mod("NonExistentAttribute", "path", "os")
def test_relative_import_behavior(self):
"""Test that relative imports are constructed correctly."""
# This test verifies the relative import logic
result = import_mod("helpers", "__module__", "langflow.components")
assert result is not None
def test_package_resolution(self):
"""Test that package parameter is used correctly."""
# Test with a known working package and module
result = import_mod("CalculatorComponent", "calculator_core", "langflow.components.helpers")
assert result is not None
assert callable(result)
def test_import_mod_with_special_module_name(self):
"""Test behavior with special module_name values."""
# Test with "__module__" - should import the attr_name as a module
result = import_mod("data", "__module__", "langflow.components")
assert result is not None
# Test with None - should also import the attr_name as a module
result2 = import_mod("data", None, "langflow.components")
assert result2 is not None
def test_error_message_formatting(self):
"""Test that error messages are properly formatted."""
with pytest.raises(ImportError) as exc_info:
import_mod("NonExistent", "nonexistent", "langflow.components")
error_msg = str(exc_info.value)
assert "langflow.components" in error_msg
assert "nonexistent" in error_msg
def test_return_value_types(self):
"""Test that import_mod returns appropriate types."""
# Test module import
module_result = import_mod("openai", "__module__", "langflow.components")
assert hasattr(module_result, "__name__")
# Test class import
class_result = import_mod("OpenAIModelComponent", "openai_chat_model", "langflow.components.openai")
assert callable(class_result)
assert hasattr(class_result, "__name__")
def test_caching_independence(self):
"""Test that import_mod doesn't interfere with Python's module caching."""
# Multiple calls should work consistently
result1 = import_mod("agents", "__module__", "langflow.components")
result2 = import_mod("agents", "__module__", "langflow.components")
# Should return the same module object (Python's import caching)
assert result1 is result2
class TestImportAttrEdgeCases:
"""Test edge cases and boundary conditions for import_mod."""
def test_empty_strings(self):
"""Test behavior with empty strings."""
with pytest.raises((ImportError, ValueError)):
import_mod("", "module", "package")
with pytest.raises((ImportError, ValueError)):
import_mod("attr", "", "package")
def test_whitespace_handling(self):
"""Test that whitespace in names is handled appropriately."""
with pytest.raises(ImportError):
import_mod("attr name", "module", "package")
def test_special_characters(self):
"""Test handling of special characters in names."""
with pytest.raises((ImportError, ValueError)):
import_mod("attr-name", "module", "package")
def test_unicode_names(self):
"""Test handling of unicode characters in names."""
with pytest.raises(ImportError):
import_mod("attß", "module", "package")
def test_very_long_names(self):
"""Test handling of very long module/attribute names."""
long_name = "a" * 1000
with pytest.raises(ImportError):
import_mod(long_name, "module", "package")
def test_numeric_names(self):
"""Test handling of numeric names."""
with pytest.raises(ImportError):
import_mod("123", "module", "package")
if __name__ == "__main__":
pytest.main([__file__, "-v"])