Source code for snowdrop.src.utils.decorators

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 13 09:52:57 2021

@author: Alexei Goumilevski
"""

import warnings
import functools
import time

[docs] def debug(func): """Print the function signature and return value.""" @functools.wraps(func) def wrapper_debug(*args, **kwargs): args_repr = [repr(a) for a in args] # 1 kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()] # 2 signature = ", ".join(args_repr + kwargs_repr) # 3 print(f"Calling {func.__name__}({signature})") value = func(*args, **kwargs) print(f"{func.__name__!r} returned {value!r}") # 4 return value return wrapper_debug
[docs] def timer(func): """Print the runtime of the decorated function.""" @functools.wraps(func) def wrapper_timer(*args, **kwargs): start_time = time.perf_counter() # 1 value = func(*args, **kwargs) end_time = time.perf_counter() # 2 run_time = end_time - start_time # 3 print(f"Finished {func.__name__!r} in {run_time:.1f} secs") return value return wrapper_timer
[docs] def repeat(_func=None, *args, num_times=2): """Repeat decorator. If name has been called without arguments, the decorated function will be passed in as _func. If it has been called with arguments, then _func will be None, and some of the keyword arguments may have been changed from their default values. The * in the argument list means that the remaining arguments can’t be called as positional arguments. Parameters: _func : function object, optional Repeats function executions. The default is None. args : Arguments Function arguments. num_times : int, optional Number of times to reprat fuction calls. The default is 2. Returns: decorator_repeat function """ def decorator_repeat(func): @functools.wraps(func) def wrapper_repeat(*args, **kwargs): for _ in range(num_times): value = func(*args, **kwargs) return value return wrapper_repeat if _func is None: return decorator_repeat else: return decorator_repeat(_func)
[docs] def count_calls(func): """Decorator that counts the number of times a function is called.""" @functools.wraps(func) def wrapper_count_calls(*args, **kwargs): wrapper_count_calls.num_calls += 1 print(f"Call {wrapper_count_calls.num_calls} of {func.__name__!r}") return func(*args, **kwargs) wrapper_count_calls.num_calls = 0 return wrapper_count_calls
[docs] def singleton(cls): """Make a class a Singleton class (only one instance).""" @functools.wraps(cls) def wrapper_singleton(*args, **kwargs): if not wrapper_singleton.instance: wrapper_singleton.instance = cls(*args, **kwargs) return wrapper_singleton.instance wrapper_singleton.instance = None return wrapper_singleton
[docs] def cache(func): """Keep a cache of previous function calls.""" @functools.wraps(func) def wrapper_cache(*args, **kwargs): cache_key = args + tuple(kwargs.items()) if cache_key not in wrapper_cache.cache: wrapper_cache.cache[cache_key] = func(*args, **kwargs) return wrapper_cache.cache[cache_key] wrapper_cache.cache = dict() return wrapper_cache
[docs] def deprecated(func): """This is a decorator which can be used to mark functions as deprecated.""" @functools.wraps(func) def new_func(*args, **kwargs): code = func.__code__ warnings.warn_explicit( "Call to deprecated function {}.".format(func.__name__), category=Warning, filename=code.co_filename, lineno=code.co_firstlineno + 1, ) return func(*args, **kwargs) return new_func