text: # openpoiservice/server/utils/decorators.py
  
  import time
  import logging
  import cProfile
  import functools
  import os
  import sys
  import inspect
  import traceback
  from functools import wraps
  from multiprocessing import Process, Queue
  
  logger = logging.getLogger(__name__)
  
  
  def processify(func):
      """Decorator to run a function as a process.
      Be sure that every argument and the return value
      is *pickable*.
      The created process is joined, so the code does not
      run in parallel."""
  
      def process_func(q, *args, **kwargs):
          try:
              ret = func(*args, **kwargs)
          except Exception:
              ex_type, ex_value, tb = sys.exc_info()
              error = ex_type, ex_value, ''.join(traceback.format_tb(tb))
              ret = None
          else:
              error = None
  
          q.put((ret, error))
  
      # register original function with different name
      # in sys.modules so it is pickable
      process_func.__name__ = func.__name__ + 'processify_func'
      setattr(sys.modules[__name__], process_func.__name__, process_func)
  
      @wraps(func)
      def wrapper(*args, **kwargs):
          q = Queue()
          p = Process(target=process_func, args=[q] + list(args), kwargs=kwargs)
          p.start()
          ret, error = q.get()
  
          if error:
              ex_type, ex_value, tb_str = error
              message = '%s (in subprocess)\n%s' % (ex_value.args, tb_str)
              raise ex_type(message)
  
          return ret
  
      return wrapper
  
  
  def get_size(obj, seen=None):
      """Recursively finds size of objects in bytes"""
      size = sys.getsizeof(obj)
      if seen is None:
          seen = set()
      obj_id = id(obj)
      if obj_id in seen:
          return 0
      # Important mark as seen *before* entering recursion to gracefully handle
      # self-referential objects
      seen.add(obj_id)
      if hasattr(obj, '__dict__'):
          for cls in obj.__class__.__mro__:
              if '__dict__' in cls.__dict__:
                  d = cls.__dict__['__dict__']
                  if inspect.isgetsetdescriptor(d) or inspect.ismemberdescriptor(d):
                      size += get_size(obj.__dict__, seen)
                  break
      if isinstance(obj, dict):
          size += sum((get_size(v, seen) for v in obj.values()))
          size += sum((get_size(k, seen) for k in obj.keys()))
      elif hasattr(obj, '__iter__') and not isinstance(obj, (list, str, bytes, bytearray)):
          size += sum((get_size(i, seen) for i in obj))
      return size
  
  
  def profile(func):
      @functools.wraps(func)
      def wrapper(*args, **kwargs):
          profiler = cProfile.Profile()
          try:
              profiler.enable()
              ret = func(*args, **kwargs)
              profiler.disable()
              return ret
          finally:
              filename = os.path.expanduser(
                  os.path.join(os.getcwd(), func.__name__ + '.pstat')
              )
              profiler.dump_stats(filename)
  
      return wrapper
  
  
  def timeit(method):
      def timed(*args, **kw):
          ts = time.time()
          result = method(*args, **kw)
          te = time.time()
          if 'log_time' in kw:
              name = kw.get('log_name', method.__name__.upper())
              kw['log_time'][name] = int((te - ts) * 1000)
          else:
              logger.info('%r  %2.2f ms' % (method.__name__, (te - ts) * 1000))
          return result
  
      return timed
  