Source code for e3fp.util

"""Utility classes/methods.

Author: Seth Axen
E-mail: seth.axen@gmail.com
"""
import inspect
import warnings


[docs]class E3FPError(Exception): """Base class for E3FP-specific errors. This class is provided for future E3FP-specific functionality. """
[docs]class E3FPWarning(Warning): """Base E3FP warning class. Unlike normal warnings, these are by default always set to on. """
# Always show custom warnings for this package warnings.filterwarnings("always", category=E3FPWarning)
[docs]class E3FPDeprecationWarning(E3FPWarning, DeprecationWarning): """A warning class for a deprecated method or class."""
[docs]class E3FPEfficiencyWarning(E3FPWarning, RuntimeWarning): """A warning class for a potentially inefficient process."""
[docs]def maybe_jit(*args, **kwargs): """Decorator to jit a function using Numba if available. Usage is identical to `numba.jit`. """ def wrapper(func): try: import numba has_numba = True except ImportError: has_numba = False if has_numba: return numba.jit(*args, **kwargs)(func) else: return func return wrapper
[docs]class deprecated(object): """Decorator to mark a function as deprecated. Issue a deprecation warning when a function is called, and update the documentation. A deprecation version must be provided. Examples -------- >>> from e3fp.util import deprecated >>> @deprecated("1.1", remove_version="1.3", ... msg="Function no longer needed") ... def my_function(): ... pass Notes ----- Adapted from https://wiki.python.org/moin/PythonDecoratorLibrary """ def __init__(self, deprecated_version, remove_version=None, msg=None): """Constructor. Parameters ---------- deprecated_version : str Version in which object was deprecated (e.g. '1.1') remove_version : str, optional Version in which object will be removed (e.g. '1.2'). If not specified, it is assumed the object will be removed in the next release (e.g. '1.2' if `deprecated_version` is '1.1') msg : str, optional Message to include with deprecation warning, to explain deprecation or point to newer version. """ self.deprecated_version = deprecated_version if remove_version is None: version_info = deprecated_version.split(".") version_info[1] = str(int(version_info[1]) + 1) for i in range(2, len(version_info)): version_info[i] = "0" remove_version = ".".join(version_info) self.remove_version = remove_version if msg is None: self.extra = "" else: self.extra = " {0}".format(msg) def __call__(self, obj): if inspect.isfunction(obj): return self.deprecate_function(obj) else: raise ValueError("Deprecated object is not a function.")
[docs] def deprecate_function(self, f): """Return the decorated function.""" msg = ( "Function `{0}` was deprecated in {1} and will be removed " "in {2}.{3}" ).format( f.__name__, self.deprecated_version, self.remove_version, self.extra, ) def new_func(*args, **kwargs): warnings.warn(msg, category=E3FPDeprecationWarning, stacklevel=2) return f(*args, **kwargs) new_func.__name__ = f.__name__ new_func.__dict__ = f.__dict__ new_func.__doc__ = f.__doc__ self.update_docstring(new_func) return new_func
[docs] def update_docstring(self, obj): """Add deprecation note to docstring.""" msg = ( ".. note:: Deprecated in e3fp {0}.\n" " `{1}` will be removed in e3fp {2}.{3}" ).format( self.deprecated_version, obj.__name__, self.remove_version, self.extra, ) obj.__doc__ = "{0}\n\n{1}".format(msg, obj.__doc__) return obj