diff --git a/poetry.lock b/poetry.lock index fd5d0bdea..b71793db0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -5988,7 +5988,7 @@ files = [ {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, - {file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] [[package]] @@ -6912,6 +6912,7 @@ optional = false python-versions = ">=3.9" files = [ {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"}, + {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"}, {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"}, {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"}, {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"}, @@ -6932,6 +6933,7 @@ files = [ {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"}, {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"}, {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"}, + {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"}, {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"}, {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"}, {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"}, @@ -8644,6 +8646,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -11991,4 +11994,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "3acb8b0235dcb5d33db0362bd5cf8a5dfcfb9cc198887dd2570b81c39a0fe46c" +content-hash = "b0b58a9883d3eacc262701a7938ff839365386ba5e155dd2582986501d2b5d7c" diff --git a/pyproject.toml b/pyproject.toml index 7e60cb89b..2553900dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,7 +111,7 @@ composio-langchain = "^0.3.28" [tool.poetry.group.dev.dependencies] types-redis = "^4.6.0.5" ipykernel = "^6.29.0" -mypy = "^1.10.0" +mypy = "^1.11.0" ruff = "^0.4.5" httpx = "*" pytest = "^8.2.0" @@ -193,8 +193,11 @@ line-length = 120 [tool.mypy] plugins = ["pydantic.mypy"] -follow_imports = "silent" +follow_imports = "skip" disable_error_code = ["type-var"] +namespace_packages = true +mypy_path = "langflow" +ignore_missing_imports = true [build-system] requires = ["poetry-core"] diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py index 03c3c96b6..50f3b06b6 100644 --- a/src/backend/base/langflow/api/v1/chat.py +++ b/src/backend/base/langflow/api/v1/chat.py @@ -103,18 +103,7 @@ async def retrieve_vertices_order( graph = await build_and_cache_graph_from_data( flow_id=flow_id_str, graph_data=data.model_dump(), chat_service=chat_service ) - graph.validate_stream() - if stop_component_id or start_component_id: - try: - first_layer = graph.sort_vertices(stop_component_id, start_component_id) - except Exception as exc: - logger.error(exc) - first_layer = graph.sort_vertices() - else: - first_layer = graph.sort_vertices() - - for vertex_id in first_layer: - graph.run_manager.add_to_vertices_being_run(vertex_id) + graph = graph.prepare(stop_component_id, start_component_id) # Now vertices is a list of lists # We need to get the id of each vertex @@ -130,7 +119,7 @@ async def retrieve_vertices_order( playgroundSuccess=True, ), ) - return VerticesOrderResponse(ids=first_layer, run_id=graph._run_id, vertices_to_run=vertices_to_run) + return VerticesOrderResponse(ids=graph.first_layer, run_id=graph.run_id, vertices_to_run=vertices_to_run) except Exception as exc: background_tasks.add_task( telemetry_service.log_package_playground, diff --git a/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py b/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py index 2a753b30e..149c7325c 100644 --- a/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py +++ b/src/backend/base/langflow/components/retrievers/SelfQueryRetriever.py @@ -67,4 +67,4 @@ class SelfQueryRetrieverComponent(CustomComponent): documents = self_query_retriever.invoke(input=input_text, config={"callbacks": self.get_langchain_callbacks()}) data = [Data.from_document(document) for document in documents] self.status = data - return data + return data # type: ignore diff --git a/src/backend/base/langflow/graph/edge/base.py b/src/backend/base/langflow/graph/edge/base.py index 78ad68d45..a59eea256 100644 --- a/src/backend/base/langflow/graph/edge/base.py +++ b/src/backend/base/langflow/graph/edge/base.py @@ -1,8 +1,9 @@ -from typing import TYPE_CHECKING, Any, List, Optional +from typing import TYPE_CHECKING, Any, List, Optional, cast from loguru import logger from pydantic import BaseModel, Field, field_validator +from langflow.graph.edge.schema import EdgeData from langflow.schema.schema import INPUT_FIELD_NAME if TYPE_CHECKING: @@ -36,7 +37,7 @@ class TargetHandle(BaseModel): class Edge: - def __init__(self, source: "Vertex", target: "Vertex", edge: dict): + def __init__(self, source: "Vertex", target: "Vertex", edge: EdgeData): self.source_id: str = source.id if source else "" self.target_id: str = target.id if target else "" if data := edge.get("data", {}): @@ -50,11 +51,11 @@ class Edge: else: # Logging here because this is a breaking change logger.error("Edge data is empty") - self._source_handle = edge.get("sourceHandle", "") - self._target_handle = edge.get("targetHandle", "") + self._source_handle = edge.get("sourceHandle", "") # type: ignore + self._target_handle = edge.get("targetHandle", "") # type: ignore # 'BaseLoader;BaseOutputParser|documents|PromptTemplate-zmTlD' # target_param is documents - self.target_param = self._target_handle.split("|")[1] + self.target_param = cast(str, self._target_handle.split("|")[1]) # type: ignore # Validate in __init__ to fail fast self.validate_edge(source, target) @@ -182,7 +183,7 @@ class Edge: class ContractEdge(Edge): - def __init__(self, source: "Vertex", target: "Vertex", raw_edge: dict): + def __init__(self, source: "Vertex", target: "Vertex", raw_edge: EdgeData): super().__init__(source, target, raw_edge) self.is_fulfilled = False # Whether the contract has been fulfilled. self.result: Any = None diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index b5f9df8da..42da6a41a 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -10,6 +10,7 @@ from loguru import logger from langflow.exceptions.component import ComponentBuildException from langflow.graph.edge.base import ContractEdge +from langflow.graph.edge.schema import EdgeData from langflow.graph.graph.constants import lazy_load_vertex_dict from langflow.graph.graph.runnable_vertices_manager import RunnableVerticesManager from langflow.graph.graph.state_manager import GraphStateManager @@ -67,13 +68,14 @@ class Graph: self.vertices: List[Vertex] = [] self.run_manager = RunnableVerticesManager() self.state_manager = GraphStateManager() + self._first_layer: List[str] = [] try: self.tracing_service: "TracingService" | None = get_tracing_service() except Exception as exc: logger.error(f"Error getting tracing service: {exc}") self.tracing_service = None - def add_nodes_and_edges(self, nodes: List[Dict], edges: List[Dict[str, str]]): + def add_nodes_and_edges(self, nodes: List[Dict], edges: List[EdgeData]): self._vertices = nodes self._edges = edges self.raw_graph_data = {"nodes": nodes, "edges": edges} @@ -91,8 +93,7 @@ class Graph: def add_node(self, node: dict): self._vertices.append(node) - # TODO: Create a TypedDict to represente the edge - def add_edge(self, edge: dict): + def add_edge(self, edge: EdgeData): self._edges.append(edge) def initialize(self): @@ -220,6 +221,12 @@ class Graph: "are connected and both have stream or streaming set to True" ) + @property + def first_layer(self): + if self._first_layer is None: + raise ValueError("Graph not prepared. Call prepare() first.") + return self._first_layer + @property def run_id(self): """ @@ -646,7 +653,7 @@ class Graph: try: vertices = payload["nodes"] edges = payload["edges"] - graph = cls(flow_id, flow_name, user_id) + graph = cls(flow_id=flow_id, flow_name=flow_name, user_id=user_id) graph.add_nodes_and_edges(vertices, edges) return graph except KeyError as exc: @@ -1220,6 +1227,27 @@ class Graph: vertex_instance.set_top_level(self.top_level_vertices) return vertex_instance + def prepare(self, stop_component_id: Optional[str] = None, start_component_id: Optional[str] = None): + if stop_component_id and start_component_id: + raise ValueError("You can only provide one of stop_component_id or start_component_id") + self.validate_stream() + self.edges = self._build_edges() + if stop_component_id or start_component_id: + try: + first_layer = self.sort_vertices(stop_component_id, start_component_id) + except Exception as exc: + logger.error(exc) + first_layer = self.sort_vertices() + else: + first_layer = self.sort_vertices() + + for vertex_id in first_layer: + self.run_manager.add_to_vertices_being_run(vertex_id) + self._first_layer = first_layer + self._run_queue = deque(first_layer) + self._prepared = True + return self + def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]: """Returns the children of a vertex based on the vertex type.""" children = [] diff --git a/src/backend/base/langflow/inputs/input_mixin.py b/src/backend/base/langflow/inputs/input_mixin.py index 5b1f112d0..f772a256a 100644 --- a/src/backend/base/langflow/inputs/input_mixin.py +++ b/src/backend/base/langflow/inputs/input_mixin.py @@ -26,7 +26,7 @@ SerializableFieldTypes = Annotated[FieldTypes, PlainSerializer(lambda v: v.value # Base mixin for common input field attributes and methods -class BaseInputMixin(BaseModel, validate_assignment=True): +class BaseInputMixin(BaseModel, validate_assignment=True): # type: ignore model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid", populate_by_name=True) field_type: SerializableFieldTypes = Field(default=FieldTypes.TEXT) diff --git a/src/backend/base/langflow/processing/process.py b/src/backend/base/langflow/processing/process.py index 60f11b388..fbbc1b9c8 100644 --- a/src/backend/base/langflow/processing/process.py +++ b/src/backend/base/langflow/processing/process.py @@ -1,4 +1,7 @@ -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast + +from loguru import logger +from pydantic import BaseModel from langflow.graph.graph.base import Graph from langflow.graph.schema import RunOutputs @@ -6,8 +9,6 @@ from langflow.graph.vertex.base import Vertex from langflow.schema.graph import InputValue, Tweaks from langflow.schema.schema import INPUT_FIELD_NAME from langflow.services.deps import get_settings_service -from loguru import logger -from pydantic import BaseModel if TYPE_CHECKING: from langflow.api.v1.schemas import InputValueRequest @@ -112,7 +113,7 @@ def run_graph( def validate_input( - graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, Dict[str, Any]]] + graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, str | Dict[str, Any]]] ) -> List[Dict[str, Any]]: if not isinstance(graph_data, dict) or not isinstance(tweaks, dict): raise ValueError("graph_data and tweaks should be dictionaries") @@ -162,12 +163,12 @@ def process_tweaks( """ tweaks_dict = {} if not isinstance(tweaks, dict): - tweaks_dict = tweaks.model_dump() + tweaks_dict = cast(Dict[str, Any], tweaks.model_dump()) else: tweaks_dict = tweaks if "stream" not in tweaks_dict: - tweaks_dict["stream"] = stream - nodes = validate_input(graph_data, tweaks_dict) + tweaks_dict |= {"stream": stream} + nodes = validate_input(graph_data, cast(Dict[str, str | Dict[str, Any]], tweaks_dict)) nodes_map = {node.get("id"): node for node in nodes} nodes_display_name_map = {node.get("data", {}).get("node", {}).get("display_name"): node for node in nodes} diff --git a/src/backend/base/langflow/services/cache/service.py b/src/backend/base/langflow/services/cache/service.py index 26aaa0978..3d4131c23 100644 --- a/src/backend/base/langflow/services/cache/service.py +++ b/src/backend/base/langflow/services/cache/service.py @@ -13,7 +13,7 @@ from langflow.services.cache.utils import CacheMiss CACHE_MISS = CacheMiss() -class ThreadingInMemoryCache(CacheService, Generic[LockType]): +class ThreadingInMemoryCache(CacheService, Generic[LockType]): # type: ignore """ A simple in-memory cache using an OrderedDict. @@ -181,7 +181,7 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]): return f"InMemoryCache(max_size={self.max_size}, expiration_time={self.expiration_time})" -class RedisCache(AsyncBaseCacheService, Generic[LockType]): +class RedisCache(AsyncBaseCacheService, Generic[LockType]): # type: ignore """ A Redis-based cache implementation. @@ -331,7 +331,7 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]): return f"RedisCache(expiration_time={self.expiration_time})" -class AsyncInMemoryCache(AsyncBaseCacheService, Generic[AsyncLockType]): +class AsyncInMemoryCache(AsyncBaseCacheService, Generic[AsyncLockType]): # type: ignore def __init__(self, max_size=None, expiration_time=3600): self.cache = OrderedDict() diff --git a/src/backend/base/langflow/services/database/models/api_key/model.py b/src/backend/base/langflow/services/database/models/api_key/model.py index 157b08b32..1a0baaef5 100644 --- a/src/backend/base/langflow/services/database/models/api_key/model.py +++ b/src/backend/base/langflow/services/database/models/api_key/model.py @@ -20,7 +20,7 @@ class ApiKeyBase(SQLModel): is_active: bool = Field(default=True) -class ApiKey(ApiKeyBase, table=True): +class ApiKey(ApiKeyBase, table=True): # type: ignore id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) created_at: Optional[datetime] = Field( default=None, sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=False) diff --git a/src/backend/base/langflow/services/database/models/flow/model.py b/src/backend/base/langflow/services/database/models/flow/model.py index b23f16a6e..22c2d2f90 100644 --- a/src/backend/base/langflow/services/database/models/flow/model.py +++ b/src/backend/base/langflow/services/database/models/flow/model.py @@ -137,7 +137,7 @@ class FlowBase(SQLModel): return datetime.fromisoformat(v) -class Flow(FlowBase, table=True): +class Flow(FlowBase, table=True): # type: ignore id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) data: Optional[Dict] = Field(default=None, sa_column=Column(JSON)) user_id: Optional[UUID] = Field(index=True, foreign_key="user.id", nullable=True) diff --git a/src/backend/base/langflow/services/database/models/folder/model.py b/src/backend/base/langflow/services/database/models/folder/model.py index dc2dfaa80..73ba6a6e5 100644 --- a/src/backend/base/langflow/services/database/models/folder/model.py +++ b/src/backend/base/langflow/services/database/models/folder/model.py @@ -16,7 +16,7 @@ class FolderBase(SQLModel): description: Optional[str] = Field(default=None) -class Folder(FolderBase, table=True): +class Folder(FolderBase, table=True): # type: ignore id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) parent_id: Optional[UUID] = Field(default=None, foreign_key="folder.id") diff --git a/src/backend/base/langflow/services/database/models/message/model.py b/src/backend/base/langflow/services/database/models/message/model.py index 7c0b9dc8f..0f2f675be 100644 --- a/src/backend/base/langflow/services/database/models/message/model.py +++ b/src/backend/base/langflow/services/database/models/message/model.py @@ -47,7 +47,7 @@ class MessageBase(SQLModel): ) -class MessageTable(MessageBase, table=True): +class MessageTable(MessageBase, table=True): # type: ignore __tablename__ = "message" id: UUID = Field(default_factory=uuid4, primary_key=True) flow_id: Optional[UUID] = Field(default=None, foreign_key="flow.id") diff --git a/src/backend/base/langflow/services/database/models/transactions/model.py b/src/backend/base/langflow/services/database/models/transactions/model.py index b07eba15b..2b8978d80 100644 --- a/src/backend/base/langflow/services/database/models/transactions/model.py +++ b/src/backend/base/langflow/services/database/models/transactions/model.py @@ -33,7 +33,7 @@ class TransactionBase(SQLModel): return value -class TransactionTable(TransactionBase, table=True): +class TransactionTable(TransactionBase, table=True): # type: ignore __tablename__ = "transaction" id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) flow: "Flow" = Relationship(back_populates="transactions") diff --git a/src/backend/base/langflow/services/database/models/user/model.py b/src/backend/base/langflow/services/database/models/user/model.py index dfc978c27..0f71cfb4f 100644 --- a/src/backend/base/langflow/services/database/models/user/model.py +++ b/src/backend/base/langflow/services/database/models/user/model.py @@ -11,7 +11,7 @@ if TYPE_CHECKING: from langflow.services.database.models.folder import Folder -class User(SQLModel, table=True): +class User(SQLModel, table=True): # type: ignore id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True) username: str = Field(index=True, unique=True) password: str = Field() diff --git a/src/backend/base/langflow/services/database/models/variable/model.py b/src/backend/base/langflow/services/database/models/variable/model.py index 1344dc9c3..376c1c92e 100644 --- a/src/backend/base/langflow/services/database/models/variable/model.py +++ b/src/backend/base/langflow/services/database/models/variable/model.py @@ -19,7 +19,7 @@ class VariableBase(SQLModel): type: Optional[str] = Field(None, description="Type of the variable") -class Variable(VariableBase, table=True): +class Variable(VariableBase, table=True): # type: ignore id: Optional[UUID] = Field( default_factory=uuid4, primary_key=True, diff --git a/src/backend/base/langflow/services/database/models/vertex_builds/model.py b/src/backend/base/langflow/services/database/models/vertex_builds/model.py index c32cefc8d..78d582fe8 100644 --- a/src/backend/base/langflow/services/database/models/vertex_builds/model.py +++ b/src/backend/base/langflow/services/database/models/vertex_builds/model.py @@ -33,7 +33,7 @@ class VertexBuildBase(SQLModel): return value -class VertexBuildTable(VertexBuildBase, table=True): +class VertexBuildTable(VertexBuildBase, table=True): # type: ignore __tablename__ = "vertex_build" build_id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True) flow: "Flow" = Relationship(back_populates="vertex_builds") diff --git a/src/backend/base/langflow/services/database/service.py b/src/backend/base/langflow/services/database/service.py index 5dd6fe055..700e900d6 100644 --- a/src/backend/base/langflow/services/database/service.py +++ b/src/backend/base/langflow/services/database/service.py @@ -1,7 +1,7 @@ import time from datetime import datetime from pathlib import Path -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING, Optional, Type import sqlalchemy as sa from alembic import command, util @@ -133,7 +133,7 @@ class DatabaseService(Service): def check_schema_health(self) -> bool: inspector = inspect(self.engine) - model_mapping = { + model_mapping: dict[str, Type[SQLModel]] = { "flow": models.Flow, "user": models.User, "apikey": models.ApiKey, diff --git a/src/backend/base/langflow/services/plugins/langfuse_plugin.py b/src/backend/base/langflow/services/plugins/langfuse_plugin.py index ffc8139f3..b65c27733 100644 --- a/src/backend/base/langflow/services/plugins/langfuse_plugin.py +++ b/src/backend/base/langflow/services/plugins/langfuse_plugin.py @@ -1,13 +1,16 @@ -from typing import Optional +from typing import TYPE_CHECKING, Optional from loguru import logger from langflow.services.deps import get_settings_service from langflow.services.plugins.base import CallbackPlugin +if TYPE_CHECKING: + from langfuse import Langfuse # type: ignore + class LangfuseInstance: - _instance = None + _instance: Optional["Langfuse"] = None @classmethod def get(cls): diff --git a/src/backend/base/pyproject.toml b/src/backend/base/pyproject.toml index 9013a49e3..b6c1c3eb6 100644 --- a/src/backend/base/pyproject.toml +++ b/src/backend/base/pyproject.toml @@ -96,11 +96,12 @@ log_cli = true markers = ["async_test"] [tool.mypy] +plugins = ["pydantic.mypy"] +follow_imports = "skip" +disable_error_code = ["type-var"] namespace_packages = true mypy_path = "langflow" ignore_missing_imports = true -disable_error_code = ["type-var"] - [tool.ruff] exclude = ["src/backend/langflow/alembic/*"]