Source code for bsb.reporting

import warnings, base64, io, sys, functools


def wrap_writer(stream, writer):
    @functools.wraps(writer)
    def wrapped(self, *args, **kwargs):
        writer(*args, **kwargs)
        self.flush()

    return wrapped.__get__(stream)


try:
    sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), "wb", 0), write_through=True)
except io.UnsupportedOperation:  # pragma: nocover
    try:
        writers = ["write", "writelines"]
        for w in writers:
            writer = getattr(sys.stdout, w)
            wrapped = wrap_writer(sys.stdout, writer)
            setattr(sys.stdout, w, wrapped)
    except:
        warnings.warn(
            f"Unable to create unbuffered wrapper around `sys.stdout` ({sys.stdout.__class__.__name__})."
        )

_verbosity = 1
_report_file = None


def set_verbosity(v):
    """
    Set the verbosity of the scaffold package.
    """
    global _verbosity
    _verbosity = v


def get_verbosity():
    """
    Return the verbosity of the scaffold package.
    """
    return _verbosity


def set_report_file(v):
    """
    Set a file to which the scaffold package should report instead of stdout.
    """
    global _report_file
    _report_file = v


def get_report_file():
    """
    Return the report file of the scaffold package.
    """
    return _report_file


preamble = chr(240) + chr(80) + chr(85) + chr(248) + chr(228)
preamble_bar = chr(191) * 3


[docs]def report(*message, level=2, ongoing=False, token=None, nodes=None, all_nodes=False): """ Send a message to the appropriate output channel. :param message: Text message to send. :type message: string :param level: Verbosity level of the message. :type level: int :param ongoing: The message is part of an ongoing progress report. This replaces the endline (`\\n`) character with a carriage return (`\\r`) character """ message = " ".join(map(str, message)) if ( (is_mpi_master and nodes is None) or all_nodes or (nodes is not None and MPI_rank in nodes) ) and _verbosity >= level: if _report_file: with open(_report_file, "a") as f: f.write(_encode(token or "", message)) else: print(message, end="\n" if not ongoing else "\r", flush=True)
[docs]def warn(message, category=None): """ Send a warning. :param message: Warning message :type message: str :param category: The class of the warning. """ if _verbosity > 0: if _report_file: with open(_report_file, "a") as f: f.write(_encode(str(category or "warning"), message)) else: warnings.warn(message, category, stacklevel=2)
def _encode(header, message): header = base64.b64encode(bytes(header, "UTF-8")).decode("UTF-8") message = base64.b64encode(bytes(message, "UTF-8")).decode("UTF-8") return preamble + header + preamble_bar + message + preamble # Initialize MPI when this module is loaded, so that communications work even before # any scaffold is created. try: try: import nest except: pass from mpi4py import MPI as _MPI MPI_rank = _MPI.COMM_WORLD.rank has_mpi_installed = True is_mpi_master = MPI_rank == 0 is_mpi_slave = MPI_rank != 0 except ImportError: has_mpi_installed = False is_mpi_master = True is_mpi_slave = False report("Reporting module initialised.", level=4)