# Path: chamber/utils/transaction.py
# def pre_commit(func, using=None):
#     connection = get_connection(using)
# 
#     if connection.in_atomic_block:
#         # Transaction in progress; save for execution on commit.
#         func_hash = hash(func) if isinstance(func, UniquePreCommitCallable) else None
#         if (func_hash is None
#                 or func_hash not in {func_hash for sids, func_hash, func in connection.run_pre_commit}):
#             connection.run_pre_commit.append((set(connection.savepoint_ids), func_hash, func))
# 
#     elif not connection.get_autocommit():
#         raise TransactionManagementError('pre_commit() cannot be used in manual transaction management')
#     else:
#         # No transaction in progress and in autocommit mode; execute immediately.
#         func()
# 
# class UniquePreCommitCallable:
#     """
#     One time callable class that is used for performing on success operations.
#     Handler is callable only once, but data of all calls are stored inside list (kwargs_list).
#     """
# 
#     def __init__(self, **kwargs):
#         self.kwargs_list = (kwargs,)
# 
#     def join(self, callable):
#         """
#         Joins two unique callable.
#         """
#         self.kwargs_list += callable.kwargs_list
# 
#     def _get_unique_id(self):
#         """
#         Callable instance hash is generated from class name and the return value of this method.
#         The method returns None by default, therefore the class init data doesn't have impact.
#         You should implement this method to distinguish callable according to its
#         input data (for example Django model instance)
#         :return:
#         """
#         return None
# 
#     def __hash__(self):
#         return hash((self.__class__, self._get_unique_id()))
# 
#     def _get_kwargs(self):
#         return self.kwargs_list[-1]
# 
#     def __call__(self):
#         self.handle()
# 
#     def handle(self):
#         raise NotImplementedError
# 
# Path: chamber/models/signals.py



from django.core.exceptions import ImproperlyConfigured
from chamber.utils.transaction import pre_commit, UniquePreCommitCallable
from chamber.models.signals import dispatcher_post_save
        """
        `instance` ... instance of the SmartModel where the handler is being called
        Some dispatchers require additional params to evaluate the handler can be dispatched,
        these are hidden in args and kwargs.
        """
        if self.can_handle(instance, **kwargs):
            self._handle(instance, **kwargs)

    def _handle(self, instance, **kwargs):
        self.handle(instance, **kwargs)

    def can_handle(self, instance, **kwargs):
        return True

    def handle(self, instance, **kwargs):
        raise NotImplementedError


class PreCommitHandler(BaseHandler):
    """
    Handler class that is used for performing on success operations.
    """

    signal = dispatcher_post_save

    def __init__(self, using=None, *args, **kwargs):
        self.using = using
        super().__init__(*args, **kwargs)

    def _handle(self, instance, **kwargs):

# Path: chamber/utils/transaction.py
# def pre_commit(func, using=None):
#     connection = get_connection(using)
# 
#     if connection.in_atomic_block:
#         # Transaction in progress; save for execution on commit.
#         func_hash = hash(func) if isinstance(func, UniquePreCommitCallable) else None
#         if (func_hash is None
#                 or func_hash not in {func_hash for sids, func_hash, func in connection.run_pre_commit}):
#             connection.run_pre_commit.append((set(connection.savepoint_ids), func_hash, func))
# 
#     elif not connection.get_autocommit():
#         raise TransactionManagementError('pre_commit() cannot be used in manual transaction management')
#     else:
#         # No transaction in progress and in autocommit mode; execute immediately.
#         func()
# 
# class UniquePreCommitCallable:
#     """
#     One time callable class that is used for performing on success operations.
#     Handler is callable only once, but data of all calls are stored inside list (kwargs_list).
#     """
# 
#     def __init__(self, **kwargs):
#         self.kwargs_list = (kwargs,)
# 
#     def join(self, callable):
#         """
#         Joins two unique callable.
#         """
#         self.kwargs_list += callable.kwargs_list
# 
#     def _get_unique_id(self):
#         """
#         Callable instance hash is generated from class name and the return value of this method.
#         The method returns None by default, therefore the class init data doesn't have impact.
#         You should implement this method to distinguish callable according to its
#         input data (for example Django model instance)
#         :return:
#         """
#         return None
# 
#     def __hash__(self):
#         return hash((self.__class__, self._get_unique_id()))
# 
#     def _get_kwargs(self):
#         return self.kwargs_list[-1]
# 
#     def __call__(self):
#         self.handle()
# 
#     def handle(self):
#         raise NotImplementedError
# 
# Path: chamber/models/signals.py



# Path: chamber/models/handlers.py
from django.core.exceptions import ImproperlyConfigured
from chamber.utils.transaction import pre_commit, UniquePreCommitCallable
from chamber.models.signals import dispatcher_post_save

        """
        `instance` ... instance of the SmartModel where the handler is being called
        Some dispatchers require additional params to evaluate the handler can be dispatched,
        these are hidden in args and kwargs.
        """
        if self.can_handle(instance, **kwargs):
            self._handle(instance, **kwargs)

    def _handle(self, instance, **kwargs):
        self.handle(instance, **kwargs)

    def can_handle(self, instance, **kwargs):
        return True

    def handle(self, instance, **kwargs):
        raise NotImplementedError


class PreCommitHandler(BaseHandler):
    """
    Handler class that is used for performing on success operations.
    """

    signal = dispatcher_post_save

    def __init__(self, using=None, *args, **kwargs):
        self.using = using
        super().__init__(*args, **kwargs)

    def _handle(self, instance, **kwargs):

        pre_commit(lambda: self.handle(instance, **kwargs), using=self.using)