# Path: pynads/utils/internal.py
# def _get_name(obj):
#     """Attempts to extract name from a given object.
#     """
#     try:
#         # interop with functools.partial and objects that emulate it
#         if hasattr(obj, 'func') and hasattr(obj.func, '__name__'):
#             return "partialed {!s}".format(obj.func.__name__)
#         # callable object that isn't a function
#         elif not isfunction(obj) and hasattr(obj, '__class__'):
#             return obj.__class__.__name__
#         # must be just a regular function
#         else:
#             return obj.__name__
#     except AttributeError:
#         return ''


import sys
from functools import WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES, partial
from .internal import _get_name
    from functools import reduce
    from itertools import filterfalse
    from itertools import (imap as map, ifilter as filter,
                           izip as zip, ifilterfalse as filterfalse)
else:
    range = xrange
    reduce = reduce


# backport Python 3.4's update_wrapper to avoid silliness
# has much smarter behavior than previous implementations of it
def update_wrapper(wrapper,
                   wrapped,
                   assigned=WRAPPER_ASSIGNMENTS,
                   updated=WRAPPER_UPDATES):
    """Makes a wrapper appear as the wrapped object.

    This is a backport of Python 3.4's `functools.update_wrapper`. This version
    is more intelligent than what's found in Python 2 as it uses a try-block
    when attempting to move attributes rather than just charitably assuming
    all of the attributes exist on the wrapped object.

    It also backports Python 3.3+'s `__wrapped__` attribute as well, which
    gives easy access to the original object.

    This function *always* modifies the wrapping object.
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            # apply some custom magic to extract a name off certain
            # types of objects such as partial and actual objects
            if attr == '__name__':

# Path: pynads/utils/internal.py
# def _get_name(obj):
#     """Attempts to extract name from a given object.
#     """
#     try:
#         # interop with functools.partial and objects that emulate it
#         if hasattr(obj, 'func') and hasattr(obj.func, '__name__'):
#             return "partialed {!s}".format(obj.func.__name__)
#         # callable object that isn't a function
#         elif not isfunction(obj) and hasattr(obj, '__class__'):
#             return obj.__class__.__name__
#         # must be just a regular function
#         else:
#             return obj.__name__
#     except AttributeError:
#         return ''


# Path: pynads/utils/compat.py
import sys
from functools import WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES, partial
from .internal import _get_name
    from functools import reduce
    from itertools import filterfalse
    from itertools import (imap as map, ifilter as filter,
                           izip as zip, ifilterfalse as filterfalse)

else:
    range = xrange
    reduce = reduce


# backport Python 3.4's update_wrapper to avoid silliness
# has much smarter behavior than previous implementations of it
def update_wrapper(wrapper,
                   wrapped,
                   assigned=WRAPPER_ASSIGNMENTS,
                   updated=WRAPPER_UPDATES):
    """Makes a wrapper appear as the wrapped object.

    This is a backport of Python 3.4's `functools.update_wrapper`. This version
    is more intelligent than what's found in Python 2 as it uses a try-block
    when attempting to move attributes rather than just charitably assuming
    all of the attributes exist on the wrapped object.

    It also backports Python 3.3+'s `__wrapped__` attribute as well, which
    gives easy access to the original object.

    This function *always* modifies the wrapping object.
    """
    for attr in assigned:
        try:
            value = getattr(wrapped, attr)
        except AttributeError:
            # apply some custom magic to extract a name off certain
            # types of objects such as partial and actual objects
            if attr == '__name__':

                value = _get_name(wrapped)