Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
# -*- coding: utf-8 -*-

#  Copyright (c) 2021, University of Luxembourg / DHARPA project
#  Copyright (c) 2021, Markus Binsteiner
#
#  Mozilla Public License, version 2.0 (see LICENSE or https://www.mozilla.org/en-US/MPL/2.0/)

from typing import ClassVar, Dict, Iterable, Mapping, Union

import structlog
from pydantic import Field

from kiara.models.module.operation import (
    BaseOperationDetails,
    Operation,
    OperationConfig,
)
from kiara.modules import KiaraModule
from kiara.operations import OperationType

logger = structlog.getLogger()


class RenderDataDetails(BaseOperationDetails):
    """A model that contains information needed to describe an 'extract_metadata' operation."""

    source_data_type: str = Field(description="The data type that will be rendered.")
    target_data_type: str = Field(description="The rendered data type.")


class RenderDataOperationType(OperationType[RenderDataDetails]):
    """An operation that renders data (and metadata) associated with a value."""

    _operation_type_name: ClassVar[str] = "render_data"

    def _calculate_op_id(cls, source_type: str, target_type: str):

        if source_type == "any":
            operation_id = f"render.as.{target_type}"
        else:
            operation_id = f"render.{source_type}.as.{target_type}"

        return operation_id

    def retrieve_included_operation_configs(
        self,
    ) -> Iterable[Union[Mapping, OperationConfig]]:

        # result = {}
        return []
        # for name, module_cls in self._kiara.module_type_classes.items():
        #
        #     if not issubclass(module_cls, RenderValueModule):
        #         continue
        #
        #     for (
        #         source_type,
        #         target_type,
        #     ) in module_cls.retrieve_supported_render_combinations():
        #         if source_type not in self._kiara.data_type_names:
        #             log_message("ignore.operation_config", operation_type="render_value", module_type=module_cls._module_type_name, source_type=source_type, target_type=target_type, reason=f"Source type '{source_type}' not registered.")  # type: ignore
        #             continue
        #         if target_type not in self._kiara.data_type_names:
        #             log_message(
        #                 "ignore.operation_config",
        #                 operation_type="render_value",
        #                 module_type=module_cls._module_type_name,
        #                 source_type=source_type,  # type: ignore
        #                 target_type=target_type,
        #                 reason=f"Target type '{target_type}' not registered.",
        #             )
        #             continue
        #         func_name = f"render__{source_type}__as__{target_type}"
        #         attr = getattr(module_cls, func_name)
        #         doc = DocumentationMetadataModel.from_function(attr)
        #         mc = {"source_type": source_type, "target_type": target_type}
        #         oc = ManifestOperationConfig(
        #             module_type=name, module_config=mc, doc=doc
        #         )
        #         op_id = self._calculate_op_id(
        #             source_type=source_type, target_type=target_type
        #         )
        #         result[op_id] = oc
        #
        # for data_type_name, data_type_class in self._kiara.data_type_classes.items():
        #     for attr in data_type_class.__dict__.keys():
        #         if not attr.startswith("render_as__"):
        #             continue
        #
        #         target_type = attr[11:]
        #         if target_type not in self._kiara.data_type_names:
        #             log_message(
        #                 "operation_config.ignore",
        #                 operation_type="render_value",
        #                 source_type=data_type_name,
        #                 target_type=target_type,
        #                 reason=f"Target type '{target_type}' not registered.",
        #             )  # type: ignore
        #
        #         # TODO: inspect signature?
        #         doc = DocumentationMetadataModel.from_string(
        #             f"Render a '{data_type_name}' value as a {target_type}."
        #         )
        #         mc = {
        #             "source_type": data_type_name,
        #             "target_type": target_type,
        #         }
        #         oc = ManifestOperationConfig(
        #             module_type="render.value", module_config=mc, doc=doc
        #         )
        #
        #         result[f"_type_{data_type_name}_{target_type}"] = oc
        #
        # return result.values()

    def check_matching_operation(
        self, module: "KiaraModule"
    ) -> Union[RenderDataDetails, None]:

        if len(module.inputs_schema) != 2:
            return None

        if len(module.outputs_schema) != 1:
            return None

        if "value" not in module.inputs_schema.keys():
            return None

        if (
            "render_config" not in module.inputs_schema.keys()
            or module.inputs_schema["render_config"].type != "dict"
        ):
            return None

        if (
            "render_value_result" not in module.outputs_schema.keys()
            or module.outputs_schema["render_value_result"].type
            != "render_value_result"
        ):
            return None

        source_type = module.inputs_schema["value"].type
        target_type = module.get_config_value("target_type")

        if source_type == "any":
            op_id = f"render.as.{target_type}"
        else:
            op_id = f"render.{source_type}.as.{target_type}"

        details: RenderDataDetails = RenderDataDetails.create_operation_details(
            module_inputs_schema=module.inputs_schema,
            module_outputs_schema=module.outputs_schema,
            operation_id=op_id,
            source_data_type=source_type,
            target_data_type=target_type,
            is_internal_operation=True,
        )

        return details

    def get_render_operations_for_source_type(
        self, source_type: str
    ) -> Mapping[str, Operation]:
        """
        Return all render operations for the specified data type.

        Arguments:
        ---------
            source_type: the data type to render

        Returns:
        -------
            a mapping with the target type as key, and the operation as value
        """
        if source_type not in self._kiara.data_type_names:
            source_type = "any"

        lineage = self._kiara.type_registry.get_type_lineage(data_type_name=source_type)

        result: Dict[str, Operation] = {}

        for data_type in lineage:

            for op_id, op in self.operations.items():
                op_details = self.retrieve_operation_details(op)
                match = op_details.source_data_type == data_type
                if not match:
                    continue
                target_type = op_details.target_data_type
                if target_type in result.keys():
                    continue
                result[target_type] = op

        return result

    def get_render_operations_for_target_type(
        self, target_type: str
    ) -> Mapping[str, Operation]:
        """
        Return all render operations that renders to the specified data type.

        Arguments:
        ---------
            target_type: the result data type

        Returns:
        -------
            a mapping with the source type as key, and the operation as value
        """
        # TODO: consider type lineages

        if target_type not in self._kiara.data_type_names:
            raise Exception(f"Invalid target data type: {target_type}")

        result: Dict[str, Operation] = {}

        for op_id, op in self.operations.items():
            op_details = self.retrieve_operation_details(op)
            match = op_details.target_data_type == target_type
            if not match:
                continue
            source_type = op_details.source_data_type
            if source_type in result.keys():
                continue

            result[source_type] = op

        return result

    def get_render_operation(
        self, source_type: str, target_type: str
    ) -> Union[Operation, None]:

        all_ops = self.get_render_operations_for_source_type(source_type=source_type)
        return all_ops.get(target_type, None)