''' This Module contains Generic abstract classes. ''' from abc import ABCMeta, abstractmethod from typing import cast, Any, TypeVar # from celery import Task abs_attr_type = TypeVar('abs_attr_type') class DummyAttribute: ''' A Dummy Type for abstract_attribute to return. ''' pass def abstract_attribute(obj = None, type_ = Any) -> abs_attr_type: ''' Use this to make abstract attributes of given type. ____________________________________________________________________________ Arguments: obj : Any -> It takes the object when using it as a decorator. type_ : Any -> Provide the type of variable you want to declear. (Default = Any) ''' _obj = cast(type_, obj) if obj is None: _obj = DummyAttribute() _obj.__is_abstract_attribute__ = True # type: ignore return cast(abs_attr_type, _obj) class MyABCMeta(ABCMeta): def __call__(cls, *args, **kwargs): instance = ABCMeta.__call__(cls, *args, **kwargs) abstract_attributes = { name for name in dir(instance) if getattr(getattr(instance, name), '__is_abstract_attribute__', False) } if abstract_attributes: raise NotImplementedError( "Can't instantiate abstract class {} with" " abstract attributes: {}".format( cls.__name__, ', '.join(abstract_attributes) ) ) # return instance # class GenericCeleryTask(Task,metaclass=MyABCMeta): # ''' # This is a Abstract Class for implementation of Classs-Based # Celery Tasks for MNF. # It contains all the necessary methods that must be implemented # by and any class inheriting it to be in-lined with the integration. # Do read the doc-scrings of each method for insites. # ____________________________________________________________________________ # This Class itself inherits from Task which is the main Class for # celery class-bases task implementation. # For reference of implementation of GenericCeleryTask, checkout neutralAudit # /tasks.py. # ____________________________________________________________________________ # By Amulya Paritosh # ''' # track_started = True # ''' # If enabled the task will report its status as 'started' when the task # is executed by a worker. Disabled by default as the normal behavior # is to not report that level of granularity. Tasks are either pending, # finished, or waiting to be retried. # ''' # name : str = abstract_attribute(type_ = str) # ''' # This is an attribute which must be defined. # `name = ` # ''' # soft_time_limit : int = abstract_attribute(type_ = int) # ''' # This is an attribute which must be defined. # This is the time limit for which the task will run. If this time limit # is exceeded, SoftTimeLimitExceeded error will be raised. # ''' # @abstractmethod # def to_run(self) -> bool: # ''' # Put logic of checking if the queued task is to be run or not. # This to_run function is the part of 2nd block of `run()` method (check out # `run()` method to know more about the logic blocks of running the task). # This method must be called in `run()` method. # ''' # ... # @abstractmethod # def after_return(self, status, retval, task_id, args, kwargs, einfo) -> None: # ''' # Handler called after the task returns. # This method is called when the task returns irrespective of its success or # failure. # Can be used for freeing resources and deleting objects. # ____________________________________________________________________________ # Arguments: # status (str): Current task state. # retval (Any): Task return value/exception. # task_id (str): Unique id of the task. # args (Tuple): Original arguments for the task. # kwargs (Dict): Original keyword arguments for the task. # einfo (~billiard.einfo.ExceptionInfo): Exception information. # ____________________________________________________________________________ # Returns: # None: The return value of this handler is ignored. # ''' # ... # @abstractmethod # def on_failure(self, exc, task_id, args, kwargs, einfo) -> None: # ''' # Error handler. # This is run by the worker when the task fails. # Put a control for expected exceptions here for their special handling. # Check with `is_expected_exceptions()` static classmethod. # ____________________________________________________________________________ # Arguments: # exc (Exception): The exception raised by the task. # task_id (str): Unique id of the failed task. # args (Tuple): Original arguments for the task that failed. # kwargs (Dict): Original keyword arguments for the task that failed. # einfo (~billiard.einfo.ExceptionInfo): Exception information. # ____________________________________________________________________________ # Returns: # None: The return value of this handler is ignored. # ''' # ... # @abstractmethod # def on_success(self, retval, task_id, args, kwargs) -> None: # ''' # Success handler. # Run by the worker if the task executes successfully. # ____________________________________________________________________________ # Arguments: # retval (Any): The return value of the task. # task_id (str): Unique id of the executed task. # args (Tuple): Original arguments for the executed task. # kwargs (Dict): Original keyword arguments for the executed task. # ____________________________________________________________________________ # Returns: # None: The return value of this handler is ignored. # ''' # ... # @abstractmethod # def on_retry(self, exc, task_id, args, kwargs, einfo) -> None: # ''' # Retry handler. # This is run by the worker when the task is to be retried. # ____________________________________________________________________________ # Arguments: # exc (Exception): The exception sent to :meth:`retry`. # task_id (str): Unique id of the retried task. # args (Tuple): Original arguments for the retried task. # kwargs (Dict): Original keyword arguments for the retried task. # einfo (~billiard.einfo.ExceptionInfo): Exception information. # ____________________________________________________________________________ # Returns: # None: The return value of this handler is ignored. # ''' # ... # @abstractmethod # def run(self, *args, **kwargs) -> None: # ''' # The body of the task executed by workers. Here write the main code blocks to # be run. # The Logic should be written in 3 blocks (its just a convention) # block1 : initialization of certian required fields. # block2 : check if to go ahed with the execution with to_run() method. # block3 : main block of the code to run. # ''' # ... # @classmethod # def is_expected_exceptions(cls, exc) -> bool: # ''' # This checks if the provided exception was expected or not. # ____________________________________________________________________________ # Returns : # bool # ''' # return isinstance(exc, cls.throws) class ABCFileType(metaclass=MyABCMeta): """ All FileTypes to inherit it. Contains some must have attributes. """ allowed_extentions : tuple = abstract_attribute(type_ = tuple) def validate() -> bool: return True