<filename>calleee/_compat.py
"""
Compatibility shims for different Python versions.
"""
from __future__ import absolute_import

try:
    import asyncio
except ImportError:
    asyncio = None
import inspect
import sys


__all__ = [
    'asyncio',
    'IS_PY3',
    'STRING_TYPES', 'casefold',
    'metaclass',
    'getargspec',
]


IS_PY3 = sys.version_info[0] == 3

STRING_TYPES = (str,) if IS_PY3 else (basestring,)
casefold = getattr(str, 'casefold', None) or (lambda s: s.lower())


class MetaclassDecorator(object):
    """Decorator for creating a class through a metaclass.

    Unlike ``__metaclass__`` attribute from Python 2, or ``metaclass=`` keyword
    argument from Python 3, the ``@metaclass`` decorator works with both
    versions of the language.

    Example::

        @metaclass(MyMetaclass)
        class MyClass(object):
            pass
    """
    def __init__(self, meta):
        if not issubclass(meta, type):
            raise TypeError(
                "expected a metaclass, got %s instead" % type(meta).__name__)
        self.metaclass = meta

    def __call__(self, cls):
        """Apply the decorator to given class.

        This recreates the class using the previously supplied metaclass.
        """
        # Copyright (c) Django Software Foundation and individual contributors.
        # All rights reserved.

        original_dict = cls.__dict__.copy()
        original_dict.pop('__dict__', None)
        original_dict.pop('__weakref__', None)

        slots = original_dict.get('__slots__')
        if slots is not None:
            if isinstance(slots, str):
                slots = [slots]
            for slot in slots:
                original_dict.pop(slot)

        return self.metaclass(cls.__name__, cls.__bases__, original_dict)

metaclass = MetaclassDecorator
del MetaclassDecorator


def getargspec(obj):
    """Portable version of inspect.getargspec().
    Since we dropped 2.7, this has to be deprecated.

    Necessary because the original is no longer available
    starting from Python 3.6.

    :return: 4-tuple of (argnames, varargname, kwargname, defaults)

    Note that distinction between positional-or-keyword and keyword-only
    parameters will be lost, as the original getargspec() doesn't honor it.
    """

    # translate the signature object back into the 4-tuple
    argnames = []
    varargname, kwargname = None, None
    defaults = []
    for name, param in inspect.signature(obj):
        if param.kind == inspect.Parameter.VAR_POSITIONAL:
            varargname = name
        elif param.kind == inspect.Parameter.VAR_KEYWORD:
            kwargname = name
        else:
            argnames.append(name)
            if param.default is not inspect.Parameter.empty:
                defaults.append(param.default)
    defaults = defaults or None

    return argnames, varargname, kwargname, defaults

<filename>calleee/_compat.py
"""
Compatibility shims for different Python versions.
"""
from __future__ import absolute_import

try:
    import asyncio
except ImportError:
    asyncio = None
import inspect
import sys


__all__ = [
    'asyncio',
    'IS_PY3',
    'STRING_TYPES', 'casefold',
    'metaclass',
    'getargspec',
]


IS_PY3 = sys.version_info[0] == 3

STRING_TYPES = (str,) if IS_PY3 else (basestring,)
casefold = getattr(str, 'casefold', None) or (lambda s: s.lower())


class MetaclassDecorator(object):
    """Decorator for creating a class through a metaclass.

    Unlike ``__metaclass__`` attribute from Python 2, or ``metaclass=`` keyword
    argument from Python 3, the ``@metaclass`` decorator works with both
    versions of the language.

    Example::

        @metaclass(MyMetaclass)
        class MyClass(object):
            pass
    """
    def __init__(self, meta):
        if not issubclass(meta, type):
            raise TypeError(
                "expected a metaclass, got %s instead" % type(meta).__name__)
        self.metaclass = meta

    def __call__(self, cls):
        """Apply the decorator to given class.

        This recreates the class using the previously supplied metaclass.
        """
        # Copyright (c) Django Software Foundation and individual contributors.
        # All rights reserved.

        original_dict = cls.__dict__.copy()
        original_dict.pop('__dict__', None)
        original_dict.pop('__weakref__', None)

        slots = original_dict.get('__slots__')
        if slots is not None:
            if isinstance(slots, str):
                slots = [slots]
            for slot in slots:
                original_dict.pop(slot)

        return self.metaclass(cls.__name__, cls.__bases__, original_dict)

metaclass = MetaclassDecorator
del MetaclassDecorator


def getargspec(obj):
    """Portable version of inspect.getargspec().
    Since we dropped 2.7, this has to be deprecated.

    Necessary because the original is no longer available
    starting from Python 3.6.

    :return: 4-tuple of (argnames, varargname, kwargname, defaults)

    Note that distinction between positional-or-keyword and keyword-only
    parameters will be lost, as the original getargspec() doesn't honor it.
    """

    # translate the signature object back into the 4-tuple
    argnames = []
    varargname, kwargname = None, None
    defaults = []
    for name, param in inspect.signature(obj):
        if param.kind == inspect.Parameter.VAR_POSITIONAL:
            varargname = name
        elif param.kind == inspect.Parameter.VAR_KEYWORD:
            kwargname = name
        else:
            argnames.append(name)
            if param.default is not inspect.Parameter.empty:
                defaults.append(param.default)
    defaults = defaults or None

    return argnames, varargname, kwargname, defaults

Compatibility shims for different Python versions. Decorator for creating a class through a metaclass.      Unlike ``__metaclass__`` attribute from Python 2, or ``metaclass=`` keyword     argument from Python 3, the ``@metaclass`` decorator works with both     versions of the language.      Example::          @metaclass(MyMetaclass)         class MyClass(object):             pass Apply the decorator to given class.          This recreates the class using the previously supplied metaclass. # Copyright (c) Django Software Foundation and individual contributors. # All rights reserved. Portable version of inspect.getargspec().     Since we dropped 2.7, this has to be deprecated.      Necessary because the original is no longer available     starting from Python 3.6.      :return: 4-tuple of (argnames, varargname, kwargname, defaults)      Note that distinction between positional-or-keyword and keyword-only     parameters will be lost, as the original getargspec() doesn't honor it. # translate the signature object back into the 4-tuple