Source code for bluecellulab.utils

"""Utility functions used within BlueCellulab."""

from __future__ import annotations
import contextlib
import io
import json
import multiprocessing
from multiprocessing import pool

import numpy as np


[docs] def run_once(func): """A decorator to ensure a function is only called once.""" def wrapper(*args, **kwargs): if not wrapper.has_run: wrapper.has_run = True return func(*args, **kwargs) wrapper.has_run = False return wrapper
[docs] class CaptureOutput(list): def __enter__(self): self._stringio = io.StringIO() self._redirect_stdout = contextlib.redirect_stdout(self._stringio) self._redirect_stdout.__enter__() return self def __exit__(self, exc_type, exc_val, exc_tb): self._redirect_stdout.__exit__(exc_type, exc_val, exc_tb) self.extend(self._stringio.getvalue().splitlines())
[docs] class NumpyEncoder(json.JSONEncoder):
[docs] def default(self, obj): if isinstance( obj, ( np.int_, np.intc, np.intp, np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64, ), ): return int(obj) elif isinstance(obj, (np.float64, np.float16, np.float32, np.float64)): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() return json.JSONEncoder.default(self, obj)
[docs] class NoDaemonProcess(multiprocessing.Process): """Class that represents a non-daemon process.""" # pylint: disable=dangerous-default-value def __init__(self, group=None, target=None, name=None, args=(), kwargs={}): """Ensures group=None, for macosx.""" super().__init__(group=None, target=target, name=name, args=args, kwargs=kwargs) @property def daemon(self): return False @daemon.setter def daemon(self, val): pass
[docs] class NestedPool(pool.Pool): # pylint: disable=abstract-method """Class that represents a MultiProcessing nested pool.""" Process = NoDaemonProcess