123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- #
- # Copyright 2018-2022 Elyra Authors
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- import json
- from typing import Any
- from typing import Type
- from typing import TypeVar
- from traitlets.utils.importstring import import_item
- from elyra.metadata.schema import SchemaManager
- # Setup forward reference for type hint on return from class factory method. See
- # https://stackoverflow.com/questions/39205527/can-you-annotate-return-type-when-value-is-instance-of-cls/39205612#39205612
- M = TypeVar("M", bound="Metadata")
- class Metadata(object):
- name = None
- resource = None
- display_name = None
- schema_name = None
- metadata = {}
- reason = None
- def __init__(self, **kwargs: Any) -> None:
- self.name = kwargs.get("name")
- self.display_name = kwargs.get("display_name")
- self.schema_name = kwargs.get("schema_name")
- self.metadata = kwargs.get("metadata", {})
- self.resource = kwargs.get("resource")
- self.reason = kwargs.get("reason")
- def on_load(self, **kwargs: Any) -> None:
- """Called by MetadataManager after fetching the instance and prior to validation.
- :param kwargs: additional arguments
- """
- pass
- def pre_save(self, **kwargs: Any) -> None:
- """Called by MetadataManager prior to saving the instance.
- :param kwargs: additional arguments
- Keyword Args:
- for_update (bool): indicates if this save operation if for update (True) or create (False)
- """
- pass
- def post_save(self, **kwargs: Any) -> None:
- """Called by MetadataManager following the save of the instance.
- :param kwargs: additional arguments
- Keyword Args:
- for_update (bool): indicates if this save operation if for update (True) or create (False)
- Note: Since exceptions thrown from this method can adversely affect the operation,
- implementations are advised to trap all exceptions unless the operation's
- rollback is warranted.
- """
- pass
- def pre_delete(self, **kwargs: Any) -> None:
- """Called by MetadataManager prior to deleting the instance."""
- pass
- def post_delete(self, **kwargs: Any) -> None:
- """Called by MetadataManager following the deletion of the instance.
- Note: Since exceptions thrown from this method can adversely affect the operation,
- implementations are advised to trap all exceptions unless the operation's
- rollback is warranted.
- """
- pass
- @classmethod
- def from_dict(cls: Type[M], schemaspace: str, metadata_dict: dict) -> M:
- """Creates an appropriate instance of Metadata from a dictionary instance"""
- # Get the schema and look for metadata_class entry and use that, else Metadata.
- metadata_class_name = "elyra.metadata.metadata.Metadata"
- schema_name = metadata_dict.get("schema_name")
- if schema_name:
- schema = SchemaManager.instance().get_schema(schemaspace, schema_name)
- metadata_class_name = schema.get("metadata_class_name", metadata_class_name)
- metadata_class = import_item(metadata_class_name)
- try:
- instance = metadata_class(**metadata_dict)
- if not isinstance(instance, Metadata):
- raise ValueError(
- f"The metadata_class_name ('{metadata_class_name}') for "
- f"schema '{schema_name}' must be a subclass of '{cls.__name__}'!"
- )
- except TypeError as te:
- raise ValueError(
- f"The metadata_class_name ('{metadata_class_name}') for "
- f"schema '{schema_name}' must be a subclass of '{cls.__name__}'!"
- ) from te
- return instance
- def to_dict(self, trim: bool = False) -> dict:
- # Exclude resource, and reason only if trim is True since we don't want to persist that information.
- # Method prepare_write will be used to remove name prior to writes.
- d = dict(name=self.name, display_name=self.display_name, metadata=self.metadata, schema_name=self.schema_name)
- if not trim:
- if self.resource:
- d["resource"] = self.resource
- if self.reason:
- d["reason"] = self.reason
- return d
- def to_json(self, trim: bool = False) -> str:
- return json.dumps(self.to_dict(trim=trim), indent=2)
- def prepare_write(self) -> dict:
- """Prepares this instance for storage, stripping name, reason, and resource and converting to a dict"""
- prepared = self.to_dict(trim=True) # we should also trim 'name' when storing
- prepared.pop("name", None)
- return prepared
- def __repr__(self):
- return self.to_json()
|