refactor(graph): add prepare method in Graph (#3124)

* refactor: update code references to use _code instead of code

* refactor: add backwards compatible attributes to Component class

* refactor: update Component constructor to pass config params with underscore

Refactored the `Component` class in `component.py` to handle inputs and outputs. Added a new method `map_outputs` to map a list of outputs to the component. Also updated the `__init__` method to properly initialize the inputs, outputs, and other attributes. This change improves the flexibility and extensibility of the `Component` class.

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* refactor: change attribute to use underscore

* refactor: update CustomComponent initialization parameters

Refactored the `instantiate_class` function in `loading.py` to update the initialization parameters for the `CustomComponent` class. Changed the parameter names from `user_id`, `parameters`, `vertex`, and `tracing_service` to `_user_id`, `_parameters`, `_vertex`, and `_tracing_service` respectively. This change ensures consistency and improves code readability.

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* refactor: update BaseComponent to accept UUID for _user_id

Updated the `BaseComponent` class in `base_component.py` to accept a `UUID` type for the `_user_id` attribute. This change improves the type safety and ensures consistency with the usage of `_user_id` throughout the codebase.

* refactor: import nanoid with type annotation

The `nanoid` import in `component.py` has been updated to include a type annotation `# type: ignore`. This change ensures that the type checker ignores any errors related to the `nanoid` import.

* fix(custom_component.py): convert _user_id to string before passing to functions to ensure compatibility with function signatures

* feat(component.py): add method to set output types based on method return type to improve type checking and validation in custom components

* refactor: extract method to get method return type in CustomComponent

* refactor(utils.py): refactor code to use _user_id instead of user_id for consistency and clarity

perf(utils.py): optimize code by reusing cc_instance instead of calling get_component_instance multiple times

* refactor(utils.py, base.py): change parameter name 'add_name' to 'keep_name' for clarity and consistency in codebase

* [autofix.ci] apply automated fixes

* refactor: update schema.py to include Edge related typres

The `schema.py` file in the `src/backend/base/langflow/graph/edge` directory has been updated to include the `TargetHandle` and `SourceHandle` models. These models define the structure and attributes of the target and source handles used in the edge data. This change improves the clarity and consistency of the codebase.

* refactor: update BaseInputMixin to handle invalid field types gracefully

The `BaseInputMixin` class in `input_mixin.py` has been updated to handle invalid field types gracefully. Instead of raising an exception, it now returns `FieldTypes.OTHER` for any invalid field type. This change improves the robustness and reliability of the codebase.

* refactor: update file_types field alias in FileMixin

The `file_types` field in the `FileMixin` class of `input_mixin.py` has been updated to use the `alias` parameter instead of `serialization_alias`. This change ensures consistency and improves the clarity of the codebase.

* refactor(inputs): update field_type declarations in various input classes to use SerializableFieldTypes enum for better type safety and clarity

* refactor(inputs): convert dict to Message object in _validate_value method

* refactor(inputs): convert dict to Message object in _validate_value method

* refactor(inputs): update model_config in BaseInputMixin to enable populating by name

The `model_config` attribute in the `BaseInputMixin` class of `input_mixin.py` has been updated to include the `populate_by_name=True` parameter. This change allows the model configuration to be populated by name, improving the flexibility and usability of the codebase.

* refactor: update _extract_return_type method in CustomComponent to accept Any type

The _extract_return_type method in CustomComponent has been updated to accept the Any type as the return_type parameter. This change improves the flexibility and compatibility of the method, allowing it to handle a wider range of return types.

* refactor(component): add get_input and get_output methods for easier access to input and output values

The `Component` class in `component.py` has been updated to include the `get_input` and `get_output` methods. These methods allow for easier retrieval of input and output values by name, improving the usability and readability of the codebase.

* refactor(vertex): add get_input and get_output methods for easier access to input and output values

* refactor(component): add set_output_value method for easier modification of output values

The `Component` class in `component.py` has been updated to include the `set_output_value` method. This method allows for easier modification of output values by name, improving the usability and flexibility of the codebase.

* feat: add run_until_complete and run_in_thread functions for handling asyncio tasks

The `async_helpers.py` file in the `src/backend/base/langflow/utils` directory has been added. This file includes the `run_until_complete` and `run_in_thread` functions, which provide a way to handle asyncio tasks in different scenarios. The `run_until_complete` function checks if an event loop is already running and either runs the coroutine in a separate event loop in a new thread or creates a new event loop and runs the coroutine. The `run_in_thread` function runs the coroutine in a separate thread and returns the result or raises an exception if one occurs. These functions improve the flexibility and usability of the codebase.

* refactor(component): add _edges attribute to Component class for managing edges

The `Component` class in `component.py` has been updated to include the `_edges` attribute. This attribute is a list of `EdgeData` objects and is used for managing edges in the component. This change improves the functionality and organization of the codebase.

* fix(component.py): fix conditional statement to check if self._vertex is not None before accessing its attributes

* refactor(component): add _get_fallback_input method for handling fallback input

The `Component` class in `component.py` has been updated to include the `_get_fallback_input` method. This method returns an `Input` object with the provided keyword arguments, which is used as a fallback input when needed. This change improves the flexibility and readability of the codebase.

* refactor(component): add TYPE_CHECKING import for Vertex in component.py

* refactor(component): add _map_parameters_on_frontend_node and _map_parameters_on_template and other methods

The `Component` class in `component.py` has been refactored to include the `_map_parameters_on_frontend_node` and `_map_parameters_on_template` methods. These methods are responsible for mapping the parameters of the component onto the frontend node and template, respectively. This change improves the organization and maintainability of the codebase.

* refactor(component): Add map_inputs and map_outputs methods for mapping inputs and outputs

The `Component` class in `component.py` has been updated to include the `map_inputs` and `map_outputs` methods. These methods allow for mapping the given inputs and outputs to the component, improving the functionality and organization of the codebase.

* refactor(component): Add Input, Output, and ComponentFrontendNode imports and run_until_complete function

This commit refactors the `component.py` file in the `src/backend/base/langflow/custom/custom_component` directory. It adds the `Input`, `Output`, and `ComponentFrontendNode` imports, as well as the `run_until_complete` function from the `async_helpers.py` file. These changes improve the functionality and organization of the codebase.

* refactor(component): Add map_inputs and map_outputs methods for mapping inputs and outputs

* refactor(component): Add _process_connection_or_parameter method for handling connections and parameters

The `Component` class in `component.py` has been updated to include the `_process_connection_or_parameter` method. This method is responsible for handling connections and parameters based on the provided key and value. It checks if the value is callable and connects it to the component, otherwise it sets the parameter or attribute. This change improves the functionality and organization of the codebase.

* refactor(frontend_node): Add set_field_value_in_template method for updating field values

The `FrontendNode` class in `base.py` has been updated to include the `set_field_value_in_template` method. This method allows for updating the value of a specific field in the template of the frontend node. It iterates through the fields and sets the value of the field with the provided name. This change improves the flexibility and functionality of the codebase.

* refactor(inputs): Add DefaultPromptField class for default prompt inputs

The `inputs.py` file in the `src/backend/base/langflow/inputs` directory has been refactored to include the `DefaultPromptField` class. This class represents a default prompt input with customizable properties such as name, display name, field type, advanced flag, multiline flag, input types, and value. This change improves the flexibility and functionality of the codebase.

* feat: Add Template.from_dict method for creating Template objects from dictionaries

This commit adds the `from_dict` class method to the `Template` class in `base.py`. This method allows for creating `Template` objects from dictionaries by converting the dictionary keys and values into the appropriate `Template` attributes. This change improves the flexibility and functionality of the codebase.

* refactor(frontend_node): Add from_dict method for creating FrontendNode objects from dictionaries

* refactor: update BaseComponent to use get_template_config method

Refactored the `BaseComponent` class in `base_component.py` to use the `get_template_config` method instead of duplicating the code. This change improves code readability and reduces redundancy.

* refactor(graph): Add EdgeData import and update add_nodes_and_edges method signature

The `Graph` class in `base.py` has been updated to include the `EdgeData` import and modify the signature of the `add_nodes_and_edges` method. The `add_nodes_and_edges` method now accepts a list of dictionaries representing `EdgeData` objects instead of a list of dictionaries with string keys and values. This change improves the type safety and clarity of the codebase.

* refactor(graph): Add first_layer property to Graph class

The `Graph` class in `base.py` has been updated to include the `first_layer` property. This property returns the first layer of the graph and throws a `ValueError` if the graph is not prepared. This change improves the functionality and organization of the codebase.

* refactor(graph): Update Graph class instantiation in base.py

The `Graph` class in `base.py` has been updated to use keyword arguments when instantiating the class. This change improves the readability and maintainability of the codebase.

* refactor(graph): Add prepare method to Graph class

The `Graph` class in `base.py` has been updated to include the `prepare` method. This method prepares the graph for execution by validating the stream, building edges, and sorting vertices. It also adds the first layer of vertices to the run manager and sets the run queue. This change improves the functionality and organization of the codebase.

* refactor(graph): Improve graph preparation in retrieve_vertices_order function

The `retrieve_vertices_order` function in `chat.py` has been updated to improve the graph preparation process. Instead of manually sorting vertices and adding them to the run manager, the function now calls the `prepare` method of the `Graph` class. This method validates the stream, builds edges, and sets the first layer of vertices. This change improves the functionality and organization of the codebase.

* feat: add BaseModel class with model_config attribute

A new `BaseModel` class has been added to the `base_model.py` file. This class extends the `PydanticBaseModel` and includes a `model_config` attribute of type `ConfigDict`. This change improves the codebase by providing a base model with a configuration dictionary for models.

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* refactor: update langflow.graph.edge.schema.py

Refactor the `langflow.graph.edge.schema.py` file to include the `TargetHandle` and `SourceHandle` models. This change improves the clarity and consistency of the codebase.

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>

* refactor: update build_custom_component_template to use add_name instead of keep_name

Refactor the `build_custom_component_template` function in `utils.py` to use the `add_name` parameter instead of the deprecated `keep_name` parameter. This change ensures consistency with the updated method signature and improves code clarity.

* feat(component.py): add method to set output types based on method return type to improve type checking and validation in custom components (#3115)

* feat(component.py): add method to set output types based on method return type to improve type checking and validation in custom components

* refactor: extract method to get method return type in CustomComponent

* refactor: update _extract_return_type method in CustomComponent to accept Any type

The _extract_return_type method in CustomComponent has been updated to accept the Any type as the return_type parameter. This change improves the flexibility and compatibility of the method, allowing it to handle a wider range of return types.

* refactor: add _template_config property to BaseComponent

Add a new `_template_config` property to the `BaseComponent` class in `base_component.py`. This property is used to store the template configuration for the custom component. If the `_template_config` property is empty, it is populated by calling the `build_template_config` method. This change improves the efficiency of accessing the template configuration and ensures that it is only built when needed.

* refactor: add type checking for Output types in add_types method

Improve type checking in the `add_types` method of the `Output` class in `base.py`. Check if the `type_` already exists in the `types` list before adding it. This change ensures that duplicate types are not added to the list.

* update starter projects

* refactor: optimize imports in base.py

Optimize imports in the `base.py` file by removing unused imports and organizing the remaining imports. This change improves code readability and reduces unnecessary clutter.

* fix(base.py): fix condition to check if self.types is not None before checking if type_ is in self.types

* refactor: update build_custom_component_template to use add_name instead of keep_name

* refactor(graph): update ContractEdge to use EdgeData for raw_edge parameter, enhancing type consistency across edges

* refactor(graph): update add_edge method to use EdgeData type, improving type safety and consistency in graph edges

* chore(dependencies): bump mypy version from 1.10.0 to 1.11.0 for improved type checking capabilities

* refactor: update Edge class to use EdgeData type for raw_edge parameter

The Edge class in base.py has been updated to use the EdgeData type for the raw_edge parameter in the __init__ method. This change improves type safety and consistency in graph edges.

* refactor: update follow_imports to "skip" in mypy configuration

* fix: add type ignore comment for return data in SelfQueryRetriever.py to resolve mypy warning

* chore: update mypy configuration to include namespace_packages and ignore missing imports in pyproject.toml files

* fix: add type ignore comment for target_param in base.py to resolve mypy warning about split method usage

* fix: add type ignore comments for various classes to resolve mypy warnings in input_mixin, database models, and cache service files

* refactor: add first layer attribute to Graph class

The Graph class in base.py has been updated to include a new attribute called `_first_layer`. This attribute is a list of strings and is initialized as an empty list. This change enhances the functionality of the Graph class by providing a way to store and access the first layer of vertices in the graph.

* refactor: store first layer in Graph class with _first_layer attribute for improved access to vertices being run

* fix: add type ignore comments to database model classes to resolve mypy type checking warnings

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-08-02 16:51:47 -03:00 committed by GitHub
commit be87c9e43e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 82 additions and 53 deletions

7
poetry.lock generated
View file

@ -5988,7 +5988,7 @@ files = [
{file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"},
{file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"},
{file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"},
{file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"},
{file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"},
]
[[package]]
@ -6912,6 +6912,7 @@ optional = false
python-versions = ">=3.9"
files = [
{file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
{file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
{file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
{file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
@ -6932,6 +6933,7 @@ files = [
{file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
{file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
{file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
{file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
{file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
{file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
@ -8644,6 +8646,7 @@ files = [
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
@ -11991,4 +11994,4 @@ local = ["ctransformers", "llama-cpp-python", "sentence-transformers"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.10,<3.13"
content-hash = "3acb8b0235dcb5d33db0362bd5cf8a5dfcfb9cc198887dd2570b81c39a0fe46c"
content-hash = "b0b58a9883d3eacc262701a7938ff839365386ba5e155dd2582986501d2b5d7c"

View file

@ -111,7 +111,7 @@ composio-langchain = "^0.3.28"
[tool.poetry.group.dev.dependencies]
types-redis = "^4.6.0.5"
ipykernel = "^6.29.0"
mypy = "^1.10.0"
mypy = "^1.11.0"
ruff = "^0.4.5"
httpx = "*"
pytest = "^8.2.0"
@ -193,8 +193,11 @@ line-length = 120
[tool.mypy]
plugins = ["pydantic.mypy"]
follow_imports = "silent"
follow_imports = "skip"
disable_error_code = ["type-var"]
namespace_packages = true
mypy_path = "langflow"
ignore_missing_imports = true
[build-system]
requires = ["poetry-core"]

View file

@ -103,18 +103,7 @@ async def retrieve_vertices_order(
graph = await build_and_cache_graph_from_data(
flow_id=flow_id_str, graph_data=data.model_dump(), chat_service=chat_service
)
graph.validate_stream()
if stop_component_id or start_component_id:
try:
first_layer = graph.sort_vertices(stop_component_id, start_component_id)
except Exception as exc:
logger.error(exc)
first_layer = graph.sort_vertices()
else:
first_layer = graph.sort_vertices()
for vertex_id in first_layer:
graph.run_manager.add_to_vertices_being_run(vertex_id)
graph = graph.prepare(stop_component_id, start_component_id)
# Now vertices is a list of lists
# We need to get the id of each vertex
@ -130,7 +119,7 @@ async def retrieve_vertices_order(
playgroundSuccess=True,
),
)
return VerticesOrderResponse(ids=first_layer, run_id=graph._run_id, vertices_to_run=vertices_to_run)
return VerticesOrderResponse(ids=graph.first_layer, run_id=graph.run_id, vertices_to_run=vertices_to_run)
except Exception as exc:
background_tasks.add_task(
telemetry_service.log_package_playground,

View file

@ -67,4 +67,4 @@ class SelfQueryRetrieverComponent(CustomComponent):
documents = self_query_retriever.invoke(input=input_text, config={"callbacks": self.get_langchain_callbacks()})
data = [Data.from_document(document) for document in documents]
self.status = data
return data
return data # type: ignore

View file

@ -1,8 +1,9 @@
from typing import TYPE_CHECKING, Any, List, Optional
from typing import TYPE_CHECKING, Any, List, Optional, cast
from loguru import logger
from pydantic import BaseModel, Field, field_validator
from langflow.graph.edge.schema import EdgeData
from langflow.schema.schema import INPUT_FIELD_NAME
if TYPE_CHECKING:
@ -36,7 +37,7 @@ class TargetHandle(BaseModel):
class Edge:
def __init__(self, source: "Vertex", target: "Vertex", edge: dict):
def __init__(self, source: "Vertex", target: "Vertex", edge: EdgeData):
self.source_id: str = source.id if source else ""
self.target_id: str = target.id if target else ""
if data := edge.get("data", {}):
@ -50,11 +51,11 @@ class Edge:
else:
# Logging here because this is a breaking change
logger.error("Edge data is empty")
self._source_handle = edge.get("sourceHandle", "")
self._target_handle = edge.get("targetHandle", "")
self._source_handle = edge.get("sourceHandle", "") # type: ignore
self._target_handle = edge.get("targetHandle", "") # type: ignore
# 'BaseLoader;BaseOutputParser|documents|PromptTemplate-zmTlD'
# target_param is documents
self.target_param = self._target_handle.split("|")[1]
self.target_param = cast(str, self._target_handle.split("|")[1]) # type: ignore
# Validate in __init__ to fail fast
self.validate_edge(source, target)
@ -182,7 +183,7 @@ class Edge:
class ContractEdge(Edge):
def __init__(self, source: "Vertex", target: "Vertex", raw_edge: dict):
def __init__(self, source: "Vertex", target: "Vertex", raw_edge: EdgeData):
super().__init__(source, target, raw_edge)
self.is_fulfilled = False # Whether the contract has been fulfilled.
self.result: Any = None

View file

@ -10,6 +10,7 @@ from loguru import logger
from langflow.exceptions.component import ComponentBuildException
from langflow.graph.edge.base import ContractEdge
from langflow.graph.edge.schema import EdgeData
from langflow.graph.graph.constants import lazy_load_vertex_dict
from langflow.graph.graph.runnable_vertices_manager import RunnableVerticesManager
from langflow.graph.graph.state_manager import GraphStateManager
@ -67,13 +68,14 @@ class Graph:
self.vertices: List[Vertex] = []
self.run_manager = RunnableVerticesManager()
self.state_manager = GraphStateManager()
self._first_layer: List[str] = []
try:
self.tracing_service: "TracingService" | None = get_tracing_service()
except Exception as exc:
logger.error(f"Error getting tracing service: {exc}")
self.tracing_service = None
def add_nodes_and_edges(self, nodes: List[Dict], edges: List[Dict[str, str]]):
def add_nodes_and_edges(self, nodes: List[Dict], edges: List[EdgeData]):
self._vertices = nodes
self._edges = edges
self.raw_graph_data = {"nodes": nodes, "edges": edges}
@ -91,8 +93,7 @@ class Graph:
def add_node(self, node: dict):
self._vertices.append(node)
# TODO: Create a TypedDict to represente the edge
def add_edge(self, edge: dict):
def add_edge(self, edge: EdgeData):
self._edges.append(edge)
def initialize(self):
@ -220,6 +221,12 @@ class Graph:
"are connected and both have stream or streaming set to True"
)
@property
def first_layer(self):
if self._first_layer is None:
raise ValueError("Graph not prepared. Call prepare() first.")
return self._first_layer
@property
def run_id(self):
"""
@ -646,7 +653,7 @@ class Graph:
try:
vertices = payload["nodes"]
edges = payload["edges"]
graph = cls(flow_id, flow_name, user_id)
graph = cls(flow_id=flow_id, flow_name=flow_name, user_id=user_id)
graph.add_nodes_and_edges(vertices, edges)
return graph
except KeyError as exc:
@ -1220,6 +1227,27 @@ class Graph:
vertex_instance.set_top_level(self.top_level_vertices)
return vertex_instance
def prepare(self, stop_component_id: Optional[str] = None, start_component_id: Optional[str] = None):
if stop_component_id and start_component_id:
raise ValueError("You can only provide one of stop_component_id or start_component_id")
self.validate_stream()
self.edges = self._build_edges()
if stop_component_id or start_component_id:
try:
first_layer = self.sort_vertices(stop_component_id, start_component_id)
except Exception as exc:
logger.error(exc)
first_layer = self.sort_vertices()
else:
first_layer = self.sort_vertices()
for vertex_id in first_layer:
self.run_manager.add_to_vertices_being_run(vertex_id)
self._first_layer = first_layer
self._run_queue = deque(first_layer)
self._prepared = True
return self
def get_children_by_vertex_type(self, vertex: Vertex, vertex_type: str) -> List[Vertex]:
"""Returns the children of a vertex based on the vertex type."""
children = []

View file

@ -26,7 +26,7 @@ SerializableFieldTypes = Annotated[FieldTypes, PlainSerializer(lambda v: v.value
# Base mixin for common input field attributes and methods
class BaseInputMixin(BaseModel, validate_assignment=True):
class BaseInputMixin(BaseModel, validate_assignment=True): # type: ignore
model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid", populate_by_name=True)
field_type: SerializableFieldTypes = Field(default=FieldTypes.TEXT)

View file

@ -1,4 +1,7 @@
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, cast
from loguru import logger
from pydantic import BaseModel
from langflow.graph.graph.base import Graph
from langflow.graph.schema import RunOutputs
@ -6,8 +9,6 @@ from langflow.graph.vertex.base import Vertex
from langflow.schema.graph import InputValue, Tweaks
from langflow.schema.schema import INPUT_FIELD_NAME
from langflow.services.deps import get_settings_service
from loguru import logger
from pydantic import BaseModel
if TYPE_CHECKING:
from langflow.api.v1.schemas import InputValueRequest
@ -112,7 +113,7 @@ def run_graph(
def validate_input(
graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, Dict[str, Any]]]
graph_data: Dict[str, Any], tweaks: Union["Tweaks", Dict[str, str | Dict[str, Any]]]
) -> List[Dict[str, Any]]:
if not isinstance(graph_data, dict) or not isinstance(tweaks, dict):
raise ValueError("graph_data and tweaks should be dictionaries")
@ -162,12 +163,12 @@ def process_tweaks(
"""
tweaks_dict = {}
if not isinstance(tweaks, dict):
tweaks_dict = tweaks.model_dump()
tweaks_dict = cast(Dict[str, Any], tweaks.model_dump())
else:
tweaks_dict = tweaks
if "stream" not in tweaks_dict:
tweaks_dict["stream"] = stream
nodes = validate_input(graph_data, tweaks_dict)
tweaks_dict |= {"stream": stream}
nodes = validate_input(graph_data, cast(Dict[str, str | Dict[str, Any]], tweaks_dict))
nodes_map = {node.get("id"): node for node in nodes}
nodes_display_name_map = {node.get("data", {}).get("node", {}).get("display_name"): node for node in nodes}

View file

@ -13,7 +13,7 @@ from langflow.services.cache.utils import CacheMiss
CACHE_MISS = CacheMiss()
class ThreadingInMemoryCache(CacheService, Generic[LockType]):
class ThreadingInMemoryCache(CacheService, Generic[LockType]): # type: ignore
"""
A simple in-memory cache using an OrderedDict.
@ -181,7 +181,7 @@ class ThreadingInMemoryCache(CacheService, Generic[LockType]):
return f"InMemoryCache(max_size={self.max_size}, expiration_time={self.expiration_time})"
class RedisCache(AsyncBaseCacheService, Generic[LockType]):
class RedisCache(AsyncBaseCacheService, Generic[LockType]): # type: ignore
"""
A Redis-based cache implementation.
@ -331,7 +331,7 @@ class RedisCache(AsyncBaseCacheService, Generic[LockType]):
return f"RedisCache(expiration_time={self.expiration_time})"
class AsyncInMemoryCache(AsyncBaseCacheService, Generic[AsyncLockType]):
class AsyncInMemoryCache(AsyncBaseCacheService, Generic[AsyncLockType]): # type: ignore
def __init__(self, max_size=None, expiration_time=3600):
self.cache = OrderedDict()

View file

@ -20,7 +20,7 @@ class ApiKeyBase(SQLModel):
is_active: bool = Field(default=True)
class ApiKey(ApiKeyBase, table=True):
class ApiKey(ApiKeyBase, table=True): # type: ignore
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True)
created_at: Optional[datetime] = Field(
default=None, sa_column=Column(DateTime(timezone=True), server_default=func.now(), nullable=False)

View file

@ -137,7 +137,7 @@ class FlowBase(SQLModel):
return datetime.fromisoformat(v)
class Flow(FlowBase, table=True):
class Flow(FlowBase, table=True): # type: ignore
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True)
data: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
user_id: Optional[UUID] = Field(index=True, foreign_key="user.id", nullable=True)

View file

@ -16,7 +16,7 @@ class FolderBase(SQLModel):
description: Optional[str] = Field(default=None)
class Folder(FolderBase, table=True):
class Folder(FolderBase, table=True): # type: ignore
id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
parent_id: Optional[UUID] = Field(default=None, foreign_key="folder.id")

View file

@ -47,7 +47,7 @@ class MessageBase(SQLModel):
)
class MessageTable(MessageBase, table=True):
class MessageTable(MessageBase, table=True): # type: ignore
__tablename__ = "message"
id: UUID = Field(default_factory=uuid4, primary_key=True)
flow_id: Optional[UUID] = Field(default=None, foreign_key="flow.id")

View file

@ -33,7 +33,7 @@ class TransactionBase(SQLModel):
return value
class TransactionTable(TransactionBase, table=True):
class TransactionTable(TransactionBase, table=True): # type: ignore
__tablename__ = "transaction"
id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
flow: "Flow" = Relationship(back_populates="transactions")

View file

@ -11,7 +11,7 @@ if TYPE_CHECKING:
from langflow.services.database.models.folder import Folder
class User(SQLModel, table=True):
class User(SQLModel, table=True): # type: ignore
id: UUID = Field(default_factory=uuid4, primary_key=True, unique=True)
username: str = Field(index=True, unique=True)
password: str = Field()

View file

@ -19,7 +19,7 @@ class VariableBase(SQLModel):
type: Optional[str] = Field(None, description="Type of the variable")
class Variable(VariableBase, table=True):
class Variable(VariableBase, table=True): # type: ignore
id: Optional[UUID] = Field(
default_factory=uuid4,
primary_key=True,

View file

@ -33,7 +33,7 @@ class VertexBuildBase(SQLModel):
return value
class VertexBuildTable(VertexBuildBase, table=True):
class VertexBuildTable(VertexBuildBase, table=True): # type: ignore
__tablename__ = "vertex_build"
build_id: Optional[UUID] = Field(default_factory=uuid4, primary_key=True)
flow: "Flow" = Relationship(back_populates="vertex_builds")

View file

@ -1,7 +1,7 @@
import time
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, Type
import sqlalchemy as sa
from alembic import command, util
@ -133,7 +133,7 @@ class DatabaseService(Service):
def check_schema_health(self) -> bool:
inspector = inspect(self.engine)
model_mapping = {
model_mapping: dict[str, Type[SQLModel]] = {
"flow": models.Flow,
"user": models.User,
"apikey": models.ApiKey,

View file

@ -1,13 +1,16 @@
from typing import Optional
from typing import TYPE_CHECKING, Optional
from loguru import logger
from langflow.services.deps import get_settings_service
from langflow.services.plugins.base import CallbackPlugin
if TYPE_CHECKING:
from langfuse import Langfuse # type: ignore
class LangfuseInstance:
_instance = None
_instance: Optional["Langfuse"] = None
@classmethod
def get(cls):

View file

@ -96,11 +96,12 @@ log_cli = true
markers = ["async_test"]
[tool.mypy]
plugins = ["pydantic.mypy"]
follow_imports = "skip"
disable_error_code = ["type-var"]
namespace_packages = true
mypy_path = "langflow"
ignore_missing_imports = true
disable_error_code = ["type-var"]
[tool.ruff]
exclude = ["src/backend/langflow/alembic/*"]