# Path: taipan/api/decorators.py
# def function_decorator(decor):
#     """Decorator for function decorators (sic), written either
#     as classes or functions.
# 
#     In either case, the decorator ``decor`` must be "doubly-callable":
# 
#         * for classes, this means implementing ``__call__`` method
#           in addition to possible ``__init__``
#         * for functions, this means returning a function that acts
#           as an actual decorator, i.e. taking a function and returning
#           its decorated version
# 
#     Although it works for any decorator, it's useful mainly for those
#     that should take optional arguments. If the decorator is adorned
#     with ``@function_decorator``, it's possible to use it without the pair of
#     empty parentheses::
# 
#         @enhanced  # rather than @enhanced()
#         def foo():
#             pass
# 
#     when we don't want to pass any arguments to it.
# 
#     .. note::
# 
#         :func:`function_decorator` makes decorator applicable
#         only to functions. Use :func:`decorator` or :func:`class_decorator`
#         for decorators that should be applicable to classes.
#     """
#     ensure_callable(decor)
#     return _wrap_decorator(decor, "functions", inspect.isfunction)
# 
# def method_decorator(decor):
#     """Decorator for function decorators (sic), written either
#     as classes or functions.
# 
#     In either case, the decorator ``decor`` must be "doubly-callable":
# 
#         * for classes, this means implementing ``__call__`` method
#           in addition to possible ``__init__``
#         * for functions, this means returning a function that acts
#           as an actual decorator, i.e. taking a function and returning
#           its decorated version
# 
#     Although it works for any decorator, it's useful mainly for those
#     that should take optional arguments. If the decorator is adorned
#     with ``@method_decorator``, it's possible to use it without the pair of
#     empty parentheses::
# 
#         class Foo(object):
#             @enhanced  # rather than @enhanced()
#             def foo(self):
#                 pass
# 
#     when we don't want to pass any arguments to it.
# 
#     .. note::
# 
#         :func:`function_decorator` makes decorator applicable
#         only to methods inside a class. Use :func:`decorator`,
#         :func:`function_decorator` or :func:`class_decorator` for decorators
#         that should be applicable to other language constructs.
# 
#     .. versionadded:: 0.0.3
#     """
#     ensure_callable(decor)
#     return _wrap_decorator(decor, "methods", is_method)
# 
# Path: taipan/strings.py
# def ensure_string(s):
#     """Checks whether ``s`` is a string of characters.
#     :return: ``s`` if it is a string of characters
#     :raise TypeError: When ``s` is not a string of characters
#     """
#     if not is_string(s):
#         raise TypeError("expected a string, got %s" % type(s).__name__)
#     return s


from taipan.api.decorators import function_decorator, method_decorator
from taipan.strings import ensure_string
            return object.__getattribute__(self, attr)
        else:
            return getattr(self.method, attr)


class _StageDecorator(object):
    """Base for the decorators that are applicable to :class:`TestCase` methods
    that are to be invoked at various stages of running a test.
    """
    #: Name of the test stage of this decorator.
    stage = None

    #: Tracks the use counters of the specific decorator
    #: to reestablish the proper order of decorated methods.
    use_counter = 0

    def __call__(self, func):
        """Decorate a test case method,
        attaching the stage & order information to it.
        """
        class_ = self.__class__

        counter = class_.use_counter
        class_.use_counter = counter + 1

        return _StageMethod(func, stage=class_.stage, order=counter)


# Specific stage decorators


# Path: taipan/api/decorators.py
# def function_decorator(decor):
#     """Decorator for function decorators (sic), written either
#     as classes or functions.
# 
#     In either case, the decorator ``decor`` must be "doubly-callable":
# 
#         * for classes, this means implementing ``__call__`` method
#           in addition to possible ``__init__``
#         * for functions, this means returning a function that acts
#           as an actual decorator, i.e. taking a function and returning
#           its decorated version
# 
#     Although it works for any decorator, it's useful mainly for those
#     that should take optional arguments. If the decorator is adorned
#     with ``@function_decorator``, it's possible to use it without the pair of
#     empty parentheses::
# 
#         @enhanced  # rather than @enhanced()
#         def foo():
#             pass
# 
#     when we don't want to pass any arguments to it.
# 
#     .. note::
# 
#         :func:`function_decorator` makes decorator applicable
#         only to functions. Use :func:`decorator` or :func:`class_decorator`
#         for decorators that should be applicable to classes.
#     """
#     ensure_callable(decor)
#     return _wrap_decorator(decor, "functions", inspect.isfunction)
# 
# def method_decorator(decor):
#     """Decorator for function decorators (sic), written either
#     as classes or functions.
# 
#     In either case, the decorator ``decor`` must be "doubly-callable":
# 
#         * for classes, this means implementing ``__call__`` method
#           in addition to possible ``__init__``
#         * for functions, this means returning a function that acts
#           as an actual decorator, i.e. taking a function and returning
#           its decorated version
# 
#     Although it works for any decorator, it's useful mainly for those
#     that should take optional arguments. If the decorator is adorned
#     with ``@method_decorator``, it's possible to use it without the pair of
#     empty parentheses::
# 
#         class Foo(object):
#             @enhanced  # rather than @enhanced()
#             def foo(self):
#                 pass
# 
#     when we don't want to pass any arguments to it.
# 
#     .. note::
# 
#         :func:`function_decorator` makes decorator applicable
#         only to methods inside a class. Use :func:`decorator`,
#         :func:`function_decorator` or :func:`class_decorator` for decorators
#         that should be applicable to other language constructs.
# 
#     .. versionadded:: 0.0.3
#     """
#     ensure_callable(decor)
#     return _wrap_decorator(decor, "methods", is_method)
# 
# Path: taipan/strings.py
# def ensure_string(s):
#     """Checks whether ``s`` is a string of characters.
#     :return: ``s`` if it is a string of characters
#     :raise TypeError: When ``s` is not a string of characters
#     """
#     if not is_string(s):
#         raise TypeError("expected a string, got %s" % type(s).__name__)
#     return s


# Path: taipan/testing/decorators.py
from taipan.api.decorators import function_decorator, method_decorator
from taipan.strings import ensure_string

            return object.__getattribute__(self, attr)
        else:
            return getattr(self.method, attr)


class _StageDecorator(object):
    """Base for the decorators that are applicable to :class:`TestCase` methods
    that are to be invoked at various stages of running a test.
    """
    #: Name of the test stage of this decorator.
    stage = None

    #: Tracks the use counters of the specific decorator
    #: to reestablish the proper order of decorated methods.
    use_counter = 0

    def __call__(self, func):
        """Decorate a test case method,
        attaching the stage & order information to it.
        """
        class_ = self.__class__

        counter = class_.use_counter
        class_.use_counter = counter + 1

        return _StageMethod(func, stage=class_.stage, order=counter)


# Specific stage decorators


@function_decorator