import logbook
from . import hooks

_LOGGER_NAME = "slash.step"
_STEP_LOG_LEVEL = logbook.NOTICE

_logger = logbook.Logger(_LOGGER_NAME)


class Step(object):

    def __init__(self, msg, *args, **kwargs):
        super(Step, self).__init__()
        self.message = msg.format(*args, **kwargs) if args or kwargs else msg

    def __str__(self):
        return self.message

    def __repr__(self):
        return "<Step {0!r}>".format(self.message)

    def _start(self):
        _logger.log(_STEP_LOG_LEVEL, self.message)
        hooks.step_start.trigger({})

    def _success(self):
        hooks.step_success.trigger({})

    def _error(self):
        hooks.step_error.trigger({})

    def _end(self):
        hooks.step_end.trigger({})

    def __enter__(self):
        self._start()
        return self

    def __exit__(self, exc_type, exc_value, exc_tb):
        try:
            if exc_type is None:
                self._success()
            else:
                self._error()
        finally:
            self._end()

@@ -27,16 +27,1230 @@
 rt hooks
+%0Aimport inspect%0A%0Adef caller_name(skip=2):%0A    %22%22%22Get a name of a caller in the format module.class.method%0A%0A       %60skip%60 specifies how many levels of stack to skip while getting caller%0A       name. skip=1 means %22who calls me%22, skip=2 %22who calls my caller%22 etc.%0A%0A       An empty string is returned if skipped levels exceed stack height%0A    %22%22%22%0A    stack = inspect.stack()%0A    start = 0 + skip%0A    if len(stack) %3C start + 1:%0A      return ''%0A    parentframe = stack%5Bstart%5D%5B0%5D%0A%0A    name = %5B%5D%0A    module = inspect.getmodule(parentframe)%0A    # %60modname%60 can be None when frame is executed directly in console%0A    # TODO(techtonik): consider using __main__%0A    if module:%0A        name.append(module.__name__)%0A    # detect classname%0A    if 'self' in parentframe.f_locals:%0A        # I don't know any way to detect call from the object method%0A        # XXX: there seems to be no way to detect static method call - it will%0A        #      be just a function call%0A        name.append(parentframe.f_locals%5B'self'%5D.__class__.__name__)%0A    codename = parentframe.f_code.co_name%0A    if codename != '%3Cmodule%3E':  # top level usually%0A        name.append( codename ) # function or a method%0A    del parentframe%0A    return %22.%22.join(name)
 %0A%0A_LOGGE
@@ -1527,16 +1527,59 @@
 else msg
+%0A        self.context = repr(caller_name())
 %0A%0A    de
@@ -1799,32 +1799,80 @@
 _start.trigger(%7B
+%22message%22: self.message, %22context%22: self.context
 %7D)%0A%0A    def _suc
@@ -1911,32 +1911,80 @@
 uccess.trigger(%7B
+%22message%22: self.message, %22context%22: self.context
 %7D)%0A%0A    def _err
@@ -2019,32 +2019,80 @@
 _error.trigger(%7B
+%22message%22: self.message, %22context%22: self.context
 %7D)%0A%0A    def _end
@@ -2131,16 +2131,64 @@
 rigger(%7B
+%22message%22: self.message, %22context%22: self.context
 %7D)%0A%0A    

add message and context to hooks call