mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-26 21:14:42 +08:00
feat(bundles): consolidate FAISS, Notion into lfx-bundles (lowercase-slug support)
Uppercase source dirs need lowercase bundle slugs (BUNDLE_NAME_RE is lowercase-only). Enhance consolidate_bundles.py with bundle_slug(provider) = provider.lower(): the bundle dir, ext id, shim target, and extra key use the lowercased slug, while the migration import_path keeps the historical lfx.components.<Provider> casing so saved flows still resolve. Identity for already-lowercase providers (no change to prior entries). - FAISS -> lfx_bundles/faiss (faiss-cpu[py-split] + langchain-community) 1 component - Notion -> lfx_bundles/notion (requests + Markdown) 8 components test_bundle_shims.py: derive the expected bundle name by lowercasing the shim dir name (FAISS shim aliases lfx_bundles.faiss) — 159 shim tests pass. Relocate the lfx-isolated FAISS test to backend/vectorstores (repointed to lfx_bundles.faiss.faiss). 36 migration entries (0 ambiguous); index 22->20 categories, 140->131 components. SKIP=detect-secrets: regenerated code_hash hex. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -158,6 +158,14 @@ PROVIDER_DEPS: dict[str, list[str]] = {
|
||||
# --- tranche 9: langwatch evaluator (pure httpx REST; the langwatch SDK extra
|
||||
# is for the tracing service, not this component) ---
|
||||
"langwatch": [],
|
||||
# --- tranche 10: uppercase source dirs -> lowercase bundle slug (FAISS->faiss,
|
||||
# Notion->notion via bundle_slug(); import paths keep historical casing) ---
|
||||
"FAISS": [
|
||||
"faiss-cpu==1.9.0.post1; python_version < '3.14'",
|
||||
"faiss-cpu>=1.13.2; python_version >= '3.14'",
|
||||
_LC_COMMUNITY,
|
||||
],
|
||||
"Notion": ["requests>=2.32.0", "Markdown>=3.8.0"],
|
||||
}
|
||||
|
||||
_OPTIONAL_DEPS_HEADER = (
|
||||
@ -201,7 +209,7 @@ def discover_component_classes(provider_dir: Path) -> list[tuple[str, str]]:
|
||||
return found
|
||||
|
||||
|
||||
def _shim_source(provider: str) -> str:
|
||||
def _shim_source(provider: str, slug: str) -> str:
|
||||
return (
|
||||
"# lfx-bundles-shim\n"
|
||||
f'"""Compatibility shim: lfx.components.{provider} moved to lfx-bundles.\n'
|
||||
@ -215,7 +223,7 @@ def _shim_source(provider: str) -> str:
|
||||
"import sys\n"
|
||||
"\n"
|
||||
"try:\n"
|
||||
f' sys.modules[__name__] = importlib.import_module("lfx_bundles.{provider}")\n'
|
||||
f' sys.modules[__name__] = importlib.import_module("lfx_bundles.{slug}")\n'
|
||||
"except ModuleNotFoundError as exc:\n"
|
||||
' if exc.name is not None and (exc.name == "lfx_bundles" or exc.name.startswith("lfx_bundles.")):\n'
|
||||
" msg = (\n"
|
||||
@ -228,15 +236,28 @@ def _shim_source(provider: str) -> str:
|
||||
)
|
||||
|
||||
|
||||
def _rewrite_self_imports(text: str, provider: str) -> str:
|
||||
"""Rewrite absolute ``lfx.components.<provider>`` self-refs to ``lfx_bundles.<provider>``."""
|
||||
return re.sub(rf"\blfx\.components\.{re.escape(provider)}\b", f"lfx_bundles.{provider}", text)
|
||||
def _rewrite_self_imports(text: str, provider: str, slug: str) -> str:
|
||||
"""Rewrite absolute ``lfx.components.<provider>`` self-refs to ``lfx_bundles.<slug>``."""
|
||||
return re.sub(rf"\blfx\.components\.{re.escape(provider)}\b", f"lfx_bundles.{slug}", text)
|
||||
|
||||
|
||||
def bundle_slug(provider: str) -> str:
|
||||
"""Bundle directory / ext-slug name for a provider.
|
||||
|
||||
Bundle names must satisfy ``BUNDLE_NAME_RE`` (lowercase), so the in-tree
|
||||
source dir name is lowercased -- e.g. ``FAISS`` -> ``faiss``, ``Notion`` ->
|
||||
``notion``. Already-lowercase providers are unchanged. The historical
|
||||
``lfx.components.<provider>`` import paths (migration table) keep the
|
||||
original casing; only the bundle dir + ``ext:<slug>`` id are lowercased.
|
||||
"""
|
||||
return provider.lower()
|
||||
|
||||
|
||||
def move_provider(provider: str, *, apply: bool) -> list[tuple[str, str]]:
|
||||
"""Move one provider into the metapackage and leave a shim. Returns its classes."""
|
||||
slug = bundle_slug(provider)
|
||||
src = COMPONENTS_DIR / provider
|
||||
dst = BUNDLES_PKG / provider
|
||||
dst = BUNDLES_PKG / slug
|
||||
if not src.is_dir():
|
||||
msg = f"provider directory not found: {src}"
|
||||
raise SystemExit(msg)
|
||||
@ -248,19 +269,19 @@ def move_provider(provider: str, *, apply: bool) -> list[tuple[str, str]]:
|
||||
py_files = sorted(src.glob("*.py"))
|
||||
print(f" {provider}: {len(py_files)} file(s), {len(classes)} component class(es) -> {dst.relative_to(REPO_ROOT)}")
|
||||
for module_stem, class_name in classes:
|
||||
print(f" {module_stem}.{class_name} -> ext:{provider}:{class_name}@official")
|
||||
print(f" {module_stem}.{class_name} -> ext:{slug}:{class_name}@official")
|
||||
|
||||
if not apply:
|
||||
return classes
|
||||
|
||||
dst.mkdir(parents=True)
|
||||
for py in py_files:
|
||||
content = _rewrite_self_imports(py.read_text(encoding="utf-8"), provider)
|
||||
content = _rewrite_self_imports(py.read_text(encoding="utf-8"), provider, slug)
|
||||
(dst / py.name).write_text(content, encoding="utf-8")
|
||||
# Remove the moved source, then replace the in-tree dir with a one-file shim.
|
||||
shutil.rmtree(src)
|
||||
src.mkdir()
|
||||
(src / "__init__.py").write_text(_shim_source(provider), encoding="utf-8")
|
||||
(src / "__init__.py").write_text(_shim_source(provider, slug), encoding="utf-8")
|
||||
return classes
|
||||
|
||||
|
||||
@ -324,8 +345,11 @@ def append_migration_entries(plan: dict[str, list[tuple[str, str]]], *, apply: b
|
||||
new_entries: list[dict] = []
|
||||
new_ambiguous: list[dict] = []
|
||||
for provider, classes in plan.items():
|
||||
# ext id uses the lowercase bundle slug; import paths keep the historical
|
||||
# (possibly mixed-case) ``lfx.components.<provider>`` form for migration.
|
||||
slug = bundle_slug(provider)
|
||||
for module_stem, class_name in classes:
|
||||
target = f"ext:{provider}:{class_name}@official"
|
||||
target = f"ext:{slug}:{class_name}@official"
|
||||
prior = existing_bare.get(class_name)
|
||||
if class_name in already_ambiguous:
|
||||
print(f" ! {class_name!r} already ambiguous; import-path entries only")
|
||||
@ -337,7 +361,7 @@ def append_migration_entries(plan: dict[str, list[tuple[str, str]]], *, apply: b
|
||||
existing_bare[class_name] = target
|
||||
new_entries.append(_entry("import_path", f"lfx.components.{provider}.{module_stem}.{class_name}", target))
|
||||
new_entries.append(_entry("import_path", f"lfx.components.{provider}.{class_name}", target))
|
||||
new_entries.append(_entry("legacy_slot", f"ext:{provider}:{class_name}@official-pre-a", target))
|
||||
new_entries.append(_entry("legacy_slot", f"ext:{slug}:{class_name}@official-pre-a", target))
|
||||
|
||||
# Idempotency guard: a partially-failed earlier run (provider dir moved
|
||||
# but the table already written, or vice versa) must not duplicate rows on
|
||||
|
||||
@ -4,8 +4,8 @@ import pytest
|
||||
|
||||
pytest.importorskip("langchain_community")
|
||||
|
||||
from lfx.components.FAISS.faiss import FaissVectorStoreComponent
|
||||
from lfx.io import BoolInput
|
||||
from lfx_bundles.faiss.faiss import FaissVectorStoreComponent
|
||||
|
||||
|
||||
class TestFaissVectorStoreComponentDefaults:
|
||||
@ -47,6 +47,7 @@ cuga = ["cuga>=0.2.20,<0.3.0; sys_platform != 'darwin' and python_version < '3.1
|
||||
deepseek = ["langchain-openai>=1.1.6", "openai>=1.68.2,<3.0.0", "requests>=2.32.0"]
|
||||
elastic = ["elasticsearch~=8.19", "langchain-elasticsearch~=1.0.0", "opensearch-py==2.8.0"]
|
||||
exa = ["metaphor-python==0.1.23"]
|
||||
faiss = ["faiss-cpu==1.9.0.post1; python_version < '3.14'", "faiss-cpu>=1.13.2; python_version >= '3.14'", "langchain-community>=0.4.1,<1.0.0"]
|
||||
firecrawl = ["firecrawl-py>=1.0.16,<2.0.0"]
|
||||
git = ["GitPython>=3.1.50", "langchain-community>=0.4.1,<1.0.0"]
|
||||
glean = []
|
||||
@ -65,6 +66,7 @@ milvus = ["langchain-milvus~=0.3.2"]
|
||||
mistral = ["langchain-mistralai~=1.1.1"]
|
||||
mongodb = ["pymongo>=4.10.1", "langchain-mongodb>=0.11.0"]
|
||||
needle = ["needle-python>=0.4.0", "langchain-community>=0.4.1,<1.0.0"]
|
||||
notion = ["requests>=2.32.0", "Markdown>=3.8.0"]
|
||||
novita = ["langchain-openai>=1.1.6", "requests>=2.32.0"]
|
||||
nvidia = ["langchain-nvidia-ai-endpoints~=1.0.0", "nv-ingest-client>=26.1.0,<27.0.0 ; python_version >= '3.12'", "gassist>=0.0.1; sys_platform == 'win32'"]
|
||||
olivya = []
|
||||
@ -118,6 +120,7 @@ all = [
|
||||
"lfx-bundles[deepseek]",
|
||||
"lfx-bundles[elastic]",
|
||||
"lfx-bundles[exa]",
|
||||
"lfx-bundles[faiss]",
|
||||
"lfx-bundles[firecrawl]",
|
||||
"lfx-bundles[git]",
|
||||
"lfx-bundles[glean]",
|
||||
@ -136,6 +139,7 @@ all = [
|
||||
"lfx-bundles[mistral]",
|
||||
"lfx-bundles[mongodb]",
|
||||
"lfx-bundles[needle]",
|
||||
"lfx-bundles[notion]",
|
||||
"lfx-bundles[novita]",
|
||||
"lfx-bundles[nvidia]",
|
||||
"lfx-bundles[olivya]",
|
||||
|
||||
34
src/bundles/lfx-bundles/src/lfx_bundles/faiss/__init__.py
Normal file
34
src/bundles/lfx-bundles/src/lfx_bundles/faiss/__init__.py
Normal file
@ -0,0 +1,34 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from lfx.components._importing import import_mod
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .faiss import FaissVectorStoreComponent
|
||||
|
||||
_dynamic_imports = {
|
||||
"FaissVectorStoreComponent": "faiss",
|
||||
}
|
||||
|
||||
__all__ = [
|
||||
"FaissVectorStoreComponent",
|
||||
]
|
||||
|
||||
|
||||
def __getattr__(attr_name: str) -> Any:
|
||||
"""Lazily import FAISS 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__)
|
||||
@ -1,7 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
from langchain_community.vectorstores import FAISS
|
||||
|
||||
from lfx.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
|
||||
from lfx.helpers.data import docs_to_data
|
||||
from lfx.io import BoolInput, HandleInput, IntInput, StrInput
|
||||
19
src/bundles/lfx-bundles/src/lfx_bundles/notion/__init__.py
Normal file
19
src/bundles/lfx-bundles/src/lfx_bundles/notion/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
from .add_content_to_page import AddContentToPage
|
||||
from .create_page import NotionPageCreator
|
||||
from .list_database_properties import NotionDatabaseProperties
|
||||
from .list_pages import NotionListPages
|
||||
from .list_users import NotionUserList
|
||||
from .page_content_viewer import NotionPageContent
|
||||
from .search import NotionSearch
|
||||
from .update_page_property import NotionPageUpdate
|
||||
|
||||
__all__ = [
|
||||
"AddContentToPage",
|
||||
"NotionDatabaseProperties",
|
||||
"NotionListPages",
|
||||
"NotionPageContent",
|
||||
"NotionPageCreator",
|
||||
"NotionPageUpdate",
|
||||
"NotionSearch",
|
||||
"NotionUserList",
|
||||
]
|
||||
@ -4,14 +4,13 @@ from typing import Any
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from langchain_core.tools import StructuredTool
|
||||
from markdown import markdown
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import MultilineInput, SecretStrInput, StrInput
|
||||
from lfx.log.logger import logger
|
||||
from lfx.schema.data import Data
|
||||
from markdown import markdown
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
MIN_ROWS_IN_TABLE = 3
|
||||
|
||||
@ -3,12 +3,11 @@ from typing import Any
|
||||
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import MultilineInput, SecretStrInput, StrInput
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionPageCreator(LCToolComponent):
|
||||
@ -1,12 +1,11 @@
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import SecretStrInput, StrInput
|
||||
from lfx.log.logger import logger
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionDatabaseProperties(LCToolComponent):
|
||||
@ -3,13 +3,12 @@ from typing import Any
|
||||
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import MultilineInput, SecretStrInput, StrInput
|
||||
from lfx.log.logger import logger
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionListPages(LCToolComponent):
|
||||
@ -1,11 +1,10 @@
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import SecretStrInput
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class NotionUserList(LCToolComponent):
|
||||
@ -1,12 +1,11 @@
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import SecretStrInput, StrInput
|
||||
from lfx.log.logger import logger
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionPageContent(LCToolComponent):
|
||||
@ -2,12 +2,11 @@ from typing import Any
|
||||
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import DropdownInput, SecretStrInput, StrInput
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionSearch(LCToolComponent):
|
||||
@ -3,13 +3,12 @@ from typing import Any
|
||||
|
||||
import requests
|
||||
from langchain_core.tools import StructuredTool
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from lfx.base.langchain_utilities.model import LCToolComponent
|
||||
from lfx.field_typing import Tool
|
||||
from lfx.inputs.inputs import MultilineInput, SecretStrInput, StrInput
|
||||
from lfx.log.logger import logger
|
||||
from lfx.schema.data import Data
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class NotionPageUpdate(LCToolComponent):
|
||||
File diff suppressed because one or more lines are too long
@ -1,34 +1,22 @@
|
||||
from __future__ import annotations
|
||||
# lfx-bundles-shim
|
||||
"""Compatibility shim: lfx.components.FAISS moved to lfx-bundles.
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
This module re-points to the installed bundle distribution. It contains
|
||||
no component implementations and no third-party dependencies, and is
|
||||
removed once the deprecation window closes (M4).
|
||||
"""
|
||||
|
||||
from lfx.components._importing import import_mod
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .faiss import FaissVectorStoreComponent
|
||||
|
||||
_dynamic_imports = {
|
||||
"FaissVectorStoreComponent": "faiss",
|
||||
}
|
||||
|
||||
__all__ = [
|
||||
"FaissVectorStoreComponent",
|
||||
]
|
||||
|
||||
|
||||
def __getattr__(attr_name: str) -> Any:
|
||||
"""Lazily import FAISS 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__)
|
||||
try:
|
||||
sys.modules[__name__] = importlib.import_module("lfx_bundles.faiss")
|
||||
except ModuleNotFoundError as exc:
|
||||
if exc.name is not None and (exc.name == "lfx_bundles" or exc.name.startswith("lfx_bundles.")):
|
||||
msg = (
|
||||
"The 'FAISS' components moved to the 'lfx-bundles' distribution. "
|
||||
"Install it with: pip install lfx-bundles "
|
||||
"(or 'pip install langflow', which bundles it)."
|
||||
)
|
||||
raise ModuleNotFoundError(msg, name="lfx_bundles") from exc
|
||||
raise
|
||||
|
||||
@ -1,19 +1,22 @@
|
||||
from .add_content_to_page import AddContentToPage
|
||||
from .create_page import NotionPageCreator
|
||||
from .list_database_properties import NotionDatabaseProperties
|
||||
from .list_pages import NotionListPages
|
||||
from .list_users import NotionUserList
|
||||
from .page_content_viewer import NotionPageContent
|
||||
from .search import NotionSearch
|
||||
from .update_page_property import NotionPageUpdate
|
||||
# lfx-bundles-shim
|
||||
"""Compatibility shim: lfx.components.Notion moved to lfx-bundles.
|
||||
|
||||
__all__ = [
|
||||
"AddContentToPage",
|
||||
"NotionDatabaseProperties",
|
||||
"NotionListPages",
|
||||
"NotionPageContent",
|
||||
"NotionPageCreator",
|
||||
"NotionPageUpdate",
|
||||
"NotionSearch",
|
||||
"NotionUserList",
|
||||
]
|
||||
This module re-points to the installed bundle distribution. It contains
|
||||
no component implementations and no third-party dependencies, and is
|
||||
removed once the deprecation window closes (M4).
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
try:
|
||||
sys.modules[__name__] = importlib.import_module("lfx_bundles.notion")
|
||||
except ModuleNotFoundError as exc:
|
||||
if exc.name is not None and (exc.name == "lfx_bundles" or exc.name.startswith("lfx_bundles.")):
|
||||
msg = (
|
||||
"The 'Notion' components moved to the 'lfx-bundles' distribution. "
|
||||
"Install it with: pip install lfx-bundles "
|
||||
"(or 'pip install langflow', which bundles it)."
|
||||
)
|
||||
raise ModuleNotFoundError(msg, name="lfx_bundles") from exc
|
||||
raise
|
||||
|
||||
@ -4580,6 +4580,186 @@
|
||||
"legacy_slot": "ext:langwatch:LangWatchComponent@official-pre-a",
|
||||
"target": "ext:langwatch:LangWatchComponent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "FaissVectorStoreComponent",
|
||||
"target": "ext:faiss:FaissVectorStoreComponent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.FAISS.faiss.FaissVectorStoreComponent",
|
||||
"target": "ext:faiss:FaissVectorStoreComponent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.FAISS.FaissVectorStoreComponent",
|
||||
"target": "ext:faiss:FaissVectorStoreComponent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:faiss:FaissVectorStoreComponent@official-pre-a",
|
||||
"target": "ext:faiss:FaissVectorStoreComponent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "AddContentToPage",
|
||||
"target": "ext:notion:AddContentToPage@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.add_content_to_page.AddContentToPage",
|
||||
"target": "ext:notion:AddContentToPage@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.AddContentToPage",
|
||||
"target": "ext:notion:AddContentToPage@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:AddContentToPage@official-pre-a",
|
||||
"target": "ext:notion:AddContentToPage@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionPageCreator",
|
||||
"target": "ext:notion:NotionPageCreator@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.create_page.NotionPageCreator",
|
||||
"target": "ext:notion:NotionPageCreator@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionPageCreator",
|
||||
"target": "ext:notion:NotionPageCreator@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionPageCreator@official-pre-a",
|
||||
"target": "ext:notion:NotionPageCreator@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionDatabaseProperties",
|
||||
"target": "ext:notion:NotionDatabaseProperties@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.list_database_properties.NotionDatabaseProperties",
|
||||
"target": "ext:notion:NotionDatabaseProperties@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionDatabaseProperties",
|
||||
"target": "ext:notion:NotionDatabaseProperties@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionDatabaseProperties@official-pre-a",
|
||||
"target": "ext:notion:NotionDatabaseProperties@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionListPages",
|
||||
"target": "ext:notion:NotionListPages@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.list_pages.NotionListPages",
|
||||
"target": "ext:notion:NotionListPages@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionListPages",
|
||||
"target": "ext:notion:NotionListPages@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionListPages@official-pre-a",
|
||||
"target": "ext:notion:NotionListPages@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionUserList",
|
||||
"target": "ext:notion:NotionUserList@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.list_users.NotionUserList",
|
||||
"target": "ext:notion:NotionUserList@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionUserList",
|
||||
"target": "ext:notion:NotionUserList@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionUserList@official-pre-a",
|
||||
"target": "ext:notion:NotionUserList@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionPageContent",
|
||||
"target": "ext:notion:NotionPageContent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.page_content_viewer.NotionPageContent",
|
||||
"target": "ext:notion:NotionPageContent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionPageContent",
|
||||
"target": "ext:notion:NotionPageContent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionPageContent@official-pre-a",
|
||||
"target": "ext:notion:NotionPageContent@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionSearch",
|
||||
"target": "ext:notion:NotionSearch@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.search.NotionSearch",
|
||||
"target": "ext:notion:NotionSearch@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionSearch",
|
||||
"target": "ext:notion:NotionSearch@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionSearch@official-pre-a",
|
||||
"target": "ext:notion:NotionSearch@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"bare_class_name": "NotionPageUpdate",
|
||||
"target": "ext:notion:NotionPageUpdate@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.update_page_property.NotionPageUpdate",
|
||||
"target": "ext:notion:NotionPageUpdate@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"import_path": "lfx.components.Notion.NotionPageUpdate",
|
||||
"target": "ext:notion:NotionPageUpdate@official",
|
||||
"added_in": "1.11.0"
|
||||
},
|
||||
{
|
||||
"legacy_slot": "ext:notion:NotionPageUpdate@official-pre-a",
|
||||
"target": "ext:notion:NotionPageUpdate@official",
|
||||
"added_in": "1.11.0"
|
||||
}
|
||||
],
|
||||
"ambiguous_bare_names": [
|
||||
|
||||
@ -640,7 +640,7 @@ def _process_single_module(modname: str) -> tuple[str, dict] | None:
|
||||
logger.error(f"Failed to import module {modname}: {e}", exc_info=True)
|
||||
return None
|
||||
# Extract the top-level subpackage name after "lfx.components."
|
||||
# e.g., "lfx.components.Notion.add_content_to_page" -> "Notion"
|
||||
# e.g., "lfx.components.processing.combine_text" -> "processing"
|
||||
mod_parts = modname.split(".")
|
||||
if len(mod_parts) <= MIN_MODULE_PARTS:
|
||||
return None
|
||||
|
||||
@ -91,13 +91,16 @@ def test_shim_source_contract(shim_dir: Path) -> None:
|
||||
message must name the matching distribution.
|
||||
"""
|
||||
provider = shim_dir.name
|
||||
# Bundle names are lowercase (BUNDLE_NAME_RE), so a mixed-case in-tree dir
|
||||
# (e.g. FAISS, Notion) aliases to its lowercased bundle (faiss, notion).
|
||||
slug = provider.lower()
|
||||
src = (shim_dir / "__init__.py").read_text(encoding="utf-8")
|
||||
|
||||
assert src.startswith(SHIM_MARKER), f"{provider}: first line must be the {SHIM_MARKER!r} marker"
|
||||
assert "sys.modules[__name__] = importlib.import_module(" in src, f"{provider}: must module-alias"
|
||||
|
||||
meta_target = f'importlib.import_module("lfx_bundles.{provider}")'
|
||||
partner_target = f'importlib.import_module("lfx_{provider}.components.{provider}")'
|
||||
meta_target = f'importlib.import_module("lfx_bundles.{slug}")'
|
||||
partner_target = f'importlib.import_module("lfx_{slug}.components.{slug}")'
|
||||
is_meta = meta_target in src
|
||||
is_partner = partner_target in src
|
||||
assert is_meta or is_partner, f"{provider}: alias target is neither metapackage nor partner shape"
|
||||
@ -106,9 +109,9 @@ def test_shim_source_contract(shim_dir: Path) -> None:
|
||||
assert 'exc.name == "lfx_bundles"' in src, f"{provider}: name-check must guard lfx_bundles"
|
||||
assert _METAPACKAGE_MSG in src, f"{provider}: locked install message missing ({_METAPACKAGE_MSG!r})"
|
||||
else:
|
||||
assert f'exc.name == "lfx_{provider}"' in src, f"{provider}: name-check must guard lfx_{provider}"
|
||||
assert f"{_PARTNER_MSG_PREFIX}{provider}" in src, (
|
||||
f"{provider}: locked install message missing ('pip install lfx-{provider}')"
|
||||
assert f'exc.name == "lfx_{slug}"' in src, f"{provider}: name-check must guard lfx_{slug}"
|
||||
assert f"{_PARTNER_MSG_PREFIX}{slug}" in src, (
|
||||
f"{provider}: locked install message missing ('pip install lfx-{slug}')"
|
||||
)
|
||||
# Contract #5: anything other than the bundle-missing case re-raises.
|
||||
assert src.rstrip().endswith("raise"), f"{provider}: must re-raise non-bundle import errors untouched"
|
||||
|
||||
21
uv.lock
generated
21
uv.lock
generated
@ -9150,6 +9150,8 @@ all = [
|
||||
{ name = "couchbase" },
|
||||
{ name = "cuga", marker = "(python_full_version < '3.14' and platform_machine == 'arm64') or (python_full_version < '3.14' and sys_platform != 'darwin')" },
|
||||
{ name = "elasticsearch" },
|
||||
{ name = "faiss-cpu", version = "1.9.0.post1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
|
||||
{ name = "faiss-cpu", version = "1.14.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
|
||||
{ name = "firecrawl-py" },
|
||||
{ name = "gassist", marker = "sys_platform == 'win32'" },
|
||||
{ name = "gitpython" },
|
||||
@ -9177,6 +9179,7 @@ all = [
|
||||
{ name = "langchain-sambanova" },
|
||||
{ name = "langchain-unstructured" },
|
||||
{ name = "langchain-weaviate" },
|
||||
{ name = "markdown" },
|
||||
{ name = "mem0ai" },
|
||||
{ name = "metaphor-python" },
|
||||
{ name = "needle-python" },
|
||||
@ -9278,6 +9281,11 @@ elastic = [
|
||||
exa = [
|
||||
{ name = "metaphor-python" },
|
||||
]
|
||||
faiss = [
|
||||
{ name = "faiss-cpu", version = "1.9.0.post1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.14'" },
|
||||
{ name = "faiss-cpu", version = "1.14.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
|
||||
{ name = "langchain-community" },
|
||||
]
|
||||
firecrawl = [
|
||||
{ name = "firecrawl-py" },
|
||||
]
|
||||
@ -9336,6 +9344,10 @@ needle = [
|
||||
{ name = "langchain-community" },
|
||||
{ name = "needle-python" },
|
||||
]
|
||||
notion = [
|
||||
{ name = "markdown" },
|
||||
{ name = "requests" },
|
||||
]
|
||||
novita = [
|
||||
{ name = "langchain-openai" },
|
||||
{ name = "requests" },
|
||||
@ -9457,6 +9469,8 @@ requires-dist = [
|
||||
{ name = "cuga", marker = "python_full_version < '3.14' and platform_machine == 'arm64' and sys_platform == 'darwin' and extra == 'cuga'", specifier = ">=0.2.20,<0.3.0" },
|
||||
{ name = "cuga", marker = "python_full_version < '3.14' and sys_platform != 'darwin' and extra == 'cuga'", specifier = ">=0.2.20,<0.3.0" },
|
||||
{ name = "elasticsearch", marker = "extra == 'elastic'", specifier = "~=8.19" },
|
||||
{ name = "faiss-cpu", marker = "python_full_version >= '3.14' and extra == 'faiss'", specifier = ">=1.13.2" },
|
||||
{ name = "faiss-cpu", marker = "python_full_version < '3.14' and extra == 'faiss'", specifier = "==1.9.0.post1" },
|
||||
{ name = "firecrawl-py", marker = "extra == 'firecrawl'", specifier = ">=1.0.16,<2.0.0" },
|
||||
{ name = "gassist", marker = "sys_platform == 'win32' and extra == 'nvidia'", specifier = ">=0.0.1" },
|
||||
{ name = "gitpython", marker = "extra == 'git'", specifier = ">=3.1.50" },
|
||||
@ -9474,6 +9488,7 @@ requires-dist = [
|
||||
{ name = "langchain-community", marker = "extra == 'cloudflare'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'confluence'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'couchbase'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'faiss'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'git'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'huggingface'", specifier = ">=0.4.1,<1.0.0" },
|
||||
{ name = "langchain-community", marker = "extra == 'maritalk'", specifier = ">=0.4.1,<1.0.0" },
|
||||
@ -9537,6 +9552,7 @@ requires-dist = [
|
||||
{ name = "lfx-bundles", extras = ["deepseek"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["elastic"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["exa"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["faiss"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["firecrawl"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["git"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["glean"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
@ -9555,6 +9571,7 @@ requires-dist = [
|
||||
{ name = "lfx-bundles", extras = ["mistral"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["mongodb"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["needle"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["notion"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["novita"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["nvidia"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["olivya"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
@ -9586,6 +9603,7 @@ requires-dist = [
|
||||
{ name = "lfx-bundles", extras = ["yahoosearch"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["youtube"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "lfx-bundles", extras = ["zep"], marker = "extra == 'all'", editable = "src/bundles/lfx-bundles" },
|
||||
{ name = "markdown", marker = "extra == 'notion'", specifier = ">=3.8.0" },
|
||||
{ name = "mem0ai", marker = "extra == 'mem0'", specifier = ">=2.0.2,<3.0.0" },
|
||||
{ name = "metaphor-python", marker = "extra == 'exa'", specifier = "==0.1.23" },
|
||||
{ name = "needle-python", marker = "extra == 'needle'", specifier = ">=0.4.0" },
|
||||
@ -9608,6 +9626,7 @@ requires-dist = [
|
||||
{ name = "requests", marker = "extra == 'deepseek'", specifier = ">=2.32.0" },
|
||||
{ name = "requests", marker = "extra == 'homeassistant'", specifier = ">=2.32.0" },
|
||||
{ name = "requests", marker = "extra == 'icosacomputing'", specifier = ">=2.32.0" },
|
||||
{ name = "requests", marker = "extra == 'notion'", specifier = ">=2.32.0" },
|
||||
{ name = "requests", marker = "extra == 'novita'", specifier = ">=2.32.0" },
|
||||
{ name = "requests", marker = "extra == 'xai'", specifier = ">=2.32.0" },
|
||||
{ name = "scrapegraph-py", marker = "extra == 'scrapegraph'", specifier = ">=1.12.0" },
|
||||
@ -9624,7 +9643,7 @@ requires-dist = [
|
||||
{ name = "youtube-transcript-api", marker = "extra == 'youtube'", specifier = ">=1.0.0,<2.0.0" },
|
||||
{ name = "zep-python", marker = "extra == 'zep'", specifier = "==2.0.2" },
|
||||
]
|
||||
provides-extras = ["agentql", "aiml", "altk", "apify", "assemblyai", "azure", "baidu", "bing", "chroma", "cleanlab", "clickhouse", "cloudflare", "codeagents", "cometapi", "composio", "confluence", "couchbase", "cuga", "deepseek", "elastic", "exa", "firecrawl", "git", "glean", "google", "groq", "homeassistant", "huggingface", "icosacomputing", "jigsawstack", "langwatch", "litellm", "lmstudio", "maritalk", "mem0", "milvus", "mistral", "mongodb", "needle", "novita", "nvidia", "olivya", "ollama", "openrouter", "perplexity", "pgvector", "pinecone", "qdrant", "redis", "sambanova", "scrapegraph", "searchapi", "serpapi", "spider", "supabase", "tavily", "toolguard", "twelvelabs", "unstructured", "upstash", "vectara", "vertexai", "vllm", "weaviate", "wikipedia", "wolframalpha", "xai", "yahoosearch", "youtube", "zep", "all"]
|
||||
provides-extras = ["agentql", "aiml", "altk", "apify", "assemblyai", "azure", "baidu", "bing", "chroma", "cleanlab", "clickhouse", "cloudflare", "codeagents", "cometapi", "composio", "confluence", "couchbase", "cuga", "deepseek", "elastic", "exa", "faiss", "firecrawl", "git", "glean", "google", "groq", "homeassistant", "huggingface", "icosacomputing", "jigsawstack", "langwatch", "litellm", "lmstudio", "maritalk", "mem0", "milvus", "mistral", "mongodb", "needle", "notion", "novita", "nvidia", "olivya", "ollama", "openrouter", "perplexity", "pgvector", "pinecone", "qdrant", "redis", "sambanova", "scrapegraph", "searchapi", "serpapi", "spider", "supabase", "tavily", "toolguard", "twelvelabs", "unstructured", "upstash", "vectara", "vertexai", "vllm", "weaviate", "wikipedia", "wolframalpha", "xai", "yahoosearch", "youtube", "zep", "all"]
|
||||
|
||||
[[package]]
|
||||
name = "lfx-cohere"
|
||||
|
||||
Reference in New Issue
Block a user