Module control.messages

Expand source code Browse git
import sys
from control.flask import appStop, flashMsg


class Messages:
    def __init__(self, Settings, onFlask=True):
        """Sending messages to the user and the server log.

        This class is instantiated by a singleton object.

        It has methods to issue messages to the screen of the webuser
        and to the log for the sysadmin.

        They distinguish themselves by the *severity*:
        **debug**, **info**, **warning**, **error**.
        There is also **plain**, a leaner variant of **info**.

        All those methods have two optional parameters:
        `logmsg` and `msg`.

        The behaviors of these methods are described in detail in
        the `Messages.message()` function.

        !!! hint "What to disclose?"
            You can pass both parameters, which gives you the opportunity
            to make a sensible distinction between what you tell the
            web user (not much) and what you send to the log (the gory details).

        Parameters
        ----------
        Settings: AttrDict
            App-wide configuration data obtained from
            `control.config.Config.Settings`.
        """
        self.Settings = Settings
        self.onFlask = False
        """Whether the webserver is running.

        If False, mo messages will be sent to the screen of the webuser,
        instead those messages end up in the log.
        This is useful in the initial processing that takes place
        before the flask app is started.
        """

    def setFlask(self):
        """Enables messaging to the web interface."""
        self.onFlask = True

    def debugAdd(self, dest):
        """Adds a quick debug method to a destination object.

        The result of this method is that instead of saying

        ```
        self.Messages.debug (logmsg="blabla")
        ```

        you can say

        ```
        self.debug ("blabla")
        ```

        It is recommended that in each object where you store a handle
        to Messages, you issue the statement

        ```
        Messages.addDebug(self)
        ```
        """

        def dbg(m):
            """Inner function to be set as method to the class."""
            self.debug(logmsg=m)

        setattr(dest, "debug", dbg)

    def debug(self, msg=None, logmsg=None):
        """Issue a debug message.

        See `Messages.message()`
        """
        self.message("debug", msg, logmsg)

    def error(self, msg=None, logmsg=None, stop=True):
        """Issue an error message.

        See `Messages.message()`
        """
        self.message("error", msg, logmsg, stop=stop)

    def warning(self, msg=None, logmsg=None):
        """Issue a warning message.

        See `Messages.message()`
        """
        self.message("warning", msg, logmsg)

    def good(self, msg=None, logmsg=None):
        """Issue a success message.

        See `Messages.message()`
        """
        self.message("good", msg, logmsg)

    def info(self, msg=None, logmsg=None):
        """Issue a informational message.

        See `Messages.message()`
        """
        self.message("info", msg, logmsg)

    def special(self, msg=None, logmsg=None):
        """Issue an emphasised informational message.

        See `Messages.message()`
        """
        self.message("special", msg, logmsg)

    def plain(self, msg=None, logmsg=None):
        """Issue a informational message, without bells and whistles.

        See `Messages.message()`
        """
        self.message("plain", msg, logmsg)

    def message(self, tp, msg, logmsg, stop=True):
        """Workhorse to issue a message in a variety of ways.

        It can issue log messages and screen messages.

        Messages passed in `msg` go to the web interface, the ones
        passed in `logmsg` go to the log.

        If there is not yet a web interface, `msg` messages are suppressed if there
        is also a `logmsg`, otherwise they will be directed to the log as well.

        Parameters
        ----------
        tp: string
            The severity of the message.
            There is a fixed number of types:

            * `debug`
              Messages are prepended with `DEBUG: `.
              Log messages go to stderr.
              Messages will only show up on the web page
              if the app runs in debug mode.

            * `plain`
              Messages are not prepended with anything.
              Log messages go to standard output.

            * `info`
              Messages are prepended with `INFO: `.
              Log messages go to standard output.

            * `warning`
              Messages are prepended with `WARNING: `.
              Log messages go to standard error.

            * `error`
              Messages are prepended with `ERROR: `.
              Log messages go to standard error.
              It also raises an exception, which will lead
              to a 404 response (if flask is running, that is).
              But this stopping can be prevented by passing
              `stop=False`.

        msg: string | void
            If not None, it is the contents of a screen message.
            This happens by the built-in `flash` method of Flask.
        logmsg: string | void
            If not None, it is the contents of a log message.
        stop: boolean, optional True
            If False, an error message will not lead to a stop.

        """
        Settings = self.Settings
        onFlask = self.onFlask

        stream = sys.stderr if tp in {"debug", "error", "warning"} else sys.stdout
        label = "" if tp == "plain" else f"{tp.upper()}: "

        if not onFlask:
            if msg is not None and logmsg is None:
                stream.write(f"{label}{msg}\n")
            if logmsg is not None:
                stream.write(f"{label}{logmsg}\n")
            stream.flush()
        else:
            debugMode = Settings.debugMode
            H = Settings.H

            if tp == "debug" and not debugMode:
                return

            if msg is not None:
                cls = "info" if tp == "plain" else tp
                m = H.he(msg)
                flashMsg(f"{label}{m}", cls)
            if logmsg is not None:
                stream.write(f"{label}{logmsg}\n")
                stream.flush()

            if tp == "error" and onFlask and stop:
                appStop()

    def client(self, tp, message, replace=False):
        """Adds javascript code whose execution displays a message.

        Parameters
        ----------
        tp, msg: string, string
            As in `message()`
        replace: boolean, optional False
            If True, clears all previous messages.

        Returns
        -------
        dict
            an onclick attribute that can be added to a link element.
        """
        replace = "true" if replace else "false"
        return dict(onclick=f"addMsg('{tp}', '{message}', {replace});")

