Repository: Avaiga/taipy
File: taipy/core/config/checkers/_data_node_config_checker.py (Python)

Code before:
                        f" `{data_node_config_id}` must be populated with a List value.",
                    )
        if data_node_config_id != DataNodeConfig._DEFAULT_KEY:
            properties_to_check_at_least_one = [
                DataNodeConfig._OPTIONAL_READ_FUNCTION_GENERIC_PROPERTY,
                DataNodeConfig._OPTIONAL_WRITE_FUNCTION_GENERIC_PROPERTY,
            ]
            has_at_least_one = False
            for prop_key in properties_to_check_at_least_one:
                if data_node_config.properties and prop_key in data_node_config.properties:
                    has_at_least_one = True
            if not has_at_least_one:
                self._error(
                    ", ".join(properties_to_check_at_least_one),
                    None,
                    f"Either `{DataNodeConfig._OPTIONAL_READ_FUNCTION_GENERIC_PROPERTY}` field or "
                    f"`{DataNodeConfig._OPTIONAL_WRITE_FUNCTION_GENERIC_PROPERTY}` field of "
                    f"DataNodeConfig `{data_node_config_id}` must be populated with a Callable function.",
                )

    @staticmethod
    def _get_class_type_and_properties() -> Dict[str, List[Tuple[Any, List[str]]]]:
        return {
            DataNodeConfig._STORAGE_TYPE_VALUE_GENERIC: [
                (
                    Callable,
                    [
                        DataNodeConfig._OPTIONAL_READ_FUNCTION_GENERIC_PROPERTY,
                        DataNodeConfig._OPTIONAL_WRITE_FUNCTION_GENERIC_PROPERTY,
                    ],
                )
            ],
            DataNodeConfig._STORAGE_TYPE_VALUE_SQL: [
                (
                    Callable,
                    [
                        DataNodeConfig._REQUIRED_WRITE_QUERY_BUILDER_SQL_PROPERTY,
                        DataNodeConfig._OPTIONAL_APPEND_QUERY_BUILDER_SQL_PROPERTY,
                    ],
                ),
            ],
        }

    def _check_class_type(self, data_node_config_id: str, data_node_config: DataNodeConfig):
        properties_to_check = self._get_class_type_and_properties()

        for storage_type in properties_to_check.keys():
            for class_type, prop_keys in properties_to_check[storage_type]:
                for prop_key in prop_keys:
                    prop_value = data_node_config.properties.get(prop_key) if data_node_config.properties else None
                    if prop_value and not isinstance(prop_value, class_type):

Review comment (bug):
I know that it was already the case before, but I actually believe it is buggy.
Callables include functions, classes, and lambdas. 
I am not sure lambdas are accepted as they must be serializable (JSON and TOML). Can you check with a unit test?

Code after:
                        None,
                        f"DataNodeConfig `{data_node_config_id}` is missing the required "
                        f"property `{required_property}` for type `{storage_type}`.",
                    )

    def _check_generic_read_write_fct_and_args(self, data_node_config_id: str, data_node_config: DataNodeConfig):
        if data_node_config.storage_type != DataNodeConfig._STORAGE_TYPE_VALUE_GENERIC:
            return

        properties_to_check = [
            DataNodeConfig._OPTIONAL_READ_FUNCTION_ARGS_GENERIC_PROPERTY,
            DataNodeConfig._OPTIONAL_WRITE_FUNCTION_ARGS_GENERIC_PROPERTY,
        ]
        for prop_key in properties_to_check:
            if data_node_config.properties and prop_key in data_node_config.properties:
                prop_value = data_node_config.properties[prop_key]
                if not isinstance(prop_value, list):
                    self._error(
                        prop_key,
                        prop_value,
                        f"`{prop_key}` field of DataNodeConfig"
                        f" `{data_node_config_id}` must be populated with a List value.",
                    )
        if data_node_config_id != DataNodeConfig._DEFAULT_KEY:
            properties_to_check_at_least_one = [
                DataNodeConfig._OPTIONAL_READ_FUNCTION_GENERIC_PROPERTY,
                DataNodeConfig._OPTIONAL_WRITE_FUNCTION_GENERIC_PROPERTY,
            ]
            has_at_least_one = False
            for prop_key in properties_to_check_at_least_one:
                if data_node_config.properties and prop_key in data_node_config.properties:
                    has_at_least_one = True
            if not has_at_least_one:
                self._error(
                    ", ".join(properties_to_check_at_least_one),
                    None,
                    f"Either `{DataNodeConfig._OPTIONAL_READ_FUNCTION_GENERIC_PROPERTY}` field or "
                    f"`{DataNodeConfig._OPTIONAL_WRITE_FUNCTION_GENERIC_PROPERTY}` field of "
                    f"DataNodeConfig `{data_node_config_id}` must be populated with a Callable function.",
                )

    def _check_class_type(self, data_node_config_id: str, data_node_config: DataNodeConfig):
        if data_node_config.storage_type in self._PROPERTIES_TYPES.keys():
            for class_type, prop_keys in self._PROPERTIES_TYPES[data_node_config.storage_type]:
                for prop_key in prop_keys:
                    prop_value = data_node_config.properties.get(prop_key) if data_node_config.properties else None
                    if prop_value and not isinstance(prop_value, class_type):
                        self._error(
                            prop_key,
                            prop_value,
                            f"`{prop_key}` of DataNodeConfig `{data_node_config_id}` must be"