# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.

"""Abstract Base Classes (ABCs) according to PEP 3119."""


def abstractmethod(funcobj):
    """A decorator indicating abstract methods.

    Requires that the metaclass is ABCMeta or derived from it.  A
    class that has a metaclass derived from ABCMeta cannot be
    instantiated unless all of its abstract methods are overridden.
    The abstract methods can be called using any of the the normal
    'super' call mechanisms.

    Usage:

        class C(metaclass=ABCMeta):
            @abstractmethod
            def my_abstract_method(self, ...):
                ...
    """
    funcobj.__isabstractmethod__ = True
    return funcobj


class abstractproperty(property):
    """A decorator indicating abstract properties.

    Requires that the metaclass is ABCMeta or derived from it.  A
    class that has a metaclass derived from ABCMeta cannot be
    instantiated unless all of its abstract properties are overridden.
    The abstract properties can be called using any of the the normal
    'super' call mechanisms.

    Usage:

        class C(metaclass=ABCMeta):
            @abstractproperty
            def my_abstract_property(self):
                ...

    This defines a read-only property; you can also define a read-write
    abstract property using the 'long' form of property declaration:

        class C(metaclass=ABCMeta):
            def getx(self): ...
            def setx(self, value): ...
            x = abstractproperty(getx, setx)
    """
    __isabstractmethod__ = True


class _Abstract(object):

    """Helper class inserted into the bases by ABCMeta (using _fix_bases()).

    You should never need to explicitly subclass this class.

    There should never be a base class between _Abstract and object.
    """

    def __new__(cls, *args, **kwds):
        am = cls.__dict__.get("__abstractmethods__")
        if am:
            raise TypeError("Can't instantiate abstract class %s "
                            "with abstract methods %s" %
                            (cls.__name__, ", ".join(sorted(am))))
        if (args or kwds) and cls.__init__ is object.__init__:
            raise TypeError("Can't pass arguments to __new__ "
                            "without overriding __init__")
        return object.__new__(cls)

    @classmethod
    def __subclasshook__(cls, subclass):
        """Abstract classes can override this to customize issubclass().

        This is invoked early on by __subclasscheck__() below.  It
        should return True, False or NotImplemented.  If it returns
        NotImplemented, the normal algorithm is used.  Otherwise, it
        overrides the normal algorithm (and the outcome is cached).
        """
        return NotImplemented


def _fix_bases(bases):
    """Helper method that inserts _Abstract in the bases if needed."""
    for base in bases:
        if issubclass(base, _Abstract):
            # _Abstract is already a base (maybe indirectly)
            return bases
    if object in bases:
        # Replace object with _Abstract
        return tuple([_Abstract if base is object else base
                      for base in bases])
    # Append _Abstract to the end
    return bases + (_Abstract,)


class ABCMeta(type):

    """Metaclass for defining Abstract Base Classes (ABCs).

    Use this metaclass to create an ABC.  An ABC can be subclassed
    directly, and then acts as a mix-in class.  You can also register
    unrelated concrete classes (even built-in classes) and unrelated
    ABCs as 'virtual subclasses' -- these and their descendants will
    be considered subclasses of the registering ABC by the built-in
    issubclass() function, but the registering ABC won't show up in
    their MRO (Method Resolution Order) nor will method
    implementations defined by the registering ABC be callable (not
    even via super()).

    """

    # A global counter that is incremented each time a class is
    # registered as a virtual subclass of anything.  It forces the
    # negative cache to be cleared before its next use.
    __invalidation_counter = 0

    def __new__(mcls, name, bases, namespace):
        bases = _fix_bases(bases)
        cls = super().__new__(mcls, name, bases, namespace)
        # Compute set of abstract method names
        abstracts = {name
                     for name, value in namespace.items()
                     if getattr(value, "__isabstractmethod__", False)}
        for base in bases:
            for name in getattr(base, "__abstractmethods__", set()):
                value = getattr(cls, name, None)
                if getattr(value, "__isabstractmethod__", False):
                    abstracts.add(name)
        cls.__abstractmethods__ = abstracts
        # Set up inheritance registry
        cls.__registry = set()
        cls.__cache = set()
        cls.__negative_cache = set()
        cls.__negative_cache_version = ABCMeta.__invalidation_counter
        return cls

    def register(cls, subclass):
        """Register a virtual subclass of an ABC."""
        if not isinstance(cls, type):
            raise TypeError("Can only register classes")
        if issubclass(subclass, cls):
            return  # Already a subclass
        # Subtle: test for cycles *after* testing for "already a subclass";
        # this means we allow X.register(X) and interpret it as a no-op.
        if issubclass(cls, subclass):
            # This would create a cycle, which is bad for the algorithm below
            raise RuntimeError("Refusing to create an inheritance cycle")
        cls.__registry.add(subclass)
        ABCMeta.__invalidation_counter += 1  # Invalidate negative cache

    def _dump_registry(cls, file=None):
        """Debug helper to print the ABC registry."""
        print("Class: %s.%s" % (cls.__module__, cls.__name__), file=file)
        print("Inv.counter: %s" % ABCMeta.__invalidation_counter, file=file)
        for name in sorted(cls.__dict__.keys()):
            if name.startswith("__abc_"):
                value = getattr(cls, name)
                print("%s: %r" % (name, value), file=file)

    def __instancecheck__(cls, instance):
        """Override for isinstance(instance, cls)."""
        return any(cls.__subclasscheck__(c)
                   for c in {instance.__class__, type(instance)})

    def __subclasscheck__(cls, subclass):
        """Override for issubclass(subclass, cls)."""
        # Check cache
        if subclass in cls.__cache:
            return True
        # Check negative cache; may have to invalidate
        if cls.__negative_cache_version < ABCMeta.__invalidation_counter:
            # Invalidate the negative cache
            cls.__negative_cache_version = ABCMeta.__invalidation_counter
            cls.__negative_cache = set()
        elif subclass in cls.__negative_cache:
            return False
        # Check the subclass hook
        ok = cls.__subclasshook__(subclass)
        if ok is not NotImplemented:
            assert isinstance(ok, bool)
            if ok:
                cls.__cache.add(subclass)
            else:
                cls.__negative_cache.add(subclass)
            return ok
        # Check if it's a direct subclass
        if cls in subclass.__mro__:
            cls.__cache.add(subclass)
            return True
        # Check if it's a subclass of a registered class (recursive)
        for rcls in cls.__registry:
            if issubclass(subclass, rcls):
                cls.__registry.add(subclass)
                return True
        # Check if it's a subclass of a subclass (recursive)
        for scls in cls.__subclasses__():
            if issubclass(subclass, scls):
                cls.__registry.add(subclass)
                return True
        # No dice; update negative cache
        cls.__negative_cache.add(subclass)
        return False
