ref: Some ruff fixes from preview (#5420)

* Some ruff fixes from preview

* [autofix.ci] apply automated fixes

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

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Christophe Bornet 2024-12-28 22:25:35 +01:00 committed by GitHub
commit e91bcc2520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
79 changed files with 402 additions and 374 deletions

View file

@ -90,7 +90,7 @@ class AgentQL(Component):
except httpx.HTTPStatusError as e:
response = e.response
if response.status_code in [401, 403]:
if response.status_code in {401, 403}:
self.status = "Please, provide a valid API Key. You can create one at https://dev.agentql.com."
else:
try:

View file

@ -71,7 +71,7 @@ class DirectoryComponent(Component):
def load_directory(self) -> list[Data]:
path = self.path
types = self.types if self.types else TEXT_FILE_TYPES
types = self.types or TEXT_FILE_TYPES
depth = self.depth
max_concurrency = self.max_concurrency
load_hidden = self.load_hidden

View file

@ -131,12 +131,12 @@ class LangWatchComponent(Component):
# Clear component's dynamic attributes
for attr in list(self.__dict__.keys()):
if attr not in default_keys and attr not in [
if attr not in default_keys and attr not in {
"evaluators",
"dynamic_inputs",
"_code",
"current_evaluator",
]:
}:
delattr(self, attr)
# Add new dynamic inputs
@ -177,7 +177,7 @@ class LangWatchComponent(Component):
input_fields = [
field
for field in evaluator.get("requiredFields", []) + evaluator.get("optionalFields", [])
if field not in ["input", "output"]
if field not in {"input", "output"}
]
for field in input_fields:

View file

@ -126,8 +126,7 @@ class ConditionalRouterComponent(Component):
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict:
if field_name == "operator":
if field_value == "matches regex":
if "case_sensitive" in build_config:
del build_config["case_sensitive"]
build_config.pop("case_sensitive", None)
# Ensure case_sensitive is present for all other operators
elif "case_sensitive" not in build_config:
case_sensitive_input = next(

View file

@ -22,7 +22,7 @@ class OpenRouterComponent(LCModelComponent):
display_name = "OpenRouter"
description = (
"OpenRouter provides unified access to multiple AI models " "from different providers through a single API."
"OpenRouter provides unified access to multiple AI models from different providers through a single API."
)
icon = "OpenRouter"
@ -180,9 +180,7 @@ class OpenRouterComponent(LCModelComponent):
build_config["model_name"]["value"] = models[0]["id"]
tooltips = {
model["id"]: (
f"{model['name']}\n" f"Context Length: {model['context_length']}\n" f"{model['description']}"
)
model["id"]: (f"{model['name']}\nContext Length: {model['context_length']}\n{model['description']}")
for model in models
}
build_config["model_name"]["tooltips"] = tooltips

View file

@ -10,7 +10,7 @@ from langflow.utils.constants import MESSAGE_SENDER_AI
class NeedleComponent(Component):
display_name = "Needle Retriever"
description = "A retriever that uses the Needle API to search collections " "and generates responses using OpenAI."
description = "A retriever that uses the Needle API to search collections and generates responses using OpenAI."
documentation = "https://docs.needle-ai.com"
icon = "search"
name = "needle"
@ -105,8 +105,8 @@ class NeedleComponent(Component):
if str(output_type).lower().strip() == "chunks":
# If chunks selected, include full context and answer
docs = result["source_documents"]
context = "\n\n".join([f"Document {i+1}:\n{doc.page_content}" for i, doc in enumerate(docs)])
text_content = f"Question: {query}\n\n" f"Context:\n{context}\n\n" f"Answer: {result['answer']}"
context = "\n\n".join([f"Document {i + 1}:\n{doc.page_content}" for i, doc in enumerate(docs)])
text_content = f"Question: {query}\n\nContext:\n{context}\n\nAnswer: {result['answer']}"
else:
# If answer selected, only include the answer
text_content = result["answer"]

View file

@ -144,7 +144,7 @@ class DataFrameOperationsComponent(Component):
build_config["new_column_value"]["show"] = True
elif field_value == "Select Columns":
build_config["columns_to_select"]["show"] = True
elif field_value in ["Head", "Tail"]:
elif field_value in {"Head", "Tail"}:
build_config["num_rows"]["show"] = True
elif field_value == "Replace Value":
build_config["column_name"]["show"] = True

View file

@ -74,7 +74,7 @@ class MergeDataComponent(Component):
for key, value in data_input.data.items():
if key in result_data and isinstance(value, str):
if isinstance(result_data[key], list):
cast(list[str], result_data[key]).append(value)
cast("list[str]", result_data[key]).append(value)
else:
result_data[key] = [result_data[key], value]
else:

View file

@ -295,7 +295,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
# Always attempt to update the database list
if field_name in ["token", "api_endpoint", "collection_name"]:
if field_name in {"token", "api_endpoint", "collection_name"}:
# Update the database selector
build_config["api_endpoint"]["options"] = self._initialize_database_options()

View file

@ -1101,7 +1101,8 @@ class Graph:
return False
return self.vertex_edges_are_identical(vertex, other_vertex)
def vertex_edges_are_identical(self, vertex: Vertex, other_vertex: Vertex) -> bool:
@staticmethod
def vertex_edges_are_identical(vertex: Vertex, other_vertex: Vertex) -> bool:
same_length = len(vertex.edges) == len(other_vertex.edges)
if not same_length:
return False
@ -1747,7 +1748,8 @@ class Graph:
new_edge = Edge(source, target, edge)
return new_edge
def _get_vertex_class(self, node_type: str, node_base_type: str, node_id: str) -> type[Vertex]:
@staticmethod
def _get_vertex_class(node_type: str, node_base_type: str, node_id: str) -> type[Vertex]:
"""Returns the node class based on the node type."""
# First we check for the node_base_type
node_name = node_id.split("-")[0]
@ -1830,7 +1832,8 @@ class Graph:
self._record_snapshot()
return self
def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> list[Vertex]:
@staticmethod
def get_children_by_vertex_type(vertex: Vertex, vertex_type: str) -> list[Vertex]:
"""Returns the children of a vertex based on the vertex type."""
children = []
vertex_types = [vertex.data["type"]]
@ -2059,7 +2062,8 @@ class Graph:
self._first_layer = first_layer
return first_layer
def sort_interface_components_first(self, vertices_layers: list[list[str]]) -> list[list[str]]:
@staticmethod
def sort_interface_components_first(vertices_layers: list[list[str]]) -> list[list[str]]:
"""Sorts the vertices in the graph so that vertices containing ChatInput or ChatOutput come first."""
def contains_interface_component(vertex):
@ -2097,9 +2101,6 @@ class Graph:
This method is responsible for building the run map for the graph,
which maps each node in the graph to its corresponding run function.
Returns:
None
"""
self.run_manager.build_run_map(predecessor_map=self.predecessor_map, vertices_to_run=self.vertices_to_run)
@ -2169,7 +2170,8 @@ class Graph:
in_degree[vertex.id] = 0
return in_degree
def build_adjacency_maps(self, edges: list[CycleEdge]) -> tuple[dict[str, list[str]], dict[str, list[str]]]:
@staticmethod
def build_adjacency_maps(edges: list[CycleEdge]) -> tuple[dict[str, list[str]], dict[str, list[str]]]:
"""Returns the adjacency maps for the graph."""
predecessor_map: dict[str, list[str]] = defaultdict(list)
successor_map: dict[str, list[str]] = defaultdict(list)

View file

@ -110,9 +110,6 @@ def update_template(template, g_nodes) -> None:
Args:
template (dict): The new template to update the node with.
g_nodes (list): The list of nodes in the graph.
Returns:
None
"""
for value in template.values():
if not value.get("proxy"):
@ -161,9 +158,6 @@ def set_new_target_handle(proxy_id, new_edge, target_handle, node) -> None:
new_edge (dict): The new edge to be created.
target_handle (dict): The target handle of the edge.
node (dict): The node containing the edge.
Returns:
None
"""
new_edge["target"] = proxy_id
type_ = target_handle.get("type")

View file

@ -423,7 +423,7 @@ class Vertex:
else:
msg = f"Invalid value type {type(val)} for field {field_name}"
raise ValueError(msg)
elif val is not None and val != "":
elif val:
params[field_name] = val
if field.get("load_from_db"):
@ -596,7 +596,8 @@ class Vertex:
result = await value.get_result(self, target_handle_name=key)
self.params[key][sub_key] = result
def _is_vertex(self, value):
@staticmethod
def _is_vertex(value):
"""Checks if the provided value is an instance of Vertex."""
return isinstance(value, Vertex)

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,5 @@
from typing_extensions import override
from langflow.services.deps import get_settings_service
from langflow.utils.lazy_load import LazyLoadDictBase
@ -13,6 +15,7 @@ class AllTypesDict(LazyLoadDictBase):
"Custom": ["Custom Tool", "Python Function"],
}
@override
def get_type_dict(self):
from langflow.interface.types import get_all_types_dict

View file

@ -15,7 +15,7 @@ from loguru._file_sink import FileSink
from loguru._simple_sinks import AsyncSink
from platformdirs import user_cache_dir
from rich.logging import RichHandler
from typing_extensions import NotRequired
from typing_extensions import NotRequired, override
from langflow.settings import DEV
@ -285,6 +285,7 @@ class InterceptHandler(logging.Handler):
See https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging.
"""
@override
def emit(self, record) -> None:
# Get corresponding Loguru level if it exists
try:

View file

@ -19,7 +19,7 @@ from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from pydantic import PydanticDeprecatedSince20
from pydantic_core import PydanticSerializationError
from rich import print as rprint
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from langflow.api import health_check_router, log_router, router
from langflow.initial_setup.setup import (
@ -45,7 +45,7 @@ class RequestCancelledMiddleware(BaseHTTPMiddleware):
def __init__(self, app) -> None:
super().__init__(app)
async def dispatch(self, request: Request, call_next):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
sentinel = object()
async def cancel_handler():
@ -68,7 +68,7 @@ class RequestCancelledMiddleware(BaseHTTPMiddleware):
class JavaScriptMIMETypeMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
try:
response = await call_next(request)
except Exception as exc:

View file

@ -26,7 +26,8 @@ class ContentSizeLimitMiddleware:
self.app = app
self.logger = logger
def receive_wrapper(self, receive):
@staticmethod
def receive_wrapper(receive):
received = 0
async def inner():

View file

@ -32,7 +32,7 @@ class DataFrame(pandas_DataFrame):
>>> dataset = DataFrame({"name": ["John", "Jane"], "age": [30, 25]})
"""
def __init__(self, data: None | list[dict | Data] | dict | pd.DataFrame = None, **kwargs):
def __init__(self, data: list[dict | Data] | dict | pd.DataFrame | None = None, **kwargs):
if data is None:
super().__init__(**kwargs)
return

View file

@ -6,7 +6,7 @@ from typing_extensions import Protocol
from langflow.schema.message import ContentBlock, Message
from langflow.schema.playground_events import PlaygroundEvent
LoggableType: TypeAlias = str | dict | list | int | float | bool | None | BaseModel | PlaygroundEvent
LoggableType: TypeAlias = str | dict | list | int | float | bool | BaseModel | PlaygroundEvent | None
class LogFunctionType(Protocol):

View file

@ -1,3 +1,5 @@
from typing_extensions import override
from langflow.services.auth.service import AuthService
from langflow.services.factory import ServiceFactory
@ -8,5 +10,6 @@ class AuthServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(AuthService)
@override
def create(self, settings_service):
return AuthService(settings_service)

View file

@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.logging.logger import logger
from langflow.services.cache.disk import AsyncDiskCache
from langflow.services.cache.service import AsyncInMemoryCache, CacheService, RedisCache, ThreadingInMemoryCache
@ -15,6 +17,7 @@ class CacheServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(CacheService)
@override
def create(self, settings_service: SettingsService):
# Here you would have logic to create and configure a CacheService
# based on the settings_service

View file

@ -187,7 +187,8 @@ class DatabaseService(Service):
await session.commit()
logger.debug("Successfully assigned orphaned flows to the default superuser")
def _generate_unique_flow_name(self, original_name: str, existing_names: set[str]) -> str:
@staticmethod
def _generate_unique_flow_name(original_name: str, existing_names: set[str]) -> str:
"""Generate a unique flow name by adding or incrementing a suffix."""
if original_name not in existing_names:
return original_name
@ -212,7 +213,8 @@ class DatabaseService(Service):
return new_name
def _check_schema_health(self, connection) -> bool:
@staticmethod
def _check_schema_health(connection) -> bool:
inspector = inspect(connection)
model_mapping: dict[str, type[SQLModel]] = {
@ -249,7 +251,8 @@ class DatabaseService(Service):
async with self.with_session() as session, session.bind.connect() as conn:
await conn.run_sync(self._check_schema_health)
def init_alembic(self, alembic_cfg) -> None:
@staticmethod
def init_alembic(alembic_cfg) -> None:
logger.info("Initializing alembic")
command.ensure_version(alembic_cfg)
# alembic_cfg.attributes["connection"].commit()
@ -317,7 +320,8 @@ class DatabaseService(Service):
should_initialize_alembic = True
await asyncio.to_thread(self._run_migrations, should_initialize_alembic, fix)
def try_downgrade_upgrade_until_success(self, alembic_cfg, retries=5) -> None:
@staticmethod
def try_downgrade_upgrade_until_success(alembic_cfg, retries=5) -> None:
# Try -1 then head, if it fails, try -2 then head, etc.
# until we reach the number of retries
for i in range(1, retries + 1):

View file

@ -1,5 +1,7 @@
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.session.service import SessionService
@ -11,5 +13,6 @@ class SessionServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(SessionService)
@override
def create(self, cache_service: "CacheService"):
return SessionService(cache_service)

View file

@ -38,7 +38,8 @@ class SessionService(Service):
return graph, artifacts
def build_key(self, session_id, data_graph) -> str:
@staticmethod
def build_key(session_id, data_graph) -> str:
json_hash = compute_dict_hash(data_graph)
return f"{session_id}{':' if session_id else ''}{json_hash}"

View file

@ -1,3 +1,5 @@
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.settings.service import SettingsService
@ -13,6 +15,7 @@ class SettingsServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(SettingsService)
@override
def create(self):
# Here you would have logic to create and configure a SettingsService

View file

@ -1,5 +1,7 @@
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.shared_component_cache.service import SharedComponentCacheService
@ -11,5 +13,6 @@ class SharedComponentCacheServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(SharedComponentCacheService)
@override
def create(self, settings_service: "SettingsService"):
return SharedComponentCacheService(expiration_time=settings_service.settings.cache_expire)

View file

@ -1,5 +1,7 @@
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.socket.service import SocketIOService
@ -13,5 +15,6 @@ class SocketIOFactory(ServiceFactory):
service_class=SocketIOService,
)
@override
def create(self, cache_service: "CacheService"):
return SocketIOService(cache_service)

View file

@ -1,3 +1,5 @@
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.settings.service import SettingsService
from langflow.services.state.service import InMemoryStateService
@ -7,6 +9,7 @@ class StateServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(InMemoryStateService)
@override
def create(self, settings_service: SettingsService):
return InMemoryStateService(
settings_service,

View file

@ -1,4 +1,5 @@
from loguru import logger
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.session.service import SessionService
@ -12,6 +13,7 @@ class StorageServiceFactory(ServiceFactory):
StorageService,
)
@override
def create(self, session_service: SessionService, settings_service: SettingsService):
storage_type = settings_service.settings.storage_type
if storage_type.lower() == "local":

View file

@ -21,12 +21,15 @@ class LocalStorageService(StorageService):
async def save_file(self, flow_id: str, file_name: str, data: bytes) -> None:
"""Save a file in the local storage.
:param flow_id: The identifier for the flow.
:param file_name: The name of the file to be saved.
:param data: The byte content of the file.
:raises FileNotFoundError: If the specified flow does not exist.
:raises IsADirectoryError: If the file name is a directory.
:raises PermissionError: If there is no permission to write the file.
Args:
flow_id: The identifier for the flow.
file_name: The name of the file to be saved.
data: The byte content of the file.
Raises:
FileNotFoundError: If the specified flow does not exist.
IsADirectoryError: If the file name is a directory.
PermissionError: If there is no permission to write the file.
"""
folder_path = self.data_dir / flow_id
await folder_path.mkdir(parents=True, exist_ok=True)
@ -43,10 +46,15 @@ class LocalStorageService(StorageService):
async def get_file(self, flow_id: str, file_name: str) -> bytes:
"""Retrieve a file from the local storage.
:param flow_id: The identifier for the flow.
:param file_name: The name of the file to be retrieved.
:return: The byte content of the file.
:raises FileNotFoundError: If the file does not exist.
Args:
flow_id: The identifier for the flow.
file_name: The name of the file to be retrieved.
Returns:
The byte content of the file.
Raises:
FileNotFoundError: If the file does not exist.
"""
file_path = self.data_dir / flow_id / file_name
if not await file_path.exists():
@ -63,9 +71,14 @@ class LocalStorageService(StorageService):
async def list_files(self, flow_id: str):
"""List all files in a specified flow.
:param flow_id: The identifier for the flow.
:return: A list of file names.
:raises FileNotFoundError: If the flow directory does not exist.
Args:
flow_id: The identifier for the flow.
Returns:
A list of file names.
Raises:
FileNotFoundError: If the flow directory does not exist.
"""
if not isinstance(flow_id, str):
flow_id = str(flow_id)

View file

@ -18,10 +18,13 @@ class S3StorageService(StorageService):
async def save_file(self, folder: str, file_name: str, data) -> None:
"""Save a file to the S3 bucket.
:param folder: The folder in the bucket to save the file.
:param file_name: The name of the file to be saved.
:param data: The byte content of the file.
:raises Exception: If an error occurs during file saving.
Args:
folder: The folder in the bucket to save the file.
file_name: The name of the file to be saved.
data: The byte content of the file.
Raises:
Exception: If an error occurs during file saving.
"""
try:
self.s3_client.put_object(Bucket=self.bucket, Key=f"{folder}/{file_name}", Body=data)
@ -36,10 +39,15 @@ class S3StorageService(StorageService):
async def get_file(self, folder: str, file_name: str):
"""Retrieve a file from the S3 bucket.
:param folder: The folder in the bucket where the file is stored.
:param file_name: The name of the file to be retrieved.
:return: The byte content of the file.
:raises Exception: If an error occurs during file retrieval.
Args:
folder: The folder in the bucket where the file is stored.
file_name: The name of the file to be retrieved.
Returns:
The byte content of the file.
Raises:
Exception: If an error occurs during file retrieval.
"""
try:
response = self.s3_client.get_object(Bucket=self.bucket, Key=f"{folder}/{file_name}")
@ -52,9 +60,14 @@ class S3StorageService(StorageService):
async def list_files(self, folder: str):
"""List all files in a specified folder of the S3 bucket.
:param folder: The folder in the bucket to list files from.
:return: A list of file names.
:raises Exception: If an error occurs during file listing.
Args:
folder: The folder in the bucket to list files from.
Returns:
A list of file names.
Raises:
Exception: If an error occurs during file listing.
"""
try:
response = self.s3_client.list_objects_v2(Bucket=self.bucket, Prefix=folder)
@ -69,9 +82,12 @@ class S3StorageService(StorageService):
async def delete_file(self, folder: str, file_name: str) -> None:
"""Delete a file from the S3 bucket.
:param folder: The folder in the bucket where the file is stored.
:param file_name: The name of the file to be deleted.
:raises Exception: If an error occurs during file deletion.
Args:
folder: The folder in the bucket where the file is stored.
file_name: The name of the file to be deleted.
Raises:
Exception: If an error occurs during file deletion.
"""
try:
self.s3_client.delete_object(Bucket=self.bucket, Key=f"{folder}/{file_name}")

View file

@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.store.service import StoreService
@ -13,5 +15,6 @@ class StoreServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(StoreService)
@override
def create(self, settings_service: SettingsService):
return StoreService(settings_service)

View file

@ -164,7 +164,8 @@ class StoreService(Service):
except Exception: # noqa: BLE001
logger.opt(exception=True).debug("Webhook failed")
def build_tags_filter(self, tags: list[str]):
@staticmethod
def build_tags_filter(tags: list[str]):
tags_filter: dict[str, Any] = {"tags": {"_and": []}}
for tag in tags:
tags_filter["tags"]["_and"].append({"_some": {"tags_id": {"name": {"_eq": tag}}}})
@ -249,7 +250,8 @@ class StoreService(Service):
return filter_conditions
def build_liked_filter(self):
@staticmethod
def build_liked_filter():
user_data = user_data_var.get()
# params["filter"] = json.dumps({"user_created": {"_eq": user_data["id"]}})
if not user_data:

View file

@ -1,3 +1,5 @@
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.task.service import TaskService
@ -6,6 +8,7 @@ class TaskServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(TaskService)
@override
def create(self):
# Here you would have logic to create and configure a TaskService
return TaskService()

View file

@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.telemetry.service import TelemetryService
@ -13,5 +15,6 @@ class TelemetryServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(TelemetryService)
@override
def create(self, settings_service: SettingsService):
return TelemetryService(settings_service)

View file

@ -132,7 +132,8 @@ class TelemetryService(Service):
except Exception: # noqa: BLE001
logger.exception("Error flushing logs")
async def _cancel_task(self, task: asyncio.Task, cancel_msg: str) -> None:
@staticmethod
async def _cancel_task(task: asyncio.Task, cancel_msg: str) -> None:
task.cancel(cancel_msg)
await asyncio.wait([task])
if not task.cancelled():

View file

@ -319,7 +319,8 @@ class ArizePhoenixTracer(BaseTracer):
return value
def _error_to_string(self, error: Exception | None):
@staticmethod
def _error_to_string(error: Exception | None):
"""Converts an error to a string with traceback details."""
error_message = None
if error:
@ -327,11 +328,13 @@ class ArizePhoenixTracer(BaseTracer):
error_message = f"{error.__class__.__name__}: {error}\n\n{string_stacktrace}"
return error_message
def _get_current_timestamp(self) -> int:
@staticmethod
def _get_current_timestamp() -> int:
"""Gets the current UTC timestamp in nanoseconds."""
return int(datetime.now(timezone.utc).timestamp() * 1_000_000_000)
def _safe_json_dumps(self, obj: Any, **kwargs: Any) -> str:
@staticmethod
def _safe_json_dumps(obj: Any, **kwargs: Any) -> str:
"""A convenience wrapper around `json.dumps` that ensures that any object can be safely encoded."""
return json.dumps(obj, default=str, ensure_ascii=False, **kwargs)
@ -359,6 +362,7 @@ class ArizePhoenixTracer(BaseTracer):
else:
current_span.set_status(Status(StatusCode.OK))
@override
def get_langchain_callback(self) -> BaseCallbackHandler | None:
"""Returns the LangChain callback handler if applicable."""
return None

View file

@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.tracing.service import TracingService
@ -13,5 +15,6 @@ class TracingServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(TracingService)
@override
def create(self, settings_service: SettingsService):
return TracingService(settings_service)

View file

@ -135,7 +135,8 @@ class LangFuseTracer(BaseTracer):
return None
return None # self._callback
def _get_config(self) -> dict:
@staticmethod
def _get_config() -> dict:
secret_key = os.getenv("LANGFUSE_SECRET_KEY", None)
public_key = os.getenv("LANGFUSE_PUBLIC_KEY", None)
host = os.getenv("LANGFUSE_HOST", None)

View file

@ -7,6 +7,7 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any
from loguru import logger
from typing_extensions import override
from langflow.schema.data import Data
from langflow.services.tracing.base import BaseTracer
@ -140,7 +141,8 @@ class LangSmithTracer(BaseTracer):
child.post()
self._child_link[trace_name] = child.get_url()
def _error_to_string(self, error: Exception | None):
@staticmethod
def _error_to_string(error: Exception | None):
error_message = None
if error:
string_stacktrace = traceback.format_exception(error)
@ -163,5 +165,6 @@ class LangSmithTracer(BaseTracer):
self._run_tree.post()
self._run_link = self._run_tree.get_url()
@override
def get_langchain_callback(self) -> BaseCallbackHandler | None:
return None

View file

@ -264,7 +264,8 @@ class TracingService(Service):
self.outputs[trace_name] |= outputs or {}
self.outputs_metadata[trace_name] |= output_metadata or {}
def _cleanup_inputs(self, inputs: dict[str, Any]):
@staticmethod
def _cleanup_inputs(inputs: dict[str, Any]):
inputs = inputs.copy()
for key in inputs:
if "api_key" in key:

View file

@ -177,9 +177,6 @@ async def clean_transactions(settings_service: SettingsService, session: AsyncSe
Args:
settings_service: The settings service containing configuration like max_transactions_to_keep
session: The database session to use for the deletion
Returns:
None
"""
try:
# Delete transactions using bulk delete
@ -209,9 +206,6 @@ async def clean_vertex_builds(settings_service: SettingsService, session: AsyncS
Args:
settings_service: The settings service containing configuration like max_vertex_builds_to_keep
session: The database session to use for the deletion
Returns:
None
"""
try:
# Delete vertex builds using bulk delete

View file

@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
from typing_extensions import override
from langflow.services.factory import ServiceFactory
from langflow.services.variable.service import DatabaseVariableService, VariableService
@ -13,6 +15,7 @@ class VariableServiceFactory(ServiceFactory):
def __init__(self) -> None:
super().__init__(VariableService)
@override
def create(self, settings_service: SettingsService):
# here you would have logic to create and configure a VariableService
# based on the settings_service

View file

@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
from loguru import logger
from sqlmodel import select
from typing_extensions import override
from langflow.services.auth import utils as auth_utils
from langflow.services.base import Service
@ -141,6 +142,7 @@ class DatabaseVariableService(VariableService, Service):
await session.refresh(db_variable)
return db_variable
@override
async def delete_variable(
self,
user_id: UUID | str,
@ -155,6 +157,7 @@ class DatabaseVariableService(VariableService, Service):
await session.delete(variable)
await session.commit()
@override
async def delete_variable_by_id(self, user_id: UUID | str, variable_id: UUID, session: AsyncSession) -> None:
stmt = select(Variable).where(Variable.user_id == user_id, Variable.id == variable_id)
variable = (await session.exec(stmt)).first()

View file

@ -36,7 +36,8 @@ class KeyedWorkerLockManager:
def __init__(self) -> None:
self.locks_dir = Path(user_cache_dir("langflow"), ensure_exists=True) / "worker_locks"
def _validate_key(self, key: str) -> bool:
@staticmethod
def _validate_key(key: str) -> bool:
"""Validate that the string only contains alphanumeric characters and underscores.
Parameters:

View file

@ -12,6 +12,7 @@ from docstring_parser import parse
from langflow.logging.logger import logger
from langflow.schema import Data
from langflow.services.deps import get_settings_service
from langflow.services.utils import initialize_settings_service
from langflow.template.frontend_node.constants import FORCE_SHOW_FIELDS
from langflow.utils import constants
@ -416,8 +417,6 @@ async def update_settings(
max_file_size_upload: int = 100,
) -> None:
"""Update the settings from a config file."""
from langflow.services.utils import initialize_settings_service
# Check for database_url in the environment variables
initialize_settings_service()

View file

@ -4,7 +4,11 @@ from langflow.utils import constants
def truncate_long_strings(data, max_length=None):
"""Recursively traverse the dictionary or list and truncate strings longer than max_length."""
"""Recursively traverse the dictionary or list and truncate strings longer than max_length.
Returns:
The data with strings truncated if they exceed the max length.
"""
if max_length is None:
max_length = constants.MAX_TEXT_LENGTH

View file

@ -170,9 +170,15 @@ def create_function(code, function_name):
def create_class(code, class_name):
"""Dynamically create a class from a string of code and a specified class name.
:param code: String containing the Python code defining the class
:param class_name: Name of the class to be created
:return: A function that, when called, returns an instance of the created class
Args:
code: String containing the Python code defining the class
class_name: Name of the class to be created
Returns:
A function that, when called, returns an instance of the created class
Raises:
ValueError: If the code contains syntax errors or the class definition is invalid
"""
if not hasattr(ast, "TypeIgnore"):
ast.TypeIgnore = create_type_ignore_class()
@ -199,7 +205,8 @@ def create_class(code, class_name):
def create_type_ignore_class():
"""Create a TypeIgnore class for AST module if it doesn't exist.
:return: TypeIgnore class
Returns:
TypeIgnore class
"""
class TypeIgnore(ast.AST):
@ -211,8 +218,15 @@ def create_type_ignore_class():
def prepare_global_scope(code, module):
"""Prepares the global scope with necessary imports from the provided code module.
:param module: AST parsed module
:return: Dictionary representing the global scope with imported modules
Args:
code: The Python code
module: AST parsed module
Returns:
Dictionary representing the global scope with imported modules
Raises:
ModuleNotFoundError: If a module is not found in the code
"""
exec_globals = globals().copy()
exec_globals.update(get_default_imports(code))
@ -250,9 +264,12 @@ def prepare_global_scope(code, module):
def extract_class_code(module, class_name):
"""Extracts the AST node for the specified class from the module.
:param module: AST parsed module
:param class_name: Name of the class to extract
:return: AST node of the specified class
Args:
module: AST parsed module
class_name: Name of the class to extract
Returns:
AST node of the specified class
"""
class_code = next(node for node in module.body if isinstance(node, ast.ClassDef) and node.name == class_name)
@ -263,8 +280,11 @@ def extract_class_code(module, class_name):
def compile_class_code(class_code):
"""Compiles the AST node of a class into a code object.
:param class_code: AST node of the class
:return: Compiled code object of the class
Args:
class_code: AST node of the class
Returns:
Compiled code object of the class
"""
return compile(ast.Module(body=[class_code], type_ignores=[]), "<string>", "exec")
@ -272,10 +292,13 @@ def compile_class_code(class_code):
def build_class_constructor(compiled_class, exec_globals, class_name):
"""Builds a constructor function for the dynamically created class.
:param compiled_class: Compiled code object of the class
:param exec_globals: Global scope with necessary imports
:param class_name: Name of the class
:return: Constructor function for the class
Args:
compiled_class: Compiled code object of the class
exec_globals: Global scope with necessary imports
class_name: Name of the class
Returns:
Constructor function for the class
"""
exec(compiled_class, exec_globals, locals())
exec_globals[class_name] = locals()[class_name]
@ -313,9 +336,12 @@ def get_default_imports(code_string):
def find_names_in_code(code, names):
"""Finds if any of the specified names are present in the given code string.
:param code: The source code as a string.
:param names: A list of names to check for in the code.
:return: A set of names that are found in the code.
Args:
code: The source code as a string.
names: A list of names to check for in the code.
Returns:
A set of names that are found in the code.
"""
return {name for name in names if name in code}
@ -339,7 +365,7 @@ def extract_class_name(code: str) -> str:
str: Name of the first Component subclass found
Raises:
ValueError: If no Component subclass is found in the code
TypeError: If no Component subclass is found in the code
"""
try:
module = ast.parse(code)

View file

@ -1,4 +1,7 @@
from importlib import metadata
import httpx
from packaging import version as pkg_version
from langflow.logging.logger import logger
@ -22,8 +25,6 @@ def _get_version_info():
Raises:
ValueError: If the package is not found from the list of package names.
"""
from importlib import metadata
package_options = [
("langflow", "Langflow"),
("langflow-base", "Langflow Base"),
@ -57,8 +58,9 @@ VERSION_INFO = _get_version_info()
def is_pre_release(v: str) -> bool:
"""Whether the version is a pre-release version.
Returns a boolean indicating whether the version is a pre-release version,
as per the definition of a pre-release segment from PEP 440.
Returns:
Whether the version is a pre-release version,
as per the definition of a pre-release segment from PEP 440.
"""
return any(label in v for label in ["a", "b", "rc"])
@ -66,15 +68,14 @@ def is_pre_release(v: str) -> bool:
def is_nightly(v: str) -> bool:
"""Whether the version is a dev (nightly) version.
Returns a boolean indicating whether the version is a dev (nightly) version,
as per the definition of a dev segment from PEP 440.
Returns:
Whether the version is a dev (nightly) version,
as per the definition of a dev segment from PEP 440.
"""
return "dev" in v
def fetch_latest_version(package_name: str, *, include_prerelease: bool) -> str | None:
from packaging import version as pkg_version
package_name = package_name.replace(" ", "-").lower()
try:
response = httpx.get(f"https://pypi.org/pypi/{package_name}/json")

View file

@ -18,7 +18,11 @@ def test_celery(word: str) -> str:
@celery_app.task(bind=True, soft_time_limit=30, max_retries=3)
def build_vertex(self, vertex: Vertex) -> Vertex:
"""Build a vertex."""
"""Build a vertex.
Returns:
The built vertex.
"""
try:
vertex.task_id = self.request.id
async_to_sync(vertex.build)()