# Path: taipan/_compat.py
# IS_PY26 = sys.version_info[:2] == (2, 6)
# IS_PY3 = sys.version_info[0] == 3
# class MetaclassDecorator(object):
#     def __init__(self, meta):
#     def __call__(self, cls):
# 
# Path: taipan/algorithms.py
# def breadth_first(start, expand):
#     """Performs a breadth-first search of a graph-like structure.
# 
#     :param start: Node to start the search from
#     :param expand: Function taking a node as an argument and returning iterable
#                    of its child nodes
# 
#     :return: Iterable of nodes in the BFS order
# 
#     Example::
# 
#         tree = json.loads(some_data)
#         for item in breadth_first(tree, key_func('children', default=())):
#             do_something_with(item)
#     """
#     ensure_callable(expand)
# 
#     def generator():
#         queue = deque([start])
#         while queue:
#             node = queue.popleft()
#             yield node
#             queue.extend(expand(node))
# 
#     return generator()
# 
# Path: taipan/api/decorators.py
# def _wrap_decorator(decorator, targets, is_valid_target):
#     """Wraps given decorator in order to provide additional functionality:
#     optional arguments and verification of decorator's target type.
# 
#     :param decorator: Decorator callable
#     :param targets: Name of the decorator targets, as plural
#                     (used in error messages)
#     :param is_valid_target: Callable for checking
#                             whether decorator's target is valid
# 
#     :return: Wrapped ``decorator``
#     """
#     @functools.wraps(decorator)
#     def wrapper(*args, **kwargs):
#         # handle the case when decorator is applied as ``@decorator``
#         # (without any parameters and parentheses)
#         one_arg = len(args) == 1 and not kwargs
#         if one_arg and is_valid_target(args[0]):
#             actual_decorator = decorator()
#             return actual_decorator(args[0])
# 
#         # pass the parameters to decorator callable
#         # to get the actual decorator that can be applied to targets
#         actual_decorator = decorator(*args, **kwargs)
#         # TODO(xion): The above raises TypeError with confusing message
#         # ("<class>.__new__() takes no parameters") when function decorator
#         # is applied to a class. See if we can detect that and do better.
# 
#         # wrap it inside a function that verifies
#         # whether a target that user has given is valid for this decorator
#         def decorator_wrapper(target):
#             if not is_valid_target(target):
#                 raise TypeError(
#                     "@%s can only be applied to %s: got %r instead" % (
#                         decorator.__name__, targets, type(target)))
#             return actual_decorator(target)
# 
#         return decorator_wrapper
# 
#     return wrapper
# 
# Path: taipan/functional/combinators.py
# def and_(*fs):
#     """Creates a function that returns true for given arguments
#     iff every given function evalutes to true for those arguments.
# 
#     :param fs: Functions to combine
# 
#     :return: Short-circuiting function performing logical conjunction
#              on results of ``fs`` applied to its arguments
#     """
#     ensure_argcount(fs, min_=1)
#     fs = list(imap(ensure_callable, fs))
# 
#     if len(fs) == 1:
#         return fs[0]
#     if len(fs) == 2:
#         f1, f2 = fs
#         return lambda *args, **kwargs: (
#             f1(*args, **kwargs) and f2(*args, **kwargs))
#     if len(fs) == 3:
#         f1, f2, f3 = fs
#         return lambda *args, **kwargs: (
#             f1(*args, **kwargs) and f2(*args, **kwargs) and f3(*args, **kwargs))
# 
#     def g(*args, **kwargs):
#         for f in fs:
#             if not f(*args, **kwargs):
#                 return False
#         return True
# 
#     return g
# 
# def not_(f):
#     """Creates a function that returns a Boolean negative of provided function.
# 
#     :param f: Function to create a Boolean negative of
# 
#     :return: Function ``g`` such that ``g(<args>) == not f(<args>)``
#              for any ``<args>``
#     """
#     ensure_callable(f)
#     return lambda *args, **kwargs: not f(*args, **kwargs)


import inspect
from taipan._compat import metaclass
from taipan.algorithms import breadth_first
from taipan.api.decorators import _wrap_decorator
from taipan.functional.combinators import and_, not_
    :return: ``class_``, if the check succeeds
    :raise TypeError: When the check fails

    .. versionadded:: 0.0.4
    """
    if not is_indirect_subclass(class_, of):
        raise TypeError(
            "expected an indirect subclass of %r, got %s instead" % (
                of, class_.__name__))
    return class_


# Class utilities

def iter_subclasses(class_):
    """Iterate over all the subclasses (and subclasses thereof, etc.)
    of given class.

    :param class_: Class to yield the subclasses of
    :return: Iterable of subclasses, sub-subclasses, etc. of ``class_``
    """
    ensure_class(class_)

    classes = set()

    def descend(class_):
        subclasses = set(class_.__subclasses__()) - classes
        classes.update(subclasses)
        return subclasses


# Path: taipan/_compat.py
# IS_PY26 = sys.version_info[:2] == (2, 6)
# IS_PY3 = sys.version_info[0] == 3
# class MetaclassDecorator(object):
#     def __init__(self, meta):
#     def __call__(self, cls):
# 
# Path: taipan/algorithms.py
# def breadth_first(start, expand):
#     """Performs a breadth-first search of a graph-like structure.
# 
#     :param start: Node to start the search from
#     :param expand: Function taking a node as an argument and returning iterable
#                    of its child nodes
# 
#     :return: Iterable of nodes in the BFS order
# 
#     Example::
# 
#         tree = json.loads(some_data)
#         for item in breadth_first(tree, key_func('children', default=())):
#             do_something_with(item)
#     """
#     ensure_callable(expand)
# 
#     def generator():
#         queue = deque([start])
#         while queue:
#             node = queue.popleft()
#             yield node
#             queue.extend(expand(node))
# 
#     return generator()
# 
# Path: taipan/api/decorators.py
# def _wrap_decorator(decorator, targets, is_valid_target):
#     """Wraps given decorator in order to provide additional functionality:
#     optional arguments and verification of decorator's target type.
# 
#     :param decorator: Decorator callable
#     :param targets: Name of the decorator targets, as plural
#                     (used in error messages)
#     :param is_valid_target: Callable for checking
#                             whether decorator's target is valid
# 
#     :return: Wrapped ``decorator``
#     """
#     @functools.wraps(decorator)
#     def wrapper(*args, **kwargs):
#         # handle the case when decorator is applied as ``@decorator``
#         # (without any parameters and parentheses)
#         one_arg = len(args) == 1 and not kwargs
#         if one_arg and is_valid_target(args[0]):
#             actual_decorator = decorator()
#             return actual_decorator(args[0])
# 
#         # pass the parameters to decorator callable
#         # to get the actual decorator that can be applied to targets
#         actual_decorator = decorator(*args, **kwargs)
#         # TODO(xion): The above raises TypeError with confusing message
#         # ("<class>.__new__() takes no parameters") when function decorator
#         # is applied to a class. See if we can detect that and do better.
# 
#         # wrap it inside a function that verifies
#         # whether a target that user has given is valid for this decorator
#         def decorator_wrapper(target):
#             if not is_valid_target(target):
#                 raise TypeError(
#                     "@%s can only be applied to %s: got %r instead" % (
#                         decorator.__name__, targets, type(target)))
#             return actual_decorator(target)
# 
#         return decorator_wrapper
# 
#     return wrapper
# 
# Path: taipan/functional/combinators.py
# def and_(*fs):
#     """Creates a function that returns true for given arguments
#     iff every given function evalutes to true for those arguments.
# 
#     :param fs: Functions to combine
# 
#     :return: Short-circuiting function performing logical conjunction
#              on results of ``fs`` applied to its arguments
#     """
#     ensure_argcount(fs, min_=1)
#     fs = list(imap(ensure_callable, fs))
# 
#     if len(fs) == 1:
#         return fs[0]
#     if len(fs) == 2:
#         f1, f2 = fs
#         return lambda *args, **kwargs: (
#             f1(*args, **kwargs) and f2(*args, **kwargs))
#     if len(fs) == 3:
#         f1, f2, f3 = fs
#         return lambda *args, **kwargs: (
#             f1(*args, **kwargs) and f2(*args, **kwargs) and f3(*args, **kwargs))
# 
#     def g(*args, **kwargs):
#         for f in fs:
#             if not f(*args, **kwargs):
#                 return False
#         return True
# 
#     return g
# 
# def not_(f):
#     """Creates a function that returns a Boolean negative of provided function.
# 
#     :param f: Function to create a Boolean negative of
# 
#     :return: Function ``g`` such that ``g(<args>) == not f(<args>)``
#              for any ``<args>``
#     """
#     ensure_callable(f)
#     return lambda *args, **kwargs: not f(*args, **kwargs)


# Path: taipan/objective/classes.py
import inspect
from taipan._compat import metaclass
from taipan.algorithms import breadth_first
from taipan.api.decorators import _wrap_decorator
from taipan.functional.combinators import and_, not_

    :return: ``class_``, if the check succeeds
    :raise TypeError: When the check fails

    .. versionadded:: 0.0.4
    """
    if not is_indirect_subclass(class_, of):
        raise TypeError(
            "expected an indirect subclass of %r, got %s instead" % (
                of, class_.__name__))
    return class_


# Class utilities

def iter_subclasses(class_):
    """Iterate over all the subclasses (and subclasses thereof, etc.)
    of given class.

    :param class_: Class to yield the subclasses of
    :return: Iterable of subclasses, sub-subclasses, etc. of ``class_``
    """
    ensure_class(class_)

    classes = set()

    def descend(class_):
        subclasses = set(class_.__subclasses__()) - classes
        classes.update(subclasses)
        return subclasses


    result = breadth_first(class_, descend)