feat: Allow variables to be defined outside a Component (#4316)
* feat: Allow variables to be defined outside a Component Fixes #4315 Modify `prepare_global_scope` function in `src/backend/base/langflow/utils/validate.py` to evaluate classes, functions, and variables defined outside the Component's class. * **Function Changes:** - Add evaluation of external classes using `ast.ClassDef`. - Add evaluation of external functions using `ast.FunctionDef`. - Add evaluation of external variables using `ast.Assign`. * **Unit Tests:** - Add tests in `src/backend/tests/unit/test_validate_code.py` to verify the evaluation of external classes, functions, and variables. - Include tests for multiple external classes and external variables and functions. --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/langflow-ai/langflow/issues/4315?shareId=XXXX-XXXX-XXXX-XXXX). * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
fb0084d478
commit
ccba14bec4
4 changed files with 84 additions and 1 deletions
|
|
@ -34,6 +34,9 @@
|
|||
"GitHub.vscode-pull-request-github"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"test": "make unit_tests"
|
||||
}
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
|
|
|
|||
BIN
localhost-19-2.db
Normal file
BIN
localhost-19-2.db
Normal file
Binary file not shown.
|
|
@ -227,6 +227,16 @@ def prepare_global_scope(code, module):
|
|||
except ModuleNotFoundError as e:
|
||||
msg = f"Module {node.module} not found. Please install it and try again"
|
||||
raise ModuleNotFoundError(msg) from e
|
||||
elif isinstance(node, ast.ClassDef):
|
||||
# Compile and execute the class definition to properly create the class
|
||||
class_code = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
|
||||
exec(class_code, exec_globals)
|
||||
elif isinstance(node, ast.FunctionDef):
|
||||
function_code = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
|
||||
exec(function_code, exec_globals)
|
||||
elif isinstance(node, ast.Assign):
|
||||
assign_code = compile(ast.Module(body=[node], type_ignores=[]), "<string>", "exec")
|
||||
exec(assign_code, exec_globals)
|
||||
return exec_globals
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,13 @@ from pathlib import Path
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from langflow.utils.validate import create_function, execute_function, extract_function_name, validate_code
|
||||
from langflow.utils.validate import (
|
||||
create_class,
|
||||
create_function,
|
||||
execute_function,
|
||||
extract_function_name,
|
||||
validate_code,
|
||||
)
|
||||
from requests.exceptions import MissingSchema
|
||||
|
||||
|
||||
|
|
@ -100,3 +106,67 @@ def my_function(x):
|
|||
"""
|
||||
with mock.patch("requests.get", side_effect=MissingSchema), pytest.raises(MissingSchema):
|
||||
execute_function(code, "my_function", "invalid_url")
|
||||
|
||||
|
||||
def test_create_class():
|
||||
code = """
|
||||
from langflow.custom import CustomComponent
|
||||
|
||||
class ExternalClass:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
class MyComponent(CustomComponent):
|
||||
def build(self):
|
||||
return ExternalClass("test")
|
||||
"""
|
||||
class_name = "MyComponent"
|
||||
created_class = create_class(code, class_name)
|
||||
instance = created_class()
|
||||
result = instance.build()
|
||||
assert result.value == "test"
|
||||
|
||||
|
||||
def test_create_class_with_multiple_external_classes():
|
||||
code = """
|
||||
from langflow.custom import CustomComponent
|
||||
|
||||
class ExternalClass1:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
class ExternalClass2:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
class MyComponent(CustomComponent):
|
||||
def build(self):
|
||||
return ExternalClass1("test1"), ExternalClass2("test2")
|
||||
"""
|
||||
class_name = "MyComponent"
|
||||
created_class = create_class(code, class_name)
|
||||
instance = created_class()
|
||||
result1, result2 = instance.build()
|
||||
assert result1.value == "test1"
|
||||
assert result2.value == "test2"
|
||||
|
||||
|
||||
def test_create_class_with_external_variables_and_functions():
|
||||
code = """
|
||||
from langflow.custom import CustomComponent
|
||||
|
||||
external_variable = "external_value"
|
||||
|
||||
def external_function():
|
||||
return "external_function_value"
|
||||
|
||||
class MyComponent(CustomComponent):
|
||||
def build(self):
|
||||
return external_variable, external_function()
|
||||
"""
|
||||
class_name = "MyComponent"
|
||||
created_class = create_class(code, class_name)
|
||||
instance = created_class()
|
||||
result_variable, result_function = instance.build()
|
||||
assert result_variable == "external_value"
|
||||
assert result_function == "external_function_value"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue