# -*- coding: utf-8 -*-
"""Python's built-in :mod:`functools` module builds several useful
utilities on top of Python's first-class function support.
``typeutils`` attempts to do the same for metaprogramming with types
and instances.
"""

from collections import deque

_issubclass = issubclass


def make_sentinel(name='_MISSING', var_name=None):
    """Creates and returns a new instance of a new class, suitable for
    usage as a "sentinel", a kind of singleton often used to indicate
    a value is missing when ``None`` is a valid input.

    Args:
        name (str): Name of the Sentinel, used in ``__repr__``s
        var_name (str): Set this name to the name of the variable in
            its respective module enable pickleability.

    >>> make_sentinel(var_name='_MISSING')
    _MISSING

    The most common use cases here in boltons are as default values
    for optional function arguments, partly because of its
    less-confusing appearance in automatically generated
    documentation. Sentinels also function well as placeholders in queues
    and linked lists.
    """
    class Sentinel(object):
        def __init__(self):
            self.name = name
            self.var_name = var_name
        def __repr__(self):
            if self.var_name:
                return self.var_name
            return '%s(%r)' % (self.__class__.__name__, self.name)
        if var_name:
            def __reduce__(self):
                return self.var_name
        def __nonzero__(self):
            return False
    return Sentinel()


def issubclass(subclass, baseclass):
    """Just like the built-in :func:`issubclass`, this function checks
    whether *subclass* is inherited from *baseclass*. Unlike the
    built-in function, this ``issubclass`` will simply return
    ``False`` if either argument is not suitable (e.g., if *subclass*
    is not an instance of :class:`type`), instead of raising
    :exc:`TypeError`.

    Args:
        subclass (type): The target class to check.
        baseclass (type): The base class *subclass* will be checked against.

    >>> class MyObject(object): pass
    ...
    >>> issubclass(MyObject, object)  # always a fun fact
    True
    >>> issubclass('hi', 'friend')
    False
    """
    try:
        return _issubclass(subclass, baseclass)
    except TypeError:
        return False


def get_all_subclasses(cls):
    """Recursive method to find all decendents of cls, ie.
    its subclasses, subclasses of those classes, etc.
    Returns a set.

    >>> class A(object):
    ...     pass
    ...
    >>> class B(A):
    ...     pass
    ...
    >>> class C(B):
    ...     pass
    ...
    >>> class D(A):
    ...     pass
    ...
    >>> [t.__name__ for t in get_all_subclasses(A)]
    ['B', 'D', 'C']
    >>> [t.__name__ for t in get_all_subclasses(B)]
    ['C']
    """
    try:
        to_check = deque(cls.__subclasses__())
    except (AttributeError, TypeError):
        raise TypeError('expected type object, not %r' % cls)
    seen, ret = set(), []
    while to_check:
        cur = to_check.popleft()
        if cur in seen:
            continue
        ret.append(cur)
        seen.add(cur)
        to_check.extend(cur.__subclasses__())
    return ret


class classproperty(object):
    """Much like a :func:`property`, but the wrapped get function is a
    class method.  For simplicity, only read-only properties are
    implemented.
    """

    def __init__(self, fn):
        self.fn = fn

    def __get__(self, instance, cls):
        return self.fn(cls)

@@ -374,24 +374,26 @@
 s a new 
+**
 instance
  of a ne
@@ -380,24 +380,26 @@
 w **instance
+**
  of a new cl
@@ -596,31 +596,8 @@
 inel
-, used in %60%60__repr__%60%60s
 %0A   
@@ -1030,24 +1030,24 @@
 s in queues%0A
-
     and link
@@ -1056,16 +1056,303 @@
  lists.%0A
+%0A    .. note::%0A%0A      By design, additional calls to %60%60make_sentinel%60%60 with the same%0A      values will not produce equivalent objects.%0A%0A      %3E%3E%3E make_sentinel('TEST') == make_sentinel('TEST')%0A      False%0A      %3E%3E%3E type(make_sentinel('TEST')) == type(make_sentinel('TEST'))%0A      False%0A%0A
     %22%22%22%0A
@@ -3532,20 +3532,21 @@
 like a :
-func
+class
 :%60proper

add a note about the sentinel