Add PythonFunctionComponent and test case for it
This commit is contained in:
parent
f43c558f7a
commit
a8779b1205
6 changed files with 56 additions and 44 deletions
|
|
@ -24,4 +24,5 @@ __all__ = [
|
||||||
"RunnableExecComponent",
|
"RunnableExecComponent",
|
||||||
"SQLExecutorComponent",
|
"SQLExecutorComponent",
|
||||||
"SubFlowComponent",
|
"SubFlowComponent",
|
||||||
|
"PythonFunctionComponent",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ from .DocumentToRecord import DocumentToRecordComponent
|
||||||
from .IDGenerator import UUIDGeneratorComponent
|
from .IDGenerator import UUIDGeneratorComponent
|
||||||
from .MessageHistory import MessageHistoryComponent
|
from .MessageHistory import MessageHistoryComponent
|
||||||
from .UpdateRecord import UpdateRecordComponent
|
from .UpdateRecord import UpdateRecordComponent
|
||||||
|
from .RecordsToText import RecordsToTextComponent
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Component",
|
"Component",
|
||||||
"UpdateRecordComponent",
|
"UpdateRecordComponent",
|
||||||
"DocumentToRecordComponent",
|
"DocumentToRecordComponent",
|
||||||
"UUIDGeneratorComponent",
|
"UUIDGeneratorComponent",
|
||||||
"PythonFunctionComponent",
|
|
||||||
"RecordsToTextComponent",
|
"RecordsToTextComponent",
|
||||||
"CreateRecordComponent",
|
"CreateRecordComponent",
|
||||||
"MessageHistoryComponent",
|
"MessageHistoryComponent",
|
||||||
|
|
|
||||||
|
|
@ -424,6 +424,19 @@ def test_build_vertex_invalid_vertex_id(client, added_flow_with_prompt_and_histo
|
||||||
assert response.status_code == 500
|
assert response.status_code == 500
|
||||||
|
|
||||||
|
|
||||||
|
# Helper function to poll task status
|
||||||
|
def poll_task_status(client, headers, href, max_attempts=20, sleep_time=1):
|
||||||
|
for _ in range(max_attempts):
|
||||||
|
task_status_response = client.get(
|
||||||
|
href,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
if task_status_response.status_code == 200 and task_status_response.json()["status"] == "SUCCESS":
|
||||||
|
return task_status_response.json()
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
return None # Return None if task did not complete in time
|
||||||
|
|
||||||
|
|
||||||
def test_successful_run(client, starter_project, created_api_key):
|
def test_successful_run(client, starter_project, created_api_key):
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
|
|
@ -455,11 +468,14 @@ def test_run_with_inputs_and_outputs(client, starter_project, created_api_key):
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": [{"components": ["component1"], "input_value": "value1"}],
|
"input_value": "value1",
|
||||||
"outputs": ["Component Name", "component_id"],
|
"input_type": "text",
|
||||||
|
"output_type": "text",
|
||||||
|
"tweaks": {"parameter_name": "value"},
|
||||||
|
"stream": False,
|
||||||
}
|
}
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK, response.text
|
||||||
# Validate the response structure and content
|
# Validate the response structure and content
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -475,16 +491,10 @@ def test_run_flow_with_caching_success(client: TestClient, starter_project, crea
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": [
|
"input_value": "value1",
|
||||||
{"components": ["component1"], "input_value": "value1"},
|
"input_type": "text",
|
||||||
{"components": ["component3"], "input_value": "value2"},
|
"output_type": "text",
|
||||||
],
|
"tweaks": {"parameter_name": "value"},
|
||||||
"outputs": ["Component Name", "component_id"],
|
|
||||||
"tweaks": {
|
|
||||||
"parameter_name": "value",
|
|
||||||
"Component Name": {"parameter_name": "value"},
|
|
||||||
"component_id": {"parameter_name": "value"},
|
|
||||||
},
|
|
||||||
"stream": False,
|
"stream": False,
|
||||||
}
|
}
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
|
|
@ -497,7 +507,7 @@ def test_run_flow_with_caching_success(client: TestClient, starter_project, crea
|
||||||
def test_run_flow_with_caching_invalid_flow_id(client: TestClient, created_api_key):
|
def test_run_flow_with_caching_invalid_flow_id(client: TestClient, created_api_key):
|
||||||
invalid_flow_id = uuid4()
|
invalid_flow_id = uuid4()
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
payload = {"inputs": [], "outputs": [], "tweaks": {}, "stream": False}
|
payload = {"input_value": "", "input_type": "text", "output_type": "text", "tweaks": {}, "stream": False}
|
||||||
response = client.post(f"/api/v1/run/{invalid_flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{invalid_flow_id}", json=payload, headers=headers)
|
||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
@ -508,8 +518,7 @@ def test_run_flow_with_caching_invalid_flow_id(client: TestClient, created_api_k
|
||||||
def test_run_flow_with_caching_invalid_input_format(client: TestClient, starter_project, created_api_key):
|
def test_run_flow_with_caching_invalid_input_format(client: TestClient, starter_project, created_api_key):
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
payload = {"inputs": [{"invalid_key": "value"}], "outputs": [], "tweaks": {}, "stream": False}
|
payload = {"invalid_key": "value"}
|
||||||
# This should raise an http 422 error not validation error
|
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||||
|
|
||||||
|
|
@ -518,8 +527,9 @@ def test_run_flow_with_session_id(client, starter_project, created_api_key):
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": [{"components": ["component1"], "input_value": "value1"}],
|
"input_value": "value1",
|
||||||
"outputs": ["Component Name", "component_id"],
|
"input_type": "text",
|
||||||
|
"output_type": "text",
|
||||||
"session_id": "test-session-id",
|
"session_id": "test-session-id",
|
||||||
}
|
}
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
|
|
@ -534,8 +544,9 @@ def test_run_flow_with_invalid_session_id(client, starter_project, created_api_k
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": [{"components": ["component1"], "input_value": "value1"}],
|
"input_value": "value1",
|
||||||
"outputs": ["Component Name", "component_id"],
|
"input_type": "text",
|
||||||
|
"output_type": "text",
|
||||||
"session_id": "invalid-session-id",
|
"session_id": "invalid-session-id",
|
||||||
}
|
}
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
|
|
@ -549,8 +560,9 @@ def test_run_flow_with_invalid_tweaks(client, starter_project, created_api_key):
|
||||||
headers = {"x-api-key": created_api_key.api_key}
|
headers = {"x-api-key": created_api_key.api_key}
|
||||||
flow_id = starter_project["id"]
|
flow_id = starter_project["id"]
|
||||||
payload = {
|
payload = {
|
||||||
"inputs": [{"components": ["component1"], "input_value": "value1"}],
|
"input_value": "value1",
|
||||||
"outputs": ["Component Name", "component_id"],
|
"input_type": "text",
|
||||||
|
"output_type": "text",
|
||||||
"tweaks": {"invalid_tweak": "value"},
|
"tweaks": {"invalid_tweak": "value"},
|
||||||
}
|
}
|
||||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
from langchain_core.documents import Document
|
from langchain_core.documents import Document
|
||||||
|
|
||||||
from langflow.components import helpers
|
from langflow.components import helpers
|
||||||
from langflow.interface.custom.utils import build_custom_component_template
|
from langflow.interface.custom.utils import build_custom_component_template
|
||||||
from langflow.schema import Record
|
from langflow.schema import Record
|
||||||
|
|
@ -52,23 +51,9 @@ def test_uuid_generator_component():
|
||||||
assert len(result) == 36
|
assert len(result) == 36
|
||||||
|
|
||||||
|
|
||||||
def test_python_function_component():
|
|
||||||
# Arrange
|
|
||||||
python_function_component = helpers.PythonFunctionComponent()
|
|
||||||
|
|
||||||
# Act
|
|
||||||
# function must be a string representation
|
|
||||||
function = "def function():\n return 'Hello, World!'"
|
|
||||||
# result is the callable function
|
|
||||||
result = python_function_component.build(function)
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
assert result() == "Hello, World!"
|
|
||||||
|
|
||||||
|
|
||||||
def test_records_as_text_component():
|
def test_records_as_text_component():
|
||||||
# Arrange
|
# Arrange
|
||||||
records_as_text_component = helpers.RecordsAsTextComponent()
|
records_as_text_component = helpers.RecordsToTextComponent()
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
# Replace with your actual test data
|
# Replace with your actual test data
|
||||||
|
|
@ -83,7 +68,7 @@ def test_records_as_text_component():
|
||||||
|
|
||||||
def test_text_to_record_component():
|
def test_text_to_record_component():
|
||||||
# Arrange
|
# Arrange
|
||||||
text_to_record_component = helpers.TextToRecordComponent()
|
text_to_record_component = helpers.CreateRecordComponent()
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
# Replace with your actual test data
|
# Replace with your actual test data
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy import func
|
|
||||||
from sqlmodel import select
|
|
||||||
|
|
||||||
from langflow.graph.graph.base import Graph
|
from langflow.graph.graph.base import Graph
|
||||||
from langflow.graph.schema import ResultData
|
from langflow.graph.schema import ResultData
|
||||||
from langflow.initial_setup.setup import (
|
from langflow.initial_setup.setup import (
|
||||||
|
|
@ -14,6 +11,8 @@ from langflow.initial_setup.setup import (
|
||||||
)
|
)
|
||||||
from langflow.services.database.models.flow.model import Flow
|
from langflow.services.database.models.flow.model import Flow
|
||||||
from langflow.services.deps import session_scope
|
from langflow.services.deps import session_scope
|
||||||
|
from sqlalchemy import func
|
||||||
|
from sqlmodel import select
|
||||||
|
|
||||||
|
|
||||||
def test_load_starter_projects():
|
def test_load_starter_projects():
|
||||||
|
|
@ -26,7 +25,7 @@ def test_get_project_data():
|
||||||
projects = load_starter_projects()
|
projects = load_starter_projects()
|
||||||
for project in projects:
|
for project in projects:
|
||||||
data = get_project_data(project)
|
data = get_project_data(project)
|
||||||
assert all(d is not None for d in data)
|
assert all(d is not None for d in data), f"Project {project} data is None"
|
||||||
|
|
||||||
|
|
||||||
def test_create_or_update_starter_projects(client):
|
def test_create_or_update_starter_projects(client):
|
||||||
|
|
|
||||||
15
tests/text_experimental_components.py
Normal file
15
tests/text_experimental_components.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from langflow.components import experimental
|
||||||
|
|
||||||
|
|
||||||
|
def test_python_function_component():
|
||||||
|
# Arrange
|
||||||
|
python_function_component = experimental.PythonFunctionComponent()
|
||||||
|
|
||||||
|
# Act
|
||||||
|
# function must be a string representation
|
||||||
|
function = "def function():\n return 'Hello, World!'"
|
||||||
|
# result is the callable function
|
||||||
|
result = python_function_component.build(function)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
assert result() == "Hello, World!"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue