diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py index fadd1d7b3..296bfbba2 100644 --- a/src/backend/base/langflow/api/v1/endpoints.py +++ b/src/backend/base/langflow/api/v1/endpoints.py @@ -552,7 +552,7 @@ async def custom_component( raw_code: CustomComponentRequest, user: User = Depends(get_current_active_user), ): - component = Component(code=raw_code.code) + component = Component(_code=raw_code.code) built_frontend_node, component_instance = build_custom_component_template(component, user_id=user.id) if raw_code.frontend_node is not None: @@ -582,7 +582,7 @@ async def custom_component_update( """ try: - component = Component(code=code_request.code) + component = Component(_code=code_request.code) component_node, cc_instance = build_custom_component_template( component, diff --git a/src/backend/base/langflow/custom/custom_component/base_component.py b/src/backend/base/langflow/custom/custom_component/base_component.py index 098942dd4..ce1c5c445 100644 --- a/src/backend/base/langflow/custom/custom_component/base_component.py +++ b/src/backend/base/langflow/custom/custom_component/base_component.py @@ -23,7 +23,8 @@ class BaseComponent: ERROR_CODE_NULL: ClassVar[str] = "Python code must be provided." ERROR_FUNCTION_ENTRYPOINT_NAME_NULL: ClassVar[str] = "The name of the entrypoint function must be provided." - code: Optional[str] = None + _code: Optional[str] = None + """The code of the component. Defaults to None.""" _function_entrypoint_name: str = "build" field_config: dict = {} _user_id: Optional[str] @@ -47,7 +48,7 @@ class BaseComponent: return parser.parse_code() def get_function(self): - if not self.code: + if not self._code: raise ComponentCodeNullError( status_code=400, detail={"error": self.ERROR_CODE_NULL, "traceback": ""}, @@ -62,7 +63,7 @@ class BaseComponent: }, ) - return validate.create_function(self.code, self._function_entrypoint_name) + return validate.create_function(self._code, self._function_entrypoint_name) def build_template_config(self) -> dict: """ @@ -71,10 +72,10 @@ class BaseComponent: Returns: A dictionary representing the template configuration. """ - if not self.code: + if not self._code: return {} - cc_class = eval_custom_component_code(self.code) + cc_class = eval_custom_component_code(self._code) component_instance = cc_class() template_config = {} diff --git a/src/backend/base/langflow/custom/custom_component/custom_component.py b/src/backend/base/langflow/custom/custom_component/custom_component.py index c5e10932f..95c10022f 100644 --- a/src/backend/base/langflow/custom/custom_component/custom_component.py +++ b/src/backend/base/langflow/custom/custom_component/custom_component.py @@ -64,8 +64,6 @@ class CustomComponent(BaseComponent): is_output: Optional[bool] = None """The output state of the component. Defaults to None. If True, the component must have a field named 'input_value'.""" - code: Optional[str] = None - """The code of the component. Defaults to None.""" field_config: dict = {} """The field configuration of the component. Defaults to an empty dictionary.""" field_order: Optional[List[str]] = None @@ -226,7 +224,7 @@ class CustomComponent(BaseComponent): Returns: dict: The code tree of the custom component. """ - return self.get_code_tree(self.code or "") + return self.get_code_tree(self._code or "") def to_data(self, data: Any, keys: Optional[List[str]] = None, silent_errors: bool = False) -> List[Data]: """ @@ -326,7 +324,7 @@ class CustomComponent(BaseComponent): Returns: dict: The build method for the custom component. """ - if not self.code: + if not self._code: return {} component_classes = [ @@ -379,7 +377,7 @@ class CustomComponent(BaseComponent): Returns: str: The main class name of the custom component. """ - if not self.code: + if not self._code: return "" base_name = self.code_class_base_inheritance @@ -468,7 +466,7 @@ class CustomComponent(BaseComponent): Returns: Callable: The function associated with the custom component. """ - return validate.create_function(self.code, self.function_entrypoint_name) + return validate.create_function(self._code, self.function_entrypoint_name) async def load_flow(self, flow_id: str, tweaks: Optional[dict] = None) -> "Graph": if not self._user_id: diff --git a/src/backend/base/langflow/custom/directory_reader/directory_reader.py b/src/backend/base/langflow/custom/directory_reader/directory_reader.py index 1fb4ca93e..18f39b5eb 100644 --- a/src/backend/base/langflow/custom/directory_reader/directory_reader.py +++ b/src/backend/base/langflow/custom/directory_reader/directory_reader.py @@ -373,7 +373,7 @@ class DirectoryReader: """ Get the output types from the code. """ - custom_component = CustomComponent(code=code) + custom_component = CustomComponent(_code=code) types_list = custom_component.get_function_entrypoint_return_type # Get the name of types classes diff --git a/src/backend/base/langflow/custom/utils.py b/src/backend/base/langflow/custom/utils.py index d721bc275..84aef2399 100644 --- a/src/backend/base/langflow/custom/utils.py +++ b/src/backend/base/langflow/custom/utils.py @@ -266,10 +266,10 @@ def run_build_inputs( def get_component_instance(custom_component: CustomComponent, user_id: Optional[Union[str, UUID]] = None): try: - if custom_component.code is None: + if custom_component._code is None: raise ValueError("Code is None") - elif isinstance(custom_component.code, str): - custom_class = eval_custom_component_code(custom_component.code) + elif isinstance(custom_component._code, str): + custom_class = eval_custom_component_code(custom_component._code) else: raise ValueError("Invalid code type") except Exception as exc: @@ -300,10 +300,10 @@ def run_build_config( """Build the field configuration for a custom component""" try: - if custom_component.code is None: + if custom_component._code is None: raise ValueError("Code is None") - elif isinstance(custom_component.code, str): - custom_class = eval_custom_component_code(custom_component.code) + elif isinstance(custom_component._code, str): + custom_class = eval_custom_component_code(custom_component._code) else: raise ValueError("Invalid code type") except Exception as exc: @@ -363,7 +363,7 @@ def build_custom_component_template_from_inputs( # The List of Inputs fills the role of the build_config and the entrypoint_args field_config = custom_component.template_config frontend_node = ComponentFrontendNode.from_inputs(**field_config) - frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {})) + frontend_node = add_code_field(frontend_node, custom_component._code, field_config.get("code", {})) # But we now need to calculate the return_type of the methods in the outputs for output in frontend_node.outputs: if output.types: @@ -407,7 +407,7 @@ def build_custom_component_template( add_extra_fields(frontend_node, field_config, entrypoint_args) - frontend_node = add_code_field(frontend_node, custom_component.code, field_config.get("code", {})) + frontend_node = add_code_field(frontend_node, custom_component._code, field_config.get("code", {})) add_base_classes(frontend_node, custom_component.get_function_entrypoint_return_type) add_output_types(frontend_node, custom_component.get_function_entrypoint_return_type) @@ -432,7 +432,7 @@ def create_component_template(component): component_code = component["code"] component_output_types = component["output_types"] - component_extractor = Component(code=component_code) + component_extractor = Component(_code=component_code) component_template, component_instance = build_custom_component_template(component_extractor) if not component_template["output_types"] and component_output_types: diff --git a/src/backend/tests/unit/test_custom_component.py b/src/backend/tests/unit/test_custom_component.py index a0e5525cb..d582f2933 100644 --- a/src/backend/tests/unit/test_custom_component.py +++ b/src/backend/tests/unit/test_custom_component.py @@ -16,7 +16,7 @@ from langflow.services.database.models.flow import Flow, FlowCreate def code_component_with_multiple_outputs(): with open("src/backend/tests/data/component_multiple_outputs.py", "r") as f: code = f.read() - return Component(code=code) + return Component(_code=code) code_default = """ @@ -72,8 +72,8 @@ def test_component_init(): """ Test the initialization of the Component class. """ - component = BaseComponent(code=code_default, function_entrypoint_name="build") - assert component.code == code_default + component = BaseComponent(_code=code_default, function_entrypoint_name="build") + assert component._code == code_default assert component.function_entrypoint_name == "build" @@ -81,8 +81,8 @@ def test_component_get_code_tree(): """ Test the get_code_tree method of the Component class. """ - component = BaseComponent(code=code_default, function_entrypoint_name="build") - tree = component.get_code_tree(component.code) + component = BaseComponent(_code=code_default, function_entrypoint_name="build") + tree = component.get_code_tree(component._code) assert "imports" in tree @@ -91,7 +91,7 @@ def test_component_code_null_error(): Test the get_function method raises the ComponentCodeNullError when the code is empty. """ - component = BaseComponent(code="", function_entrypoint_name="") + component = BaseComponent(_code="", function_entrypoint_name="") with pytest.raises(ComponentCodeNullError): component.get_function() @@ -102,8 +102,8 @@ def test_custom_component_init(): """ function_entrypoint_name = "build" - custom_component = CustomComponent(code=code_default, function_entrypoint_name=function_entrypoint_name) - assert custom_component.code == code_default + custom_component = CustomComponent(_code=code_default, function_entrypoint_name=function_entrypoint_name) + assert custom_component._code == code_default assert custom_component.function_entrypoint_name == function_entrypoint_name @@ -111,7 +111,7 @@ def test_custom_component_build_template_config(): """ Test the build_template_config property of the CustomComponent class. """ - custom_component = CustomComponent(code=code_default, function_entrypoint_name="build") + custom_component = CustomComponent(_code=code_default, function_entrypoint_name="build") config = custom_component.build_template_config() assert isinstance(config, dict) @@ -120,7 +120,7 @@ def test_custom_component_get_function(): """ Test the get_function property of the CustomComponent class. """ - custom_component = CustomComponent(code="def build(): pass", function_entrypoint_name="build") + custom_component = CustomComponent(_code="def build(): pass", function_entrypoint_name="build") my_function = custom_component.get_function() assert isinstance(my_function, types.FunctionType) @@ -195,7 +195,7 @@ def test_component_get_function_valid(): Test the get_function method of the Component class with valid code and function_entrypoint_name. """ - component = BaseComponent(code="def build(): pass", function_entrypoint_name="build") + component = BaseComponent(_code="def build(): pass", function_entrypoint_name="build") my_function = component.get_function() assert callable(my_function) @@ -205,7 +205,7 @@ def test_custom_component_get_function_entrypoint_args(): Test the get_function_entrypoint_args property of the CustomComponent class. """ - custom_component = CustomComponent(code=code_default, function_entrypoint_name="build") + custom_component = CustomComponent(_code=code_default, function_entrypoint_name="build") args = custom_component.get_function_entrypoint_args assert len(args) == 3 assert args[0]["name"] == "self" @@ -219,7 +219,7 @@ def test_custom_component_get_function_entrypoint_return_type(): property of the CustomComponent class. """ - custom_component = CustomComponent(code=code_default, function_entrypoint_name="build") + custom_component = CustomComponent(_code=code_default, function_entrypoint_name="build") return_type = custom_component.get_function_entrypoint_return_type assert return_type == [Document] @@ -228,7 +228,7 @@ def test_custom_component_get_main_class_name(): """ Test the get_main_class_name property of the CustomComponent class. """ - custom_component = CustomComponent(code=code_default, function_entrypoint_name="build") + custom_component = CustomComponent(_code=code_default, function_entrypoint_name="build") class_name = custom_component.get_main_class_name assert class_name == "YourComponent" @@ -238,7 +238,7 @@ def test_custom_component_get_function_valid(): Test the get_function property of the CustomComponent class with valid code and function_entrypoint_name. """ - custom_component = CustomComponent(code="def build(): pass", function_entrypoint_name="build") + custom_component = CustomComponent(_code="def build(): pass", function_entrypoint_name="build") my_function = custom_component.get_function assert callable(my_function) @@ -352,9 +352,9 @@ def test_component_get_code_tree_syntax_error(): Test the get_code_tree method of the Component class raises the CodeSyntaxError when given incorrect syntax. """ - component = BaseComponent(code="import os as", function_entrypoint_name="build") + component = BaseComponent(_code="import os as", function_entrypoint_name="build") with pytest.raises(CodeSyntaxError): - component.get_code_tree(component.code) + component.get_code_tree(component._code) def test_custom_component_class_template_validation_no_code(): @@ -362,7 +362,7 @@ def test_custom_component_class_template_validation_no_code(): Test the _class_template_validation method of the CustomComponent class raises the HTTPException when the code is None. """ - custom_component = CustomComponent(code=None, function_entrypoint_name="build") + custom_component = CustomComponent(_code=None, function_entrypoint_name="build") with pytest.raises(TypeError): custom_component.get_function() @@ -372,9 +372,9 @@ def test_custom_component_get_code_tree_syntax_error(): Test the get_code_tree method of the CustomComponent class raises the CodeSyntaxError when given incorrect syntax. """ - custom_component = CustomComponent(code="import os as", function_entrypoint_name="build") + custom_component = CustomComponent(_code="import os as", function_entrypoint_name="build") with pytest.raises(CodeSyntaxError): - custom_component.get_code_tree(custom_component.code) + custom_component.get_code_tree(custom_component._code) def test_custom_component_get_function_entrypoint_args_no_args(): @@ -387,7 +387,7 @@ class MyMainClass(CustomComponent): def build(): pass""" - custom_component = CustomComponent(code=my_code, function_entrypoint_name="build") + custom_component = CustomComponent(_code=my_code, function_entrypoint_name="build") args = custom_component.get_function_entrypoint_args assert len(args) == 0 @@ -402,7 +402,7 @@ class MyClass(CustomComponent): def build(): pass""" - custom_component = CustomComponent(code=my_code, function_entrypoint_name="build") + custom_component = CustomComponent(_code=my_code, function_entrypoint_name="build") return_type = custom_component.get_function_entrypoint_return_type assert return_type == [] @@ -416,7 +416,7 @@ def test_custom_component_get_main_class_name_no_main_class(): def build(): pass""" - custom_component = CustomComponent(code=my_code, function_entrypoint_name="build") + custom_component = CustomComponent(_code=my_code, function_entrypoint_name="build") class_name = custom_component.get_main_class_name assert class_name == "" @@ -426,13 +426,13 @@ def test_custom_component_build_not_implemented(): Test the build method of the CustomComponent class raises the NotImplementedError. """ - custom_component = CustomComponent(code="def build(): pass", function_entrypoint_name="build") + custom_component = CustomComponent(_code="def build(): pass", function_entrypoint_name="build") with pytest.raises(NotImplementedError): custom_component.build() def test_build_config_no_code(): - component = CustomComponent(code=None) + component = CustomComponent(_code=None) assert component.get_function_entrypoint_args == [] assert component.get_function_entrypoint_return_type == [] diff --git a/src/backend/tests/unit/test_helper_components.py b/src/backend/tests/unit/test_helper_components.py index dc07c5835..75395b862 100644 --- a/src/backend/tests/unit/test_helper_components.py +++ b/src/backend/tests/unit/test_helper_components.py @@ -32,7 +32,7 @@ from langflow.schema import Data def test_uuid_generator_component(): # Arrange uuid_generator_component = helpers.IDGeneratorComponent() - uuid_generator_component.code = open(helpers.IDGenerator.__file__, "r").read() + uuid_generator_component._code = open(helpers.IDGenerator.__file__, "r").read() frontend_node, _ = build_custom_component_template(uuid_generator_component)