code: def run(self):
          
          if self.on_start:
              self.on_start(self)
  
          try:
              result = self.func(*self.func_args, **self.func_kwargs)
          except Exception as err:
              self.to_failed()
  
              if self.on_error:
                  self.on_error(self, err)
  
              raise
  
          self.to_success()
  
          if self.on_success:
              self.on_success(self, result)
  
          return result
docs: Runs the task.
  
          This fires the ``on_start`` hook function first (if present), passing
          the task itself.
  
          Then it runs the target function supplied via ``Task.to_call`` with
          its arguments & stores the result.
  
          If the target function succeeded, the ``on_success`` hook function is
          called, passing both the task & the result to it.
  
          If the target function failed (threw an exception), the ``on_error``
          hook function is called, passing both the task & the exception to it.
          Then the exception is re-raised.
  
          Finally, the result is returned.