ref: Add ruff rules for bugbear (B) (#3983)

Add ruff rules for bugbear (B)
This commit is contained in:
Christophe Bornet 2024-10-02 18:55:51 +02:00 committed by GitHub
commit 7e3d470845
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
86 changed files with 267 additions and 230 deletions

View file

@ -1,10 +1,10 @@
from __future__ import annotations
import uuid
import warnings
from typing import TYPE_CHECKING, Any
from fastapi import HTTPException
from loguru import logger
from sqlalchemy import delete
from sqlmodel import Session
@ -101,7 +101,7 @@ async def check_langflow_version(component: StoreComponentCreate):
if langflow_version is None:
raise HTTPException(status_code=500, detail="Unable to verify the latest version of Langflow")
if langflow_version != component.last_tested_version:
warnings.warn(
logger.warning(
f"Your version of Langflow ({component.last_tested_version}) is outdated. "
f"Please update to the latest version ({langflow_version}) and try again."
)
@ -260,4 +260,4 @@ async def cascade_delete_flow(session: Session, flow: Flow):
session.exec(delete(Flow).where(Flow.id == flow.id)) # type: ignore
except Exception as e:
msg = f"Unable to cascade delete flow: ${flow.id}"
raise RuntimeError(msg, e)
raise RuntimeError(msg, e) from e

View file

@ -134,7 +134,7 @@ async def retrieve_vertices_order(
),
)
if "stream or streaming set to True" in str(exc):
raise HTTPException(status_code=400, detail=str(exc))
raise HTTPException(status_code=400, detail=str(exc)) from exc
logger.error(f"Error checking build status: {exc}")
logger.exception(exc)
raise HTTPException(status_code=500, detail=str(exc)) from exc
@ -202,7 +202,7 @@ async def build_flow(
),
)
if "stream or streaming set to True" in str(exc):
raise HTTPException(status_code=400, detail=str(exc))
raise HTTPException(status_code=400, detail=str(exc)) from exc
logger.error(f"Error checking build status: {exc}")
logger.exception(exc)
raise HTTPException(status_code=500, detail=str(exc)) from exc

View file

@ -176,7 +176,7 @@ async def simple_run_flow_task(
async def simplified_run_flow(
background_tasks: BackgroundTasks,
flow: Annotated[FlowRead | None, Depends(get_flow_by_id_or_endpoint_name)],
input_request: SimplifiedAPIRequest = SimplifiedAPIRequest(),
input_request: SimplifiedAPIRequest | None = None,
stream: bool = False,
api_key_user: UserRead = Depends(api_key_security),
telemetry_service: TelemetryService = Depends(get_telemetry_service),
@ -244,6 +244,7 @@ async def simplified_run_flow(
supporting a wide range of applications by allowing for dynamic input and output configuration along with
performance optimizations through session management and caching.
"""
input_request = input_request if input_request is not None else SimplifiedAPIRequest()
if flow is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Flow not found")
start_time = time.perf_counter()
@ -379,8 +380,8 @@ async def webhook_run_flow(
async def experimental_run_flow(
session: Annotated[Session, Depends(get_session)],
flow_id: UUID,
inputs: list[InputValueRequest] | None = [InputValueRequest(components=[], input_value="")],
outputs: list[str] | None = [],
inputs: list[InputValueRequest] | None = None,
outputs: list[str] | None = None,
tweaks: Annotated[Tweaks | None, Body(embed=True)] = None, # noqa: F821
stream: Annotated[bool, Body(embed=True)] = False, # noqa: F821
session_id: Annotated[None | str, Body(embed=True)] = None, # noqa: F821
@ -438,6 +439,8 @@ async def experimental_run_flow(
flow_id_str = str(flow_id)
if outputs is None:
outputs = []
if inputs is None:
inputs = [InputValueRequest(components=[], input_value="")]
artifacts = {}
if session_id:

View file

@ -64,7 +64,7 @@ async def upload_file(
await storage_service.save_file(flow_id=folder, file_name=full_file_name, data=file_content)
return UploadFileResponse(flowId=flow_id_str, file_path=f"{folder}/{full_file_name}")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/download/{flow_id}/{file_name}")
@ -89,7 +89,7 @@ async def download_file(file_name: str, flow_id: UUID, storage_service: StorageS
}
return StreamingResponse(BytesIO(file_content), media_type=content_type, headers=headers)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/images/{flow_id}/{file_name}")
@ -111,7 +111,7 @@ async def download_image(file_name: str, flow_id: UUID, storage_service: Storage
file_content = await storage_service.get_file(flow_id=flow_id_str, file_name=file_name)
return StreamingResponse(BytesIO(file_content), media_type=content_type)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/profile_pictures/{folder_name}/{file_name}")
@ -130,7 +130,7 @@ async def download_profile_picture(
return StreamingResponse(BytesIO(file_content), media_type=content_type)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/profile_pictures/list")
@ -151,7 +151,7 @@ async def list_profile_pictures(storage_service: StorageService = Depends(get_st
return {"files": files}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/list/{flow_id}")
@ -163,7 +163,7 @@ async def list_files(
files = await storage_service.list_files(flow_id=flow_id_str)
return {"files": files}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.delete("/delete/{flow_id}/{file_name}")
@ -175,4 +175,4 @@ async def delete_file(
await storage_service.delete_file(flow_id=flow_id_str, file_name=file_name)
return {"message": f"File {file_name} deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -74,7 +74,7 @@ def create_folder(
return new_folder
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/", response_model=list[FolderRead], status_code=200)
@ -91,7 +91,7 @@ def read_folders(
).all()
return sorted(folders, key=lambda x: x.name != DEFAULT_FOLDER_NAME)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/{folder_id}", response_model=FolderReadWithFlows, status_code=200)
@ -110,8 +110,8 @@ def read_folder(
return folder
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=404, detail="Folder not found") from e
raise HTTPException(status_code=500, detail=str(e)) from e
@router.patch("/{folder_id}", response_model=FolderRead, status_code=200)
@ -167,7 +167,7 @@ def update_folder(
return existing_folder
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.delete("/{folder_id}", status_code=204)
@ -191,7 +191,7 @@ async def delete_folder(
return Response(status_code=status.HTTP_204_NO_CONTENT)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/download/{folder_id}", response_model=FlowListReadWithFolderName, status_code=200)
@ -206,8 +206,8 @@ async def download_file(
return session.exec(select(Folder).where(Folder.id == folder_id, Folder.user_id == current_user.id)).first()
except Exception as e:
if "No result found" in str(e):
raise HTTPException(status_code=404, detail="Folder not found")
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=404, detail="Folder not found") from e
raise HTTPException(status_code=500, detail=str(e)) from e
@router.post("/upload/", response_model=list[FlowRead], status_code=201)

View file

@ -29,7 +29,7 @@ async def get_vertex_builds(
vertex_builds = get_vertex_builds_by_flow_id(session, flow_id)
return VertexBuildMapModel.from_list_of_dicts(vertex_builds)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.delete("/builds", status_code=204)
@ -40,7 +40,7 @@ async def delete_vertex_builds(
try:
delete_vertex_builds_by_flow_id(session, flow_id)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/messages", response_model=list[MessageResponse])
@ -68,7 +68,7 @@ async def get_messages(
messages = session.exec(stmt)
return [MessageResponse.model_validate(d, from_attributes=True) for d in messages]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.delete("/messages", status_code=204)
@ -81,7 +81,7 @@ async def delete_messages(
session.exec(delete(MessageTable).where(MessageTable.id.in_(message_ids))) # type: ignore
session.commit()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.put("/messages/{message_id}", response_model=MessageRead)
@ -104,7 +104,7 @@ async def update_message(
except HTTPException as e:
raise e
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.patch("/messages/session/{old_session_id}", response_model=list[MessageResponse])
@ -137,7 +137,7 @@ async def update_session_id(
except HTTPException as e:
raise e
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.delete("/messages/session/{session_id}", status_code=204)
@ -154,7 +154,7 @@ async def delete_messages_session(
session.commit()
return {"message": "Messages deleted successfully"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e
@router.get("/transactions", response_model=list[TransactionReadResponse])
@ -179,4 +179,4 @@ async def get_transactions(
for t in transactions
]
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -67,7 +67,7 @@ async def check_if_store_has_api_key(
try:
is_valid = await store_service.check_api_key(api_key)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
raise HTTPException(status_code=400, detail=str(e)) from e
return {"has_api_key": api_key is not None, "is_valid": is_valid}
@ -82,7 +82,7 @@ async def share_component(
await check_langflow_version(component)
return await store_service.upload(store_api_key, component)
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.patch("/components/{component_id}", response_model=CreateComponentResponse, status_code=201)
@ -96,7 +96,7 @@ async def update_shared_component(
await check_langflow_version(component)
return await store_service.update(store_api_key, component_id, component)
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
raise HTTPException(status_code=400, detail=str(exc)) from exc
@router.get("/components/", response_model=ListComponentResponseModel)
@ -164,7 +164,7 @@ async def get_tags(
except CustomException as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc))
raise HTTPException(status_code=500, detail=str(exc)) from exc
@router.get("/users/likes", response_model=list[UsersLikesResponse])
@ -177,7 +177,7 @@ async def get_list_of_components_liked_by_user(
except CustomException as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc))
raise HTTPException(status_code=500, detail=str(exc)) from exc
@router.post("/users/likes/{component_id}", response_model=UsersLikesResponse)
@ -194,4 +194,4 @@ async def like_component(
except CustomException as exc:
raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc))
raise HTTPException(status_code=500, detail=str(exc)) from exc

View file

@ -83,8 +83,8 @@ def update_variable(
variable=variable,
session=session,
)
except NoResultFound:
raise HTTPException(status_code=404, detail="Variable not found")
except NoResultFound as e:
raise HTTPException(status_code=404, detail="Variable not found") from e
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -1,12 +1,12 @@
from __future__ import annotations
import re
import warnings
from collections.abc import Callable
from typing import TYPE_CHECKING
from langchain_core.tools import BaseTool
from langchain_core.tools.structured import StructuredTool
from loguru import logger
from langflow.base.tools.constants import TOOL_OUTPUT_NAME
from langflow.io.schema import create_input_schema
@ -27,7 +27,7 @@ def _get_input_type(input: InputTypes):
def build_description(component: Component, output: Output):
if not output.required_inputs:
warnings.warn(f"Output {output.name} does not have required inputs defined")
logger.warning(f"Output {output.name} does not have required inputs defined")
if output.required_inputs:
args = ", ".join(

View file

@ -1,10 +1,10 @@
from __future__ import annotations
import warnings
from typing import Any
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import BaseTool, ToolException
from loguru import logger
from pydantic.v1 import BaseModel
from langflow.base.flow_processing.utils import build_data_from_result_data, format_flow_output_data
@ -45,7 +45,7 @@ class FlowTool(BaseTool):
"""Use the tool."""
args_names = get_arg_names(self.inputs)
if len(args_names) == len(args):
kwargs = {arg["arg_name"]: arg_value for arg, arg_value in zip(args_names, args)}
kwargs = {arg["arg_name"]: arg_value for arg, arg_value in zip(args_names, args, strict=True)}
elif len(args_names) != len(args) and len(args) != 0:
msg = "Number of arguments does not match the number of inputs. Pass keyword arguments instead."
raise ToolException(msg)
@ -77,7 +77,7 @@ class FlowTool(BaseTool):
raise ToolException(msg)
if len(args) == len(args_names):
kwargs = {arg_name["arg_name"]: arg_value for arg_name, arg_value in zip(args_names, args)}
kwargs = {arg_name["arg_name"]: arg_value for arg_name, arg_value in zip(args_names, args, strict=True)}
missing_args = [arg["arg_name"] for arg in args_names if arg["arg_name"] not in kwargs]
if missing_args:
@ -101,7 +101,7 @@ class FlowTool(BaseTool):
try:
run_id = self.graph.run_id if self.graph else None
except Exception as e:
warnings.warn(f"Failed to set run_id: {e}")
logger.warning(f"Failed to set run_id: {e}")
run_id = None
run_outputs = await run_flow(
tweaks={key: {"input_value": value} for key, value in tweaks.items()},

View file

@ -26,7 +26,6 @@ class AssistantsRun(Component):
if field_value is None:
thread = self.client.beta.threads.create()
self.thread_id = thread.id
field_value
build_config["thread_id"] = field_value
inputs = [
@ -92,4 +91,4 @@ class AssistantsRun(Component):
except Exception as e:
print(e)
msg = f"Error running assistant: {e}"
raise Exception(msg)
raise Exception(msg) from e

View file

@ -94,7 +94,7 @@ class APIRequestComponent(Component):
except Exception as exc:
logger.error(f"Error parsing curl: {exc}")
msg = f"Error parsing curl: {exc}"
raise ValueError(msg)
raise ValueError(msg) from exc
return build_config
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
@ -123,7 +123,7 @@ class APIRequestComponent(Component):
logger.error(f"Error decoding JSON data: {e}")
body = None
msg = f"Error decoding JSON data: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
data = body if body else None
@ -191,7 +191,10 @@ class APIRequestComponent(Component):
async with httpx.AsyncClient() as client:
results = await asyncio.gather(
*[self.make_request(client, method, u, headers, rec, timeout) for u, rec in zip(urls, bodies)]
*[
self.make_request(client, method, u, headers, rec, timeout)
for u, rec in zip(urls, bodies, strict=True)
]
)
self.status = results
return results

View file

@ -124,9 +124,9 @@ class ChatLiteLLMModelComponent(LCModelComponent):
litellm.drop_params = True
litellm.set_verbose = self.verbose
except ImportError:
except ImportError as e:
msg = "Could not import litellm python package. " "Please install it with `pip install litellm`"
raise ChatLiteLLMException(msg)
raise ChatLiteLLMException(msg) from e
# Remove empty keys
if "" in self.kwargs:
del self.kwargs[""]

View file

@ -38,10 +38,10 @@ class ExtractKeyFromDataComponent(CustomComponent):
for key in keys:
try:
extracted_keys[key] = getattr(data, key)
except AttributeError:
except AttributeError as e:
if not silent_error:
msg = f"The key '{key}' does not exist in the data."
raise KeyError(msg)
raise KeyError(msg) from e
return_data = Data(data=extracted_keys)
self.status = return_data
return return_data

View file

@ -22,7 +22,7 @@ class ShouldRunNextComponent(CustomComponent):
prompt = PromptTemplate.from_template(template)
chain = prompt | llm
error_message = ""
for i in range(retries):
for _i in range(retries):
result = chain.invoke(
{"question": question, "context": context, "error_message": error_message},
config={"callbacks": self.get_langchain_callbacks()},

View file

@ -78,7 +78,7 @@ class GoogleGenerativeAIEmbeddingsComponent(Component):
title=title,
output_dimensionality=1536,
)
for text, title in zip(batch, titles_batch)
for text, title in zip(batch, titles_batch, strict=True)
]
try:

View file

@ -55,12 +55,12 @@ class HuggingFaceInferenceAPIEmbeddingsComponent(LCEmbeddingsModel):
try:
response = requests.get(f"{inference_endpoint}/health", timeout=5)
except requests.RequestException:
except requests.RequestException as e:
msg = (
f"Inference endpoint '{inference_endpoint}' is not responding. "
"Please ensure the URL is correct and the service is running."
)
raise ValueError(msg)
raise ValueError(msg) from e
if response.status_code != 200:
msg = f"HuggingFace health check failed: {response.status_code}"

View file

@ -52,15 +52,15 @@ class NVIDIAEmbeddingsComponent(LCEmbeddingsModel):
build_config["model"]["value"] = ids[0]
except Exception as e:
msg = f"Error getting model names: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
return build_config
def build_embeddings(self) -> Embeddings:
try:
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings
except ImportError:
except ImportError as e:
msg = "Please install langchain-nvidia-ai-endpoints to use the Nvidia model."
raise ImportError(msg)
raise ImportError(msg) from e
try:
output = NVIDIAEmbeddings(
model=self.model,

View file

@ -38,9 +38,9 @@ class VertexAIEmbeddingsComponent(LCModelComponent):
def build_embeddings(self) -> Embeddings:
try:
from langchain_google_vertexai import VertexAIEmbeddings
except ImportError:
except ImportError as e:
msg = "Please install the langchain-google-vertexai package to use the VertexAIEmbeddings component."
raise ImportError(msg)
raise ImportError(msg) from e
from google.oauth2 import service_account

View file

@ -63,7 +63,7 @@ class ParseJSONDataComponent(Component):
to_filter_as_dict.append(json.loads(repair_json(f)))
except JSONDecodeError as e:
msg = f"Invalid JSON: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
full_filter_str = json.dumps(to_filter_as_dict)

View file

@ -56,11 +56,11 @@ class FirecrawlCrawlApi(CustomComponent):
) -> Data:
try:
from firecrawl.firecrawl import FirecrawlApp # type: ignore
except ImportError:
except ImportError as e:
msg = (
"Could not import firecrawl integration package. " "Please install it with `pip install firecrawl-py`."
)
raise ImportError(msg)
raise ImportError(msg) from e
crawler_options_dict = crawlerOptions.__dict__["data"]["text"] if crawlerOptions else {}
page_options_dict = pageOptions.__dict__["data"]["text"] if pageOptions else {}

View file

@ -49,11 +49,11 @@ class FirecrawlScrapeApi(CustomComponent):
) -> Data:
try:
from firecrawl.firecrawl import FirecrawlApp # type: ignore
except ImportError:
except ImportError as e:
msg = (
"Could not import firecrawl integration package. " "Please install it with `pip install firecrawl-py`."
)
raise ImportError(msg)
raise ImportError(msg) from e
extractor_options_dict = extractorOptions.__dict__["data"]["text"] if extractorOptions else {}
page_options_dict = pageOptions.__dict__["data"]["text"] if pageOptions else {}

View file

@ -114,7 +114,7 @@ class SpiderTool(Component):
raise ValueError(msg)
except Exception as e:
msg = f"Error: {str(e)}"
raise Exception(msg)
raise Exception(msg) from e
records = []

View file

@ -52,12 +52,12 @@ class AstraDBChatMemory(LCChatMemoryComponent):
def build_message_history(self) -> BaseChatMessageHistory:
try:
from langchain_astradb.chat_message_histories import AstraDBChatMessageHistory
except ImportError:
except ImportError as e:
msg = (
"Could not import langchain Astra DB integration package. "
"Please install it with `pip install langchain-astradb`."
)
raise ImportError(msg)
raise ImportError(msg) from e
return AstraDBChatMessageHistory(
session_id=self.session_id,

View file

@ -54,9 +54,9 @@ class CassandraChatMemory(LCChatMemoryComponent):
try:
import cassio
except ImportError:
except ImportError as e:
msg = "Could not import cassio integration package. " "Please install it with `pip install cassio`."
raise ImportError(msg)
raise ImportError(msg) from e
from uuid import UUID

View file

@ -34,9 +34,9 @@ class ZepChatMemory(LCChatMemoryComponent):
from zep_python.langchain import ZepChatMessageHistory
zep_python.zep_client.API_BASE_PATH = self.api_base_path
except ImportError:
except ImportError as e:
msg = "Could not import zep-python package. " "Please install it with `pip install zep-python`."
raise ImportError(msg)
raise ImportError(msg) from e
zep_client = ZepClient(api_url=self.url, api_key=self.api_key)
return ZepChatMessageHistory(session_id=self.session_id, zep_client=zep_client)

View file

@ -68,9 +68,9 @@ class AmazonBedrockComponent(LCModelComponent):
def build_model(self) -> LanguageModel: # type: ignore[type-var]
try:
from langchain_aws import ChatBedrock
except ImportError:
except ImportError as e:
msg = "langchain_aws is not installed. Please install it with `pip install langchain_aws`."
raise ImportError(msg)
raise ImportError(msg) from e
if self.aws_access_key:
import boto3 # type: ignore

View file

@ -62,9 +62,9 @@ class AnthropicModelComponent(LCModelComponent):
def build_model(self) -> LanguageModel: # type: ignore[type-var]
try:
from langchain_anthropic.chat_models import ChatAnthropic
except ImportError:
except ImportError as e:
msg = "langchain_anthropic is not installed. Please install it with `pip install langchain_anthropic`."
raise ImportError(msg)
raise ImportError(msg) from e
model = self.model
anthropic_api_key = self.anthropic_api_key
max_tokens = self.max_tokens

View file

@ -62,9 +62,9 @@ class GoogleGenerativeAIComponent(LCModelComponent):
def build_model(self) -> LanguageModel: # type: ignore[type-var]
try:
from langchain_google_genai import ChatGoogleGenerativeAI
except ImportError:
except ImportError as e:
msg = "The 'langchain_google_genai' package is required to use the Google Generative AI model."
raise ImportError(msg)
raise ImportError(msg) from e
google_api_key = self.google_api_key
model = self.model

View file

@ -66,15 +66,15 @@ class NVIDIAModelComponent(LCModelComponent):
build_config["model_name"]["value"] = ids[0]
except Exception as e:
msg = f"Error getting model names: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
return build_config
def build_model(self) -> LanguageModel: # type: ignore[type-var]
try:
from langchain_nvidia_ai_endpoints import ChatNVIDIA
except ImportError:
except ImportError as e:
msg = "Please install langchain-nvidia-ai-endpoints to use the NVIDIA model."
raise ImportError(msg)
raise ImportError(msg) from e
nvidia_api_key = self.nvidia_api_key
temperature = self.temperature
model_name: str = self.model_name

View file

@ -41,9 +41,9 @@ class ChatVertexAIComponent(LCModelComponent):
def build_model(self) -> LanguageModel:
try:
from langchain_google_vertexai import ChatVertexAI
except ImportError:
except ImportError as e:
msg = "Please install the langchain-google-vertexai package to use the VertexAIEmbeddings component."
raise ImportError(msg)
raise ImportError(msg) from e
location = self.location or None
if self.credentials:
from google.cloud import aiplatform

View file

@ -1,6 +1,7 @@
import warnings
from typing import Any
from loguru import logger
from langflow.base.langchain_utilities.model import LCToolComponent
from langflow.base.tools.flow_tool import FlowTool
from langflow.field_typing import Tool
@ -85,7 +86,7 @@ class FlowToolComponent(LCToolComponent):
try:
graph.set_run_id(self.graph.run_id)
except Exception as e:
warnings.warn(f"Failed to set run_id: {e}")
logger.warning(f"Failed to set run_id: {e}")
inputs = get_flow_inputs(graph)
tool = FlowTool(
name=self.name,

View file

@ -47,9 +47,9 @@ class JSONCleaner(Component):
def clean_json(self) -> Message:
try:
from json_repair import repair_json # type: ignore
except ImportError:
except ImportError as e:
msg = "Could not import the json_repair package." "Please install it with `pip install json_repair`."
raise ImportError(msg)
raise ImportError(msg) from e
"""Clean the input JSON string based on provided options and return the cleaned JSON string."""
json_str = self.json_str
@ -79,7 +79,7 @@ class JSONCleaner(Component):
return Message(text=result)
except Exception as e:
msg = f"Error cleaning JSON string: {str(e)}"
raise ValueError(msg)
raise ValueError(msg) from e
def _remove_control_characters(self, s: str) -> str:
"""Remove control characters from the string."""
@ -96,4 +96,4 @@ class JSONCleaner(Component):
return s
except json.JSONDecodeError as e:
msg = f"Invalid JSON string: {str(e)}"
raise ValueError(msg)
raise ValueError(msg) from e

View file

@ -49,7 +49,7 @@ class SQLExecutorComponent(CustomComponent):
database = SQLDatabase.from_uri(database_url)
except Exception as e:
msg = f"An error occurred while connecting to the database: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
try:
tool = QuerySQLDataBaseTool(db=database)
result = tool.run(query, include_columns=include_columns)

View file

@ -56,15 +56,15 @@ class NvidiaRerankComponent(LCVectorStoreComponent):
build_config["model"]["value"] = ids[0]
except Exception as e:
msg = f"Error getting model names: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
return build_config
def build_model(self):
try:
from langchain_nvidia_ai_endpoints import NVIDIARerank
except ImportError:
except ImportError as e:
msg = "Please install langchain-nvidia-ai-endpoints to use the NVIDIA model."
raise ImportError(msg)
raise ImportError(msg) from e
return NVIDIARerank(api_key=self.api_key, model=self.model, base_url=self.base_url)
def build_base_retriever(self) -> Retriever: # type: ignore[type-var]

View file

@ -38,7 +38,7 @@ class GoogleSearchAPIComponent(LCToolComponent):
def _build_wrapper(self):
try:
from langchain_google_community import GoogleSearchAPIWrapper # type: ignore
except ImportError:
except ImportError as e:
msg = "Please install langchain-google-community to use GoogleSearchAPIWrapper."
raise ImportError(msg)
raise ImportError(msg) from e
return GoogleSearchAPIWrapper(google_api_key=self.google_api_key, google_cse_id=self.google_cse_id, k=self.k)

View file

@ -61,9 +61,9 @@ class PythonREPLToolComponent(LCToolComponent):
try:
imported_module = importlib.import_module(module)
global_dict[imported_module.__name__] = imported_module
except ImportError:
except ImportError as e:
msg = f"Could not import module {module}"
raise ImportError(msg)
raise ImportError(msg) from e
return global_dict
def build_tool(self) -> Tool:

View file

@ -1,4 +1,5 @@
import json
from collections.abc import Sequence
from typing import Any
import requests
@ -87,7 +88,7 @@ class SearXNGToolComponent(LCToolComponent):
_max_results: int = 10
@staticmethod
def search(query: str, categories: list[str] = []) -> list:
def search(query: str, categories: Sequence[str] = ()) -> list:
if not SearxSearch._categories and not categories:
msg = "No categories provided."
raise ValueError(msg)

View file

@ -213,11 +213,13 @@ class AstraVectorStoreComponent(LCVectorStoreComponent):
items = list(build_config.items())
# Find the index of the key to insert after
for i, (key, value) in enumerate(items):
idx = len(items)
for i, (key, _value) in enumerate(items):
if key == field_name:
idx = i + 1
break
items.insert(i + 1, (new_field_name, new_parameter))
items.insert(idx, (new_field_name, new_parameter))
# Clear the original dictionary and update with the modified items
build_config.clear()
@ -366,21 +368,21 @@ class AstraVectorStoreComponent(LCVectorStoreComponent):
try:
from langchain_astradb import AstraDBVectorStore
from langchain_astradb.utils.astradb import SetupMode
except ImportError:
except ImportError as e:
msg = (
"Could not import langchain Astra DB integration package. "
"Please install it with `pip install langchain-astradb`."
)
raise ImportError(msg)
raise ImportError(msg) from e
try:
if not self.setup_mode:
self.setup_mode = self._inputs["setup_mode"].options[0]
setup_mode_value = SetupMode[self.setup_mode.upper()]
except KeyError:
except KeyError as e:
msg = f"Invalid setup mode: {self.setup_mode}"
raise ValueError(msg)
raise ValueError(msg) from e
if self.embedding:
embedding_dict = {"embedding": self.embedding}

View file

@ -136,9 +136,9 @@ class CassandraVectorStoreComponent(LCVectorStoreComponent):
try:
import cassio
from langchain_community.utilities.cassandra import SetupMode
except ImportError:
except ImportError as e:
msg = "Could not import cassio integration package. " "Please install it with `pip install cassio`."
raise ImportError(msg)
raise ImportError(msg) from e
from uuid import UUID
@ -234,7 +234,7 @@ class CassandraVectorStoreComponent(LCVectorStoreComponent):
"You should ingest data through Langflow (or LangChain) to query it in Langflow. "
"Your collection does not contain a field name 'content'."
)
raise ValueError(msg)
raise ValueError(msg) from e
raise e
logger.debug(f"Retrieved documents: {len(docs)}")

View file

@ -125,9 +125,9 @@ class CassandraGraphVectorStoreComponent(LCVectorStoreComponent):
try:
import cassio
from langchain_community.utilities.cassandra import SetupMode
except ImportError:
except ImportError as e:
msg = "Could not import cassio integration package. " "Please install it with `pip install cassio`."
raise ImportError(msg)
raise ImportError(msg) from e
database_ref = self.database_ref

View file

@ -106,11 +106,11 @@ class ChromaVectorStoreComponent(LCVectorStoreComponent):
try:
from chromadb import Client
from langchain_chroma import Chroma
except ImportError:
except ImportError as e:
msg = (
"Could not import Chroma integration package. " "Please install it with `pip install langchain-chroma`."
)
raise ImportError(msg)
raise ImportError(msg) from e
# Chroma settings
chroma_settings = None
client = None

View file

@ -83,7 +83,7 @@ class ClickhouseVectorStoreComponent(LCVectorStoreComponent):
client.command("SELECT 1")
except Exception as e:
msg = f"Failed to connect to Clickhouse: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
documents = []
for _input in self.ingest_data or []:

View file

@ -59,7 +59,7 @@ class CouchbaseVectorStoreComponent(LCVectorStoreComponent):
cluster.wait_until_ready(timedelta(seconds=5))
except Exception as e:
msg = f"Failed to connect to Couchbase: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
documents = []
for _input in self.ingest_data or []:

View file

@ -180,28 +180,28 @@ class HCDVectorStoreComponent(LCVectorStoreComponent):
try:
from langchain_astradb import AstraDBVectorStore
from langchain_astradb.utils.astradb import SetupMode
except ImportError:
except ImportError as e:
msg = (
"Could not import langchain Astra DB integration package. "
"Please install it with `pip install langchain-astradb`."
)
raise ImportError(msg)
raise ImportError(msg) from e
try:
from astrapy.authentication import UsernamePasswordTokenProvider
from astrapy.constants import Environment
except ImportError:
except ImportError as e:
msg = "Could not import astrapy integration package. " "Please install it with `pip install astrapy`."
raise ImportError(msg)
raise ImportError(msg) from e
try:
if not self.setup_mode:
self.setup_mode = self._inputs["setup_mode"].options[0]
setup_mode_value = SetupMode[self.setup_mode.upper()]
except KeyError:
except KeyError as e:
msg = f"Invalid setup mode: {self.setup_mode}"
raise ValueError(msg)
raise ValueError(msg) from e
if not isinstance(self.embedding, dict):
embedding_dict = {"embedding": self.embedding}

View file

@ -73,11 +73,11 @@ class MilvusVectorStoreComponent(LCVectorStoreComponent):
def build_vector_store(self):
try:
from langchain_milvus.vectorstores import Milvus as LangchainMilvus
except ImportError:
except ImportError as e:
msg = (
"Could not import Milvus integration package. " "Please install it with `pip install langchain-milvus`."
)
raise ImportError(msg)
raise ImportError(msg) from e
self.connection_args.update(uri=self.uri, token=self.password)
milvus_store = LangchainMilvus(
embedding_function=self.embedding,

View file

@ -38,16 +38,16 @@ class MongoVectorStoreComponent(LCVectorStoreComponent):
def build_vector_store(self) -> MongoDBAtlasVectorSearch:
try:
from pymongo import MongoClient
except ImportError:
except ImportError as e:
msg = "Please install pymongo to use MongoDB Atlas Vector Store"
raise ImportError(msg)
raise ImportError(msg) from e
try:
mongo_client: MongoClient = MongoClient(self.mongodb_atlas_cluster_uri)
collection = mongo_client[self.db_name][self.collection_name]
except Exception as e:
msg = f"Failed to connect to MongoDB Atlas: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
documents = []
for _input in self.ingest_data or []:

View file

@ -58,9 +58,9 @@ class VectaraVectorStoreComponent(LCVectorStoreComponent):
"""
try:
from langchain_community.vectorstores import Vectara
except ImportError:
except ImportError as e:
msg = "Could not import Vectara. Please install it with `pip install langchain-community`."
raise ImportError(msg)
raise ImportError(msg) from e
vectara = Vectara(
vectara_customer_id=self.vectara_customer_id,

View file

@ -136,9 +136,9 @@ class VectaraRagComponent(Component):
try:
from langchain_community.vectorstores import Vectara
from langchain_community.vectorstores.vectara import RerankConfig, SummaryConfig, VectaraQueryConfig
except ImportError:
except ImportError as e:
msg = "Could not import Vectara. Please install it with `pip install langchain-community`."
raise ImportError(msg)
raise ImportError(msg) from e
vectara = Vectara(self.vectara_customer_id, self.vectara_corpus_id, self.vectara_api_key)
rerank_config = RerankConfig(self.reranker, self.reranker_k, self.diversity_bias)

View file

@ -1,7 +1,7 @@
import warnings
from collections.abc import Callable
import emoji
from loguru import logger
def validate_icon(value: str, *args, **kwargs):
@ -18,7 +18,7 @@ def validate_icon(value: str, *args, **kwargs):
emoji_value = emoji.emojize(value, variant="emoji_type")
if value == emoji_value:
warnings.warn(f"Invalid emoji. {value} is not a valid emoji.")
logger.warning(f"Invalid emoji. {value} is not a valid emoji.")
return value
return emoji_value

View file

@ -217,7 +217,7 @@ class CodeParser:
defaults = missing_defaults + default_values
return [self.parse_arg(arg, default) for arg, default in zip(node.args.args, defaults)]
return [self.parse_arg(arg, default) for arg, default in zip(node.args.args, defaults, strict=True)]
def parse_varargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
"""
@ -238,7 +238,7 @@ class CodeParser:
ast.unparse(default) if default else None for default in node.args.kw_defaults
]
return [self.parse_arg(arg, default) for arg, default in zip(node.args.kwonlyargs, kw_defaults)]
return [self.parse_arg(arg, default) for arg, default in zip(node.args.kwonlyargs, kw_defaults, strict=True)]
def parse_kwargs(self, node: ast.FunctionDef) -> list[dict[str, Any]]:
"""

View file

@ -1,10 +1,10 @@
import operator
import warnings
from typing import Any, ClassVar
from uuid import UUID
from cachetools import TTLCache, cachedmethod
from fastapi import HTTPException
from loguru import logger
from langflow.custom.attributes import ATTR_FUNC_MAPPING
from langflow.custom.code_parser import CodeParser
@ -35,13 +35,13 @@ class BaseComponent:
self.cache = TTLCache(maxsize=1024, ttl=60)
for key, value in data.items():
if key == "user_id":
setattr(self, "_user_id", value)
self._user_id = value
else:
setattr(self, key, value)
def __setattr__(self, key, value):
if key == "_user_id" and hasattr(self, "_user_id") and getattr(self, "_user_id") is not None:
warnings.warn("user_id is immutable and cannot be changed.")
if key == "_user_id" and self._user_id is not None:
logger.warning("user_id is immutable and cannot be changed.")
super().__setattr__(key, value)
@cachedmethod(cache=operator.attrgetter("cache"))

View file

@ -113,7 +113,7 @@ class Component(CustomComponent):
def _reset_all_output_values(self):
if isinstance(self._outputs_map, dict):
for output in self._outputs_map.values():
setattr(output, "value", UNDEFINED)
output.value = UNDEFINED
def _build_state_model(self):
if self._state_model:
@ -164,9 +164,9 @@ class Component(CustomComponent):
raise ValueError(msg)
class_code = inspect.getsource(module)
self._code = class_code
except OSError:
except OSError as e:
msg = f"Could not find source code for {self.__class__.__name__}"
raise ValueError(msg)
raise ValueError(msg) from e
def set(self, **kwargs):
"""
@ -441,9 +441,9 @@ class Component(CustomComponent):
if callable(value) and self._inherits_from_component(value):
try:
self._method_is_valid_output(value)
except ValueError:
except ValueError as e:
msg = f"Method {value.__name__} is not a valid output of {value.__self__.__class__.__name__}"
raise ValueError(msg)
raise ValueError(msg) from e
self._connect_to_component(key, value, _input)
else:
self._set_parameter_or_attribute(key, value)
@ -569,15 +569,15 @@ class Component(CustomComponent):
for name, value in self._parameters.items():
try:
template[name]["value"] = value
except KeyError:
except KeyError as e:
close_match = find_closest_match(name, list(template.keys()))
if close_match:
msg = (
f"Parameter '{name}' not found in {self.__class__.__name__}. " f"Did you mean '{close_match}'?"
)
raise ValueError(msg)
raise ValueError(msg) from e
msg = f"Parameter {name} not found in {self.__class__.__name__}. "
raise ValueError(msg)
raise ValueError(msg) from e
def _get_method_return_type(self, method_name: str) -> list[str]:
method = getattr(self, method_name)
@ -594,7 +594,7 @@ class Component(CustomComponent):
#! works and then update this later
field_config = self.get_template_config(self)
frontend_node = ComponentFrontendNode.from_inputs(**field_config)
for key, value in self._inputs.items():
for key, _value in self._inputs.items():
frontend_node.set_field_load_from_db_in_template(key, False)
self._map_parameters_on_frontend_node(frontend_node)

View file

@ -118,7 +118,7 @@ class CustomComponent(BaseComponent):
self._vertex.graph.update_state(name=name, record=value, caller=self._vertex.id)
except Exception as e:
msg = f"Error updating state: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
def stop(self, output_name: str | None = None):
if not output_name and self._vertex and len(self._vertex.outputs) == 1:
@ -133,7 +133,7 @@ class CustomComponent(BaseComponent):
self.graph.mark_branch(vertex_id=self._vertex.id, output_name=output_name, state="INACTIVE")
except Exception as e:
msg = f"Error stopping {self.display_name}: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
def append_state(self, name: str, value: Any):
if not self._vertex:
@ -143,7 +143,7 @@ class CustomComponent(BaseComponent):
self._vertex.graph.append_state(name=name, record=value, caller=self._vertex.id)
except Exception as e:
msg = f"Error appending state: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
def get_state(self, name: str):
if not self._vertex:
@ -153,7 +153,7 @@ class CustomComponent(BaseComponent):
return self._vertex.graph.get_state(name=name)
except Exception as e:
msg = f"Error getting state: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
@staticmethod
def resolve_path(path: str) -> str:
@ -278,9 +278,9 @@ class CustomComponent(BaseComponent):
else:
try:
data_dict[key] = model_dump[key]
except KeyError:
except KeyError as e:
msg = f"Key {key} not found in {item}"
raise ValueError(msg)
raise ValueError(msg) from e
elif isinstance(item, str):
data_dict = {"text": item}
@ -512,7 +512,7 @@ class CustomComponent(BaseComponent):
return list_flows(user_id=str(self._user_id))
except Exception as e:
msg = f"Error listing flows: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
def build(self, *args: Any, **kwargs: Any) -> Any:
"""

View file

@ -324,7 +324,7 @@ class DirectoryReader:
tasks = [self.process_file_async(file_path) for file_path in file_paths]
results = await asyncio.gather(*tasks)
for file_path, (validation_result, result_content) in zip(file_paths, results):
for file_path, (validation_result, result_content) in zip(file_paths, results, strict=True):
menu_name = os.path.basename(os.path.dirname(file_path))
filename = os.path.basename(file_path)

View file

@ -2,7 +2,6 @@ import ast
import contextlib
import re
import traceback
import warnings
from typing import Any
from uuid import UUID
@ -177,7 +176,7 @@ def add_new_custom_field(
field_config["is_list"] = is_list or field_config.get("list", False) or field_contains_list
if "name" in field_config:
warnings.warn("The 'name' key in field_config is used to build the object and can't be changed.")
logger.warning("The 'name' key in field_config is used to build the object and can't be changed.")
required = field_config.pop("required", field_required)
placeholder = field_config.pop("placeholder", "")

View file

@ -5,7 +5,6 @@ import contextlib
import copy
import json
import uuid
import warnings
from collections import defaultdict, deque
from collections.abc import Generator, Iterable
from datetime import datetime, timezone
@ -263,11 +262,11 @@ class Graph:
input_field = target_vertex.get_input(input_name)
input_types = input_field.input_types
input_field_type = str(input_field.field_type)
except ValueError:
except ValueError as e:
input_field = target_vertex.data.get("node", {}).get("template", {}).get(input_name)
if not input_field:
msg = f"Input field {input_name} not found in target vertex {target_id}"
raise ValueError(msg)
raise ValueError(msg) from e
input_types = input_field.get("input_types", [])
input_field_type = input_field.get("type", "")
@ -793,7 +792,7 @@ class Graph:
types = []
for _ in range(len(inputs) - len(types)):
types.append("chat") # default to chat
for run_inputs, components, input_type in zip(inputs, inputs_components, types):
for run_inputs, components, input_type in zip(inputs, inputs_components, types, strict=True):
run_outputs = await self._run(
inputs=run_inputs,
input_components=components,
@ -1199,9 +1198,9 @@ class Graph:
"""Returns a vertex by id."""
try:
return self.vertex_map[vertex_id]
except KeyError:
except KeyError as e:
msg = f"Vertex {vertex_id} not found"
raise ValueError(msg)
raise ValueError(msg) from e
def get_root_of_group_node(self, vertex_id: str) -> Vertex:
"""Returns the root of a group node."""
@ -1646,7 +1645,7 @@ class Graph:
new_edge = self.build_edge(edge)
edges.add(new_edge)
if self.vertices and not edges:
warnings.warn("Graph has vertices but no edges")
logger.warning("Graph has vertices but no edges")
return list(cast(Iterable[CycleEdge], edges))
def build_edge(self, edge: EdgeData) -> CycleEdge | Edge:

View file

@ -62,6 +62,6 @@ def create_state_model_from_graph(graph: BaseModel) -> type[BaseModel]:
]
fields = {
camel_to_snake(vertex.id): state_model_getter
for vertex, state_model_getter in zip(graph.vertices, state_model_getters)
for vertex, state_model_getter in zip(graph.vertices, state_model_getters, strict=False)
}
return create_state_model(model_name="GraphStateModel", validate=False, **fields)

View file

@ -281,14 +281,14 @@ def sort_up_to_vertex(
"""Cuts the graph up to a given vertex and sorts the resulting subgraph."""
try:
stop_or_start_vertex = graph[vertex_id]
except KeyError:
except KeyError as e:
if parent_node_map is None:
msg = "Parent node map is required to find the root of a group node"
raise ValueError(msg)
raise ValueError(msg) from e
vertex_id = get_root_of_group_node(graph=graph, vertex_id=vertex_id, parent_node_map=parent_node_map)
if vertex_id not in graph:
msg = f"Vertex {vertex_id} not found into graph"
raise ValueError(msg)
raise ValueError(msg) from e
stop_or_start_vertex = graph[vertex_id]
visited, excluded = set(), set()

View file

@ -39,7 +39,7 @@ def list_flows(*, user_id: str | None = None) -> list[Data]:
return [flow.to_data() for flow in flows]
except Exception as e:
msg = f"Error listing flows: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
async def load_flow(
@ -161,7 +161,7 @@ def generate_function_for_flow(
# Map original argument names to their corresponding Pythonic variable names in the function
arg_mappings = ", ".join(
f'"{original_name}": {name}'
for original_name, name in zip(original_arg_names, [arg.split(":")[0] for arg in args])
for original_name, name in zip(original_arg_names, [arg.split(":")[0] for arg in args], strict=True)
)
func_body = f"""

View file

@ -78,7 +78,7 @@ def update_projects_components_with_latest_component_versions(project_data, all_
}
)
node_data["template"][key]["value"] = value["value"]
for key, value in node_data["template"].items():
for key in node_data["template"]:
if key not in latest_template:
node_data["template"][key]["input_types"] = DEFAULT_PROMPT_INTUT_TYPES
node_changes_log[node_data["display_name"]].append(
@ -359,7 +359,7 @@ def load_starter_projects(retries=3, delay=1) -> list[tuple[Path, dict]]:
attempt += 1
if attempt >= retries:
msg = f"Error loading starter project {file}: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
time.sleep(delay) # Wait before retrying
return starter_projects

View file

@ -108,10 +108,14 @@ class StrInput(BaseInputMixin, ListableInputMixin, DatabaseLoadMixin, MetadataTr
if _info.data.get("input_types") and v.__class__.__name__ not in _info.data.get("input_types"):
warnings.warn(
f"Invalid value type {type(v)} for input {_info.data.get('name')}. "
f"Expected types: {_info.data.get('input_types')}"
f"Expected types: {_info.data.get('input_types')}",
stacklevel=4,
)
else:
warnings.warn(f"Invalid value type {type(v)} for input {_info.data.get('name')}.")
warnings.warn(
f"Invalid value type {type(v)} for input {_info.data.get('name')}.",
stacklevel=4,
)
return v
@field_validator("value")

View file

@ -36,9 +36,7 @@ def update_memory_keys(langchain_object, possible_new_mem_key):
if key not in [langchain_object.memory.memory_key, possible_new_mem_key]
][0]
keys = [input_key, output_key, possible_new_mem_key]
attrs = ["input_key", "output_key", "memory_key"]
for key, attr in zip(keys, attrs):
for key, attr in [(input_key, "input_key"), (output_key, "output_key"), (possible_new_mem_key, "memory_key")]:
try:
setattr(langchain_object.memory, attr, key)
except ValueError as exc:

View file

@ -28,7 +28,7 @@ def upload(file_path, host, flow_id):
raise Exception(msg)
except Exception as e:
msg = f"Error uploading file: {e}"
raise Exception(msg)
raise Exception(msg) from e
def upload_file(file_path: str, host: str, flow_id: str, components: list[str], tweaks: dict | None = None):
@ -65,7 +65,7 @@ def upload_file(file_path: str, host: str, flow_id: str, components: list[str],
raise ValueError(msg)
except Exception as e:
msg = f"Error uploading file: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
def get_flow(url: str, flow_id: str):
@ -92,4 +92,4 @@ def get_flow(url: str, flow_id: str):
raise Exception(msg)
except Exception as e:
msg = f"Error retrieving flow: {e}"
raise Exception(msg)
raise Exception(msg) from e

View file

@ -78,7 +78,7 @@ class SizedLogBuffer:
with self._wlock:
as_list = list(self.buffer)
max_index = -1
for i, (ts, msg) in enumerate(as_list):
for i, (ts, _) in enumerate(as_list):
if ts >= timestamp:
max_index = i
break

View file

@ -1,4 +1,3 @@
import warnings
from collections.abc import Sequence
from uuid import UUID
@ -124,7 +123,7 @@ def store_message(
ValueError: If any of the required parameters (session_id, sender, sender_name) is not provided.
"""
if not message:
warnings.warn("No message provided.")
logger.warning("No message provided.")
return []
if not message.session_id or not message.sender or not message.sender_name:

View file

@ -164,10 +164,10 @@ class Data(BaseModel):
if key in {"data", "text_key"} or key.startswith("_"):
return super().__getattr__(key)
return self.data[key]
except KeyError:
except KeyError as e:
# Fallback to default behavior to raise AttributeError for undefined attributes
msg = f"'{type(self).__name__}' object has no attribute '{key}'"
raise AttributeError(msg)
raise AttributeError(msg) from e
def __setattr__(self, key, value):
"""

View file

@ -29,9 +29,9 @@ class dotdict(dict):
value = dotdict(value)
self[attr] = value # Update self to nest dotdict for future accesses
return value
except KeyError:
except KeyError as e:
msg = f"'dotdict' object has no attribute '{attr}'"
raise AttributeError(msg)
raise AttributeError(msg) from e
def __setattr__(self, key, value):
"""
@ -57,9 +57,9 @@ class dotdict(dict):
"""
try:
del self[key]
except KeyError:
except KeyError as e:
msg = f"'dotdict' object has no attribute '{key}'"
raise AttributeError(msg)
raise AttributeError(msg) from e
def __missing__(self, key):
"""

View file

@ -31,9 +31,9 @@ def _timestamp_to_str(timestamp: datetime | str) -> str:
try:
datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
return timestamp
except ValueError:
except ValueError as e:
msg = f"Invalid timestamp: {timestamp}"
raise ValueError(msg)
raise ValueError(msg) from e
return timestamp.strftime("%Y-%m-%d %H:%M:%S")

View file

@ -23,7 +23,7 @@ class Service(ABC):
return schema
async def teardown(self):
pass
return
def set_ready(self):
self.ready = True

View file

@ -1,7 +1,6 @@
# Path: src/backend/langflow/services/database/models/flow/model.py
import re
import warnings
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Optional
from uuid import UUID, uuid4
@ -9,6 +8,7 @@ from uuid import UUID, uuid4
import emoji
from emoji import purely_emoji # type: ignore
from fastapi import HTTPException, status
from loguru import logger
from pydantic import field_serializer, field_validator
from sqlalchemy import Text, UniqueConstraint
from sqlmodel import JSON, Column, Field, Relationship, SQLModel
@ -88,8 +88,7 @@ class FlowBase(SQLModel):
emoji_value = emoji.emojize(v, variant="emoji_type")
if v == emoji_value:
warnings.warn(f"Invalid emoji. {v} is not a valid emoji.")
icon = v
logger.warning(f"Invalid emoji. {v} is not a valid emoji.")
icon = emoji_value
if purely_emoji(icon):

View file

@ -220,7 +220,7 @@ class DatabaseService(Service):
logger.error(f"AutogenerateDiffsDetected: {exc}")
if not fix:
msg = f"There's a mismatch between the models and the database.\n{exc}"
raise RuntimeError(msg)
raise RuntimeError(msg) from exc
if fix:
self.try_downgrade_upgrade_until_success(alembic_cfg)

View file

@ -54,9 +54,9 @@ def infer_service_types(factory_class: type[ServiceFactory], available_services=
# Attempt to find a matching enum value
service_type = ServiceType[type_name]
service_types.append(service_type)
except KeyError:
except KeyError as e:
msg = f"No matching ServiceType for parameter type: {param_type.__name__}"
raise ValueError(msg)
raise ValueError(msg) from e
return service_types

View file

@ -132,7 +132,7 @@ class ServiceManager:
module = importlib.import_module(module_name)
# Find all classes in the module that are subclasses of ServiceFactory
for name, obj in inspect.getmembers(module, inspect.isclass):
for _, obj in inspect.getmembers(module, inspect.isclass):
if issubclass(obj, ServiceFactory) and obj is not ServiceFactory:
factories.append(obj())
break

View file

@ -44,7 +44,7 @@ async def user_data_context(store_service: StoreService, api_key: str | None = N
except HTTPStatusError as exc:
if exc.response.status_code == 403:
msg = "Invalid API key"
raise ValueError(msg)
raise ValueError(msg) from exc
try:
yield
finally:
@ -119,10 +119,10 @@ class StoreService(Service):
if exc.response.status_code in [403, 401]:
return False
msg = f"Unexpected status code: {exc.response.status_code}"
raise ValueError(msg)
raise ValueError(msg) from exc
except Exception as exc:
msg = f"Unexpected error: {exc}"
raise ValueError(msg)
raise ValueError(msg) from exc
async def _get(
self, url: str, api_key: str | None = None, params: dict[str, Any] | None = None
@ -137,7 +137,7 @@ class StoreService(Service):
raise exc
except Exception as exc:
msg = f"GET failed: {exc}"
raise ValueError(msg)
raise ValueError(msg) from exc
json_response = response.json()
result = json_response["data"]
metadata = {}
@ -355,9 +355,9 @@ class StoreService(Service):
# If it is, we need to build the metadata
try:
download_component.metadata = process_component_data(download_component.data.get("nodes", []))
except KeyError:
except KeyError as e:
msg = "Invalid component data. No nodes found"
raise ValueError(msg)
raise ValueError(msg) from e
return download_component
async def upload(self, api_key: str, component_data: StoreComponentCreate) -> CreateComponentResponse:
@ -392,7 +392,7 @@ class StoreService(Service):
except UnboundLocalError:
pass
msg = f"Upload failed: {exc}"
raise ValueError(msg)
raise ValueError(msg) from exc
async def update(
self, api_key: str, component_id: UUID, component_data: StoreComponentCreate
@ -429,7 +429,7 @@ class StoreService(Service):
except UnboundLocalError:
pass
msg = f"Upload failed: {exc}"
raise ValueError(msg)
raise ValueError(msg) from exc
async def get_tags(self) -> list[dict[str, Any]]:
url = f"{self.base_url}/items/tags"
@ -460,9 +460,9 @@ class StoreService(Service):
# try to convert it to int
try:
likes = int(likes)
except ValueError:
except ValueError as e:
msg = f"Unexpected value for likes count: {likes}"
raise ValueError(msg)
raise ValueError(msg) from e
return likes
async def like_component(self, api_key: str, component_id: str) -> bool:
@ -567,10 +567,10 @@ class StoreService(Service):
except HTTPStatusError as exc:
if exc.response.status_code == 403:
msg = "You are not authorized to access this public resource"
raise ForbiddenError(msg)
raise ForbiddenError(msg) from exc
if exc.response.status_code == 401:
msg = "You are not authorized to access this resource. Please check your API key."
raise APIKeyError(msg)
raise APIKeyError(msg) from exc
if store_api_key:
# Now, from the result, we need to get the components

View file

@ -1,6 +1,7 @@
from __future__ import annotations
from abc import ABC, abstractmethod
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any
from uuid import UUID
@ -40,7 +41,7 @@ class BaseTracer(ABC):
trace_name: str,
outputs: dict[str, Any] | None = None,
error: Exception | None = None,
logs: list[Log | dict] = [],
logs: Sequence[Log | dict] = (),
):
raise NotImplementedError

View file

@ -1,6 +1,7 @@
from __future__ import annotations
import os
from collections.abc import Sequence
from datetime import datetime
from typing import TYPE_CHECKING, Any
from uuid import UUID
@ -100,7 +101,7 @@ class LangFuseTracer(BaseTracer):
trace_name: str,
outputs: dict[str, Any] | None = None,
error: Exception | None = None,
logs: list[Log | dict] = [],
logs: Sequence[Log | dict] = (),
):
end_time = datetime.utcnow()
if not self._ready:
@ -111,7 +112,7 @@ class LangFuseTracer(BaseTracer):
_output: dict = {}
_output |= outputs if outputs else {}
_output |= {"error": str(error)} if error else {}
_output |= {"logs": logs} if logs else {}
_output |= {"logs": list(logs)} if logs else {}
content = {"output": _output, "end_time": end_time}
span.update(**content)

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import os
import traceback
import types
from collections.abc import Sequence
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any
from uuid import UUID
@ -119,7 +120,7 @@ class LangSmithTracer(BaseTracer):
trace_name: str,
outputs: dict[str, Any] | None = None,
error: Exception | None = None,
logs: list[Log | dict] = [],
logs: Sequence[Log | dict] = (),
):
if not self._ready:
return

View file

@ -1,5 +1,6 @@
from __future__ import annotations
from collections.abc import Sequence
from typing import TYPE_CHECKING, Any, cast
from uuid import UUID
@ -103,7 +104,7 @@ class LangWatchTracer(BaseTracer):
trace_name: str,
outputs: dict[str, Any] | None = None,
error: Exception | None = None,
logs: list[Log | dict] = [],
logs: Sequence[Log | dict] = (),
):
if not self._ready:
return

View file

@ -1,6 +1,7 @@
from __future__ import annotations
import os
from collections.abc import Sequence
from datetime import datetime, timezone
from typing import TYPE_CHECKING
from uuid import UUID
@ -165,7 +166,7 @@ class DatabaseVariableService(VariableService, Service):
user_id: UUID | str,
name: str,
value: str,
default_fields: list[str] = [],
default_fields: Sequence[str] = (),
_type: str = GENERIC_TYPE,
session: Session = Depends(get_session),
):
@ -173,7 +174,7 @@ class DatabaseVariableService(VariableService, Service):
name=name,
type=_type,
value=auth_utils.encrypt_api_key(value, settings_service=self.settings_service),
default_fields=default_fields,
default_fields=list(default_fields),
)
variable = Variable.model_validate(variable_base, from_attributes=True, update={"user_id": user_id})
session.add(variable)

View file

@ -53,7 +53,7 @@ class Template(BaseModel):
_input = instantiate_input(input_type, value)
except Exception as e:
msg = f"Error instantiating input {input_type}: {e}"
raise ValueError(msg)
raise ValueError(msg) from e
else:
_input = Input(**value)

View file

@ -217,9 +217,9 @@ def prepare_global_scope(code, module):
imported_module = importlib.import_module(node.module)
for alias in node.names:
exec_globals[alias.name] = getattr(imported_module, alias.name)
except ModuleNotFoundError:
except ModuleNotFoundError as e:
msg = f"Module {node.module} not found. Please install it and try again"
raise ModuleNotFoundError(msg)
raise ModuleNotFoundError(msg) from e
return exec_globals

View file

@ -74,20 +74,18 @@ def fetch_latest_version(package_name: str, include_prerelease: bool) -> str | N
from packaging import version as pkg_version
package_name = package_name.replace(" ", "-").lower()
valid_versions = []
try:
response = httpx.get(f"https://pypi.org/pypi/{package_name}/json")
versions = response.json()["releases"].keys()
valid_versions = [v for v in versions if include_prerelease or not is_pre_release(v)]
except Exception as e:
logger.exception(e)
finally:
if not valid_versions:
return None # Handle case where no valid versions are found
return max(valid_versions, key=lambda v: pkg_version.parse(v))
except Exception as e:
logger.exception(e)
return None
def get_version_info():
return VERSION_INFO

View file

@ -149,8 +149,15 @@ exclude = ["langflow/alembic"]
line-length = 120
[tool.ruff.lint]
flake8-bugbear.extend-immutable-calls = [
"fastapi.Depends",
"fastapi.File",
"fastapi.Query",
"typer.Option",
]
select = [
"ASYNC",
"B",
"C4",
"COM",
"DJ",

View file

@ -11,6 +11,9 @@ from typing import TYPE_CHECKING
import orjson
import pytest
from loguru import logger
from pytest import LogCaptureFixture
from base.langflow.components.inputs.ChatInput import ChatInput
from dotenv import load_dotenv
from fastapi.testclient import TestClient
@ -79,6 +82,19 @@ def get_text():
assert path.exists(), f"File {path} does not exist. Available files: {list(data_path.iterdir())}"
@pytest.fixture
def caplog(caplog: LogCaptureFixture):
handler_id = logger.add(
caplog.handler,
format="{message}",
level=0,
filter=lambda record: record["level"].no >= caplog.handler.level,
enqueue=False, # Set to 'True' if your test is spawning child processes.
)
yield caplog
logger.remove(handler_id)
@pytest.fixture()
async def async_client() -> AsyncGenerator:
from langflow.main import create_app

View file

@ -1,6 +1,8 @@
import logging
from collections import deque
import pytest
from pytest import LogCaptureFixture
from langflow.components.agents.ToolCallingAgent import ToolCallingAgentComponent
from langflow.components.inputs.ChatInput import ChatInput
@ -28,14 +30,16 @@ async def test_graph_not_prepared():
@pytest.mark.asyncio
async def test_graph():
async def test_graph(caplog: LogCaptureFixture):
chat_input = ChatInput()
chat_output = ChatOutput()
graph = Graph()
graph.add_component(chat_input)
graph.add_component(chat_output)
with pytest.warns(UserWarning, match="Graph has vertices but no edges"):
caplog.clear()
with caplog.at_level(logging.WARNING):
graph.prepare()
assert "Graph has vertices but no edges" in caplog.text
@pytest.mark.asyncio