4 Some useful decorators. 
    7 from typing 
import Any, Callable
 
   13 log = logging.getLogger(__name__)
 
   15 TFunc = Callable[..., Any]
 
   19         exc_info = sys.exc_info()
 
   20     _exc_class, _exc, tb = exc_info
 
   21     raise new_exc.__class__ (new_exc, tb)
 
   26     This decorator implements the forking patterns, i.e. it runs the function 
   29      http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/511474 
   31     @functools.wraps(func)
 
   32     def wrapper(*args, **kwargs):
 
   37         pread, pwrite = os.pipe()
 
   45             with os.fdopen(pread, 
'rb') 
as f:
 
   46                 status, result = pickle.load(f)
 
   51                 remote_exc = result[0]
 
   58                 result = func(*args, **kwargs)
 
   60             except (Exception, KeyboardInterrupt) 
as exc:
 
   62                 exc_string = traceback.format_exc(limit=10)
 
   63                 for l 
in exc_string.splitlines():
 
   64                     print (
"[%d]"%os.getpid(),l.rstrip())
 
   66                 result = exc, exc_string
 
   68             with os.fdopen(pwrite, 
'wb') 
as f:
 
   70                     pickle.dump((status,result), f, pickle.HIGHEST_PROTOCOL)
 
   71                 except pickle.PicklingError 
as exc:
 
   72                     pickle.dump((2,exc), f, pickle.HIGHEST_PROTOCOL)
 
   80     reason: str, *, warn_once_per_call: bool = 
True, print_context: bool = 
False 
   81 ) -> Callable[[TFunc], TFunc]:
 
   82     """Decorator to indicate that a function should not be used 
   87         A string explaining why the function should not be used 
   88     warn_once_per_call : bool 
   89         If True, only warn once per call location, default True 
   91         If True, print the calling context as part of the warning, default False 
   95     warncache: set[tuple[int, str, int]] = 
set()
 
   97     def deprecate_decorator(f):
 
   99         def call_deprecated(*args, **kwargs):
 
  100             """Call a deprecated function""" 
  104             frame_info = inspect.stack()[1]
 
  105             cache_value = 
id(f), frame_info.filename, frame_info.lineno
 
  106             if not warn_once_per_call 
or cache_value 
not in warncache:
 
  107                 if warn_once_per_call:
 
  108                     warncache.add(cache_value)
 
  109                 log.warning(f
"Calling deprecated function '{f.__qualname__}'")
 
  111                     f
"in function {frame_info.function}, file {frame_info.filename}, line {frame_info.lineno}" 
  114                     for idx, line 
in enumerate(frame_info.code_context):
 
  115                         log.warning(f
"{frame_info.lineno + idx - frame_info.index}\t{line}")
 
  117             return f(*args, **kwargs)
 
  118         return call_deprecated
 
  119     return deprecate_decorator