Source code for MED3pa.models.base

"""
This module introduces a singleton manager that manages the instantiation and cloning of a base model, 
which is particularly useful for applications like ``med3pa`` and ``Detectron`` where a consistent reference model is necessary. 
It employs the **Singleton and Prototype** design patterns to ensure that the base model is instantiated once and can be cloned without reinitialization.
"""
import pickle
from io import BytesIO
import copy

from .abstract_models import Model


[docs] class BaseModelManager: """ Singleton manager class for the base model. ensures the base model is set only once. """ __baseModel = None
[docs] @classmethod def set_base_model(cls, model: Model): """ Sets the base model for the manager, ensuring Singleton behavior. Parameters: model (Model): The model to be set as the base model. Raises: TypeError: If the base model has already been initialized. """ if cls.__baseModel is None: cls.__baseModel = model else: raise TypeError("The Base Model has already been initialized")
[docs] @classmethod def get_instance(cls) -> Model: """ Returns the instance of the base model, ensuring Singleton access. Returns: The base model instance. Raises: TypeError: If the base model has not been initialized yet. """ if cls.__baseModel is None: raise TypeError("The Base Model has not been initialized yet") return cls.__baseModel
[docs] @classmethod def clone_base_model(cls) -> Model: """ Creates and returns a deep clone of the base model, following the Prototype pattern. This method uses serialization and deserialization to clone complex model attributes, allowing for independent modification of the cloned model. Returns: A cloned instance of the base model. Raises: TypeError: If the base model has not been initialized yet. """ if cls.__baseModel is None: raise TypeError("The Base Model has not been initialized and cannot be cloned") else: cloned_model = type(cls.__baseModel)() # Serialize and deserialize the entire base model to create a deep clone. if hasattr(cls.__baseModel, 'model') and cls.__baseModel.model is not None: buffer = BytesIO() pickle.dump(cls.__baseModel.model, buffer) buffer.seek(0) cloned_model.model = pickle.load(buffer) cloned_model.model_class = cls.__baseModel.model_class cloned_model.pickled_model = True cloned_model.params = copy.deepcopy(cls.__baseModel.params) else: for attribute, value in vars(cls.__baseModel).items(): setattr(cloned_model, attribute, copy.deepcopy(value)) return cloned_model
[docs] @classmethod def reset(cls): """ Resets the singleton instance, allowing for reinitialization. This method clears the current base model, enabling the set_base_model method to set a new base model. """ cls.__baseModel = None