Source code for vdat.command_interpreter.relay

"""Except for the logging mechanism, the :class:`.CommandInterpreter` uses
relays-like objects to communicate with the external word. This module defines
a few classes with an ``emit`` method, that mimic `PyQt signals
<http://pyqt.sourceforge.net/Docs/PyQt4/new_style_signals_slots.html>`_

The names of the ``emit`` method arguments are the type of the parameter
followed by an underscore and optionally by an explanatory name.

Available relays:

* ``command_string``: accept an int and a string

  .. automethod:: _CommandString.emit
      :noindex:

* ``progress``: accept three numbers, the total expected number, the number of
  successes and of failures;

  .. automethod:: _Progress.emit
      :noindex:

* ``logger``: accept a two strings

  .. automethod:: _Logger.emit
      :noindex:
"""
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import logging
import sys

__all__ = ['override_emit']

relays = {}


def register(name):
    """Initialise the decorated class and save it into the ``relays``
    dictionary with ``name`` as key

    Parameters
    ----------
    name : string
        name under which the class or instance must be registered

    Returns
    -------
    decorator : function
        class decorator
    """
    def decorator(cls):
        "save the class into the ``_registered`` dictionary"
        relays[name] = cls()
        return cls
    return decorator


@register("command_string")
class _CommandString(object):
    """Receive the string of the command to execute after substituting the
    keywords"""

[docs] def emit(self, int_, string_): """Default implementation: print the ``string_`` for when ``int_ == 0``""" if int_ == 0: print(string_)
@register("progress") class _Progress(object): """Receive total number of jobs and the number successful and failed ones"""
[docs] def emit(self, int_tot, int_done, int_fail): """Default implementation: Print the percentages of finished, successful and failed jobs, overwriting the line""" line = "Progress: {0:.0%}, success: {1:.0%}, failures: {2:.0%}" line = line.format(int_done / int_tot, (int_done - int_fail) / int_tot, int_fail / int_tot) sys.stdout.write("\r\x1b[K" + line) sys.stdout.flush()
@register("logger") class _Logger(object): """Receive the level of severity of the message and a string to print. """
[docs] def emit(self, int_level, string_msg): """Default implementation: print ``int_level: string_msg`` The ``int_level`` values are chosen to be the standard `logging levels <https://docs.python.org/2/library/logging.html#logging-levels>`_ and are converted to strings accordingly The idea behind this relay is to bind it to the main logger if needed. We decided not to do this directly as we don't know the name of the logger. We implement it in this way to have a more coherent interface. """ print(logging.getLevelName(int_level) + ": " + string_msg)
def get_relay(name): """Get the relay associated with ``name`` Parameters ---------- name : string name of the requested relay Returns ------- one of the relay instances defined in this module and registered into the ``relays`` dictionary """ return relays[name]
[docs]def override_emit(name, new_emit): """Replace the emit method in the relay instance called ``name`` with ``new_emit``. The original class is not modified. Parameters ---------- name : string name of the relay new_emit : callable function to use to replace the default ``emit`` method. This function must have at least one argument, ``self`` and it's signature must match the original one to avoid errors at runtime """ import types relays[name].emit = types.MethodType(new_emit, relays[name])