Classes

class Messages (Settings, onFlask=True)

Sending messages to the user and the server log.

This class is instantiated by a singleton object.

It has methods to issue messages to the screen of the webuser and to the log for the sysadmin.

They distinguish themselves by the severity: debug, info, warning, error. There is also plain, a leaner variant of info.

All those methods have two optional parameters: logmsg and msg.

The behaviors of these methods are described in detail in the Messages.message() function.

What to disclose?

You can pass both parameters, which gives you the opportunity to make a sensible distinction between what you tell the web user (not much) and what you send to the log (the gory details).

Parameters

Settings : AttrDict
App-wide configuration data obtained from Config.Settings.
Expand source code Browse git
class Messages:
    def __init__(self, Settings, onFlask=True):
        """Sending messages to the user and the server log.

        This class is instantiated by a singleton object.

        It has methods to issue messages to the screen of the webuser
        and to the log for the sysadmin.

        They distinguish themselves by the *severity*:
        **debug**, **info**, **warning**, **error**.
        There is also **plain**, a leaner variant of **info**.

        All those methods have two optional parameters:
        `logmsg` and `msg`.

        The behaviors of these methods are described in detail in
        the `Messages.message()` function.

        !!! hint "What to disclose?"
            You can pass both parameters, which gives you the opportunity
            to make a sensible distinction between what you tell the
            web user (not much) and what you send to the log (the gory details).

        Parameters
        ----------
        Settings: AttrDict
            App-wide configuration data obtained from
            `control.config.Config.Settings`.
        """
        self.Settings = Settings
        self.onFlask = False
        """Whether the webserver is running.

        If False, mo messages will be sent to the screen of the webuser,
        instead those messages end up in the log.
        This is useful in the initial processing that takes place
        before the flask app is started.
        """

    def setFlask(self):
        """Enables messaging to the web interface."""
        self.onFlask = True

    def debugAdd(self, dest):
        """Adds a quick debug method to a destination object.

        The result of this method is that instead of saying

        ```
        self.Messages.debug (logmsg="blabla")
        ```

        you can say

        ```
        self.debug ("blabla")
        ```

        It is recommended that in each object where you store a handle
        to Messages, you issue the statement

        ```
        Messages.addDebug(self)
        ```
        """

        def dbg(m):
            """Inner function to be set as method to the class."""
            self.debug(logmsg=m)

        setattr(dest, "debug", dbg)

    def debug(self, msg=None, logmsg=None):
        """Issue a debug message.

        See `Messages.message()`
        """
        self.message("debug", msg, logmsg)

    def error(self, msg=None, logmsg=None, stop=True):
        """Issue an error message.

        See `Messages.message()`
        """
        self.message("error", msg, logmsg, stop=stop)

    def warning(self, msg=None, logmsg=None):
        """Issue a warning message.

        See `Messages.message()`
        """
        self.message("warning", msg, logmsg)

    def good(self, msg=None, logmsg=None):
        """Issue a success message.

        See `Messages.message()`
        """
        self.message("good", msg, logmsg)

    def info(self, msg=None, logmsg=None):
        """Issue a informational message.

        See `Messages.message()`
        """
        self.message("info", msg, logmsg)

    def special(self, msg=None, logmsg=None):
        """Issue an emphasised informational message.

        See `Messages.message()`
        """
        self.message("special", msg, logmsg)

    def plain(self, msg=None, logmsg=None):
        """Issue a informational message, without bells and whistles.

        See `Messages.message()`
        """
        self.message("plain", msg, logmsg)

    def message(self, tp, msg, logmsg, stop=True):
        """Workhorse to issue a message in a variety of ways.

        It can issue log messages and screen messages.

        Messages passed in `msg` go to the web interface, the ones
        passed in `logmsg` go to the log.

        If there is not yet a web interface, `msg` messages are suppressed if there
        is also a `logmsg`, otherwise they will be directed to the log as well.

        Parameters
        ----------
        tp: string
            The severity of the message.
            There is a fixed number of types:

            * `debug`
              Messages are prepended with `DEBUG: `.
              Log messages go to stderr.
              Messages will only show up on the web page
              if the app runs in debug mode.

            * `plain`
              Messages are not prepended with anything.
              Log messages go to standard output.

            * `info`
              Messages are prepended with `INFO: `.
              Log messages go to standard output.

            * `warning`
              Messages are prepended with `WARNING: `.
              Log messages go to standard error.

            * `error`
              Messages are prepended with `ERROR: `.
              Log messages go to standard error.
              It also raises an exception, which will lead
              to a 404 response (if flask is running, that is).
              But this stopping can be prevented by passing
              `stop=False`.

        msg: string | void
            If not None, it is the contents of a screen message.
            This happens by the built-in `flash` method of Flask.
        logmsg: string | void
            If not None, it is the contents of a log message.
        stop: boolean, optional True
            If False, an error message will not lead to a stop.

        """
        Settings = self.Settings
        onFlask = self.onFlask

        stream = sys.stderr if tp in {"debug", "error", "warning"} else sys.stdout
        label = "" if tp == "plain" else f"{tp.upper()}: "

        if not onFlask:
            if msg is not None and logmsg is None:
                stream.write(f"{label}{msg}\n")
            if logmsg is not None:
                stream.write(f"{label}{logmsg}\n")
            stream.flush()
        else:
            debugMode = Settings.debugMode
            H = Settings.H

            if tp == "debug" and not debugMode:
                return

            if msg is not None:
                cls = "info" if tp == "plain" else tp
                m = H.he(msg)
                flashMsg(f"{label}{m}", cls)
            if logmsg is not None:
                stream.write(f"{label}{logmsg}\n")
                stream.flush()

            if tp == "error" and onFlask and stop:
                appStop()

    def client(self, tp, message, replace=False):
        """Adds javascript code whose execution displays a message.

        Parameters
        ----------
        tp, msg: string, string
            As in `message()`
        replace: boolean, optional False
            If True, clears all previous messages.

        Returns
        -------
        dict
            an onclick attribute that can be added to a link element.
        """
        replace = "true" if replace else "false"
        return dict(onclick=f"addMsg('{tp}', '{message}', {replace});")

Instance variables

var onFlask

Whether the webserver is running.

If False, mo messages will be sent to the screen of the webuser, instead those messages end up in the log. This is useful in the initial processing that takes place before the flask app is started.

Methods

def client(self, tp, message, replace=False)

Adds javascript code whose execution displays a message.

Parameters

tp, msg : string, string
As in message()
replace : boolean, optional False
If True, clears all previous messages.

Returns

dict
an onclick attribute that can be added to a link element.
Expand source code Browse git
def client(self, tp, message, replace=False):
    """Adds javascript code whose execution displays a message.

    Parameters
    ----------
    tp, msg: string, string
        As in `message()`
    replace: boolean, optional False
        If True, clears all previous messages.

    Returns
    -------
    dict
        an onclick attribute that can be added to a link element.
    """
    replace = "true" if replace else "false"
    return dict(onclick=f"addMsg('{tp}', '{message}', {replace});")
def debug(self, msg=None, logmsg=None)

Issue a debug message.

See Messages.message()

Expand source code Browse git
def debug(self, msg=None, logmsg=None):
    """Issue a debug message.

    See `Messages.message()`
    """
    self.message("debug", msg, logmsg)
def debugAdd(self, dest)

Adds a quick debug method to a destination object.

The result of this method is that instead of saying

self.Messages.debug (logmsg="blabla")

you can say

self.debug ("blabla")

It is recommended that in each object where you store a handle to Messages, you issue the statement

Messages.addDebug(self)
Expand source code Browse git
def debugAdd(self, dest):
    """Adds a quick debug method to a destination object.

    The result of this method is that instead of saying

    ```
    self.Messages.debug (logmsg="blabla")
    ```

    you can say

    ```
    self.debug ("blabla")
    ```

    It is recommended that in each object where you store a handle
    to Messages, you issue the statement

    ```
    Messages.addDebug(self)
    ```
    """

    def dbg(m):
        """Inner function to be set as method to the class."""
        self.debug(logmsg=m)

    setattr(dest, "debug", dbg)
def error(self, msg=None, logmsg=None, stop=True)

Issue an error message.

See Messages.message()

Expand source code Browse git
def error(self, msg=None, logmsg=None, stop=True):
    """Issue an error message.

    See `Messages.message()`
    """
    self.message("error", msg, logmsg, stop=stop)
def good(self, msg=None, logmsg=None)

Issue a success message.

See Messages.message()

Expand source code Browse git
def good(self, msg=None, logmsg=None):
    """Issue a success message.

    See `Messages.message()`
    """
    self.message("good", msg, logmsg)
def info(self, msg=None, logmsg=None)

Issue a informational message.

See Messages.message()

Expand source code Browse git
def info(self, msg=None, logmsg=None):
    """Issue a informational message.

    See `Messages.message()`
    """
    self.message("info", msg, logmsg)
def message(self, tp, msg, logmsg, stop=True)

Workhorse to issue a message in a variety of ways.

It can issue log messages and screen messages.

Messages passed in msg go to the web interface, the ones passed in logmsg go to the log.

If there is not yet a web interface, msg messages are suppressed if there is also a logmsg, otherwise they will be directed to the log as well.

Parameters

tp : string

The severity of the message. There is a fixed number of types:

  • debug Messages are prepended with DEBUG:. Log messages go to stderr. Messages will only show up on the web page if the app runs in debug mode.

  • plain Messages are not prepended with anything. Log messages go to standard output.

  • info Messages are prepended with INFO:. Log messages go to standard output.

  • warning Messages are prepended with WARNING:. Log messages go to standard error.

  • error Messages are prepended with ERROR:. Log messages go to standard error. It also raises an exception, which will lead to a 404 response (if flask is running, that is). But this stopping can be prevented by passing stop=False.

msg : string | void
If not None, it is the contents of a screen message. This happens by the built-in flash method of Flask.
logmsg : string | void
If not None, it is the contents of a log message.
stop : boolean, optional True
If False, an error message will not lead to a stop.
Expand source code Browse git
def message(self, tp, msg, logmsg, stop=True):
    """Workhorse to issue a message in a variety of ways.

    It can issue log messages and screen messages.

    Messages passed in `msg` go to the web interface, the ones
    passed in `logmsg` go to the log.

    If there is not yet a web interface, `msg` messages are suppressed if there
    is also a `logmsg`, otherwise they will be directed to the log as well.

    Parameters
    ----------
    tp: string
        The severity of the message.
        There is a fixed number of types:

        * `debug`
          Messages are prepended with `DEBUG: `.
          Log messages go to stderr.
          Messages will only show up on the web page
          if the app runs in debug mode.

        * `plain`
          Messages are not prepended with anything.
          Log messages go to standard output.

        * `info`
          Messages are prepended with `INFO: `.
          Log messages go to standard output.

        * `warning`
          Messages are prepended with `WARNING: `.
          Log messages go to standard error.

        * `error`
          Messages are prepended with `ERROR: `.
          Log messages go to standard error.
          It also raises an exception, which will lead
          to a 404 response (if flask is running, that is).
          But this stopping can be prevented by passing
          `stop=False`.

    msg: string | void
        If not None, it is the contents of a screen message.
        This happens by the built-in `flash` method of Flask.
    logmsg: string | void
        If not None, it is the contents of a log message.
    stop: boolean, optional True
        If False, an error message will not lead to a stop.

    """
    Settings = self.Settings
    onFlask = self.onFlask

    stream = sys.stderr if tp in {"debug", "error", "warning"} else sys.stdout
    label = "" if tp == "plain" else f"{tp.upper()}: "

    if not onFlask:
        if msg is not None and logmsg is None:
            stream.write(f"{label}{msg}\n")
        if logmsg is not None:
            stream.write(f"{label}{logmsg}\n")
        stream.flush()
    else:
        debugMode = Settings.debugMode
        H = Settings.H

        if tp == "debug" and not debugMode:
            return

        if msg is not None:
            cls = "info" if tp == "plain" else tp
            m = H.he(msg)
            flashMsg(f"{label}{m}", cls)
        if logmsg is not None:
            stream.write(f"{label}{logmsg}\n")
            stream.flush()

        if tp == "error" and onFlask and stop:
            appStop()
def plain(self, msg=None, logmsg=None)

Issue a informational message, without bells and whistles.

See Messages.message()

Expand source code Browse git
def plain(self, msg=None, logmsg=None):
    """Issue a informational message, without bells and whistles.

    See `Messages.message()`
    """
    self.message("plain", msg, logmsg)
def setFlask(self)

Enables messaging to the web interface.

Expand source code Browse git
def setFlask(self):
    """Enables messaging to the web interface."""
    self.onFlask = True
def special(self, msg=None, logmsg=None)

Issue an emphasised informational message.

See Messages.message()

Expand source code Browse git
def special(self, msg=None, logmsg=None):
    """Issue an emphasised informational message.

    See `Messages.message()`
    """
    self.message("special", msg, logmsg)
def warning(self, msg=None, logmsg=None)

Issue a warning message.

See Messages.message()

Expand source code Browse git
def warning(self, msg=None, logmsg=None):
    """Issue a warning message.

    See `Messages.message()`
    """
    self.message("warning", msg, logmsg)