Repository: numpy/numpy
File: numpy/_utils/__init__.py (Python)

Code before:
Everything in here must be self-contained so that it can be
imported anywhere else without creating circular imports.
If a utility requires the import of NumPy, it probably belongs
in ``numpy._core``.
"""

import functools
import warnings
from ._convertions import asunicode, asbytes


def set_module(module):
    """Private decorator for overriding __module__ on a function or class.

    Example usage::

        @set_module('numpy')
        def example():
            pass

        assert example.__module__ == 'numpy'
    """
    def decorator(func):
        if module is not None:
            if isinstance(func, type):
                func._module_source = func.__module__

            func.__module__ = module
        return func
    return decorator


def _rename_parameter(old_names, new_names, dep_version=None):
    """
    Generate decorator for backward-compatible keyword renaming.

    Apply the decorator generated by `_rename_parameter` to functions with a
    renamed parameter to maintain backward-compatibility.

    After decoration, the function behaves as follows:
    If only the new parameter is passed into the function, behave as usual.
    If only the old parameter is passed into the function (as a keyword), raise
    a DeprecationWarning if `dep_version` is provided, and behave as usual
    otherwise.
    If both old and new parameters are passed into the function, raise a
    DeprecationWarning if `dep_version` is provided, and raise the appropriate
    TypeError (function got multiple values for argument).

    Parameters
    ----------
    old_names : list of str

Review comment (suggestion):
This could still raise an `AttributeError`, e.g. in case it's a metaclass with `__slots__` or a custom `__setattr__` or something. I'm not sure if it'll occur in practice, but I'm guessing that the `except AttributeError` was there for that reason.

Code after:
Everything in here must be self-contained so that it can be
imported anywhere else without creating circular imports.
If a utility requires the import of NumPy, it probably belongs
in ``numpy._core``.
"""

import functools
import warnings
from ._convertions import asunicode, asbytes


def set_module(module):
    """Private decorator for overriding __module__ on a function or class.

    Example usage::

        @set_module('numpy')
        def example():
            pass

        assert example.__module__ == 'numpy'
    """
    def decorator(func):
        if module is not None:
            if isinstance(func, type):
                try:
                    func._module_source = func.__module__
                except (AttributeError):
                    pass

            func.__module__ = module
        return func
    return decorator


def _rename_parameter(old_names, new_names, dep_version=None):
    """
    Generate decorator for backward-compatible keyword renaming.

    Apply the decorator generated by `_rename_parameter` to functions with a
    renamed parameter to maintain backward-compatibility.

    After decoration, the function behaves as follows:
    If only the new parameter is passed into the function, behave as usual.
    If only the old parameter is passed into the function (as a keyword), raise
    a DeprecationWarning if `dep_version` is provided, and behave as usual
    otherwise.
    If both old and new parameters are passed into the function, raise a
    DeprecationWarning if `dep_version` is provided, and raise the appropriate
    TypeError (function got multiple values for argument).