"""Actions module."""
import logging
from collections import OrderedDict
from typing import Hashable, List
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
[docs]class Actions:
"""Class to keep track and log a set of actions performed and their result with a nice string representation."""
def __init__(self, name: Hashable):
"""Initialize the instance.
When converted to string returns a nicely formatted representation of the instance and all its actions.
It exposes the following properties:
- ``name``: the name passed to the instance at instantiation time.
- ``has_warnings``: a :py:class:`bool` that is :py:data:`True` when at least one warning action was registered,
:py:data:`False` otherwise.
- ``has_failures``: a :py:class:`bool` that is :py:data:`True` when at least one failed action was registered,
:py:data:`False` otherwise.
Arguments:
name (typing.Hashable): the name of the set of actions to be registered.
"""
self.name = name
self.actions = [] # type: List[str]
self.has_warnings = False
self.has_failures = False
def __str__(self) -> str:
"""Custom string representation of the actions performed.
Returns:
str: the string representation.
"""
actions = '\n'.join(' - {action}'.format(action=action) for action in self.actions)
return '{name} (**{status}**)\n{actions}'.format(name=self.name, status=self.status, actions=actions)
@property
def status(self) -> str:
"""Return the current status of the actions based on the worst result recorded.
Returns:
str: the short string representation of the status, one of: ``PASS``, ``WARN``, ``FAIL``.
"""
if self.has_failures:
return 'FAIL'
if self.has_warnings:
return 'WARN'
return 'PASS'
[docs] def success(self, message: str) -> None:
"""Register a successful action.
Arguments:
message (str): the action description.
"""
self._action(logging.INFO, message)
[docs] def failure(self, message: str) -> None:
"""Register a failed action.
Arguments:
message (str): the action description.
"""
self._action(logging.ERROR, message)
self.has_failures = True
[docs] def warning(self, message: str) -> None:
"""Register an action that require some attention.
Arguments:
message (str): the action description.
"""
self._action(logging.WARNING, message)
self.has_warnings = True
def _action(self, level: int, message: str) -> None:
"""Register a generic action.
Arguments:
level (int): a logging level integer to register the action for.
message (str): the action description.
"""
logger.log(level, message)
self.actions.append(message)
[docs]class ActionsDict(OrderedDict):
"""OrderedDict with defaultdict capabilities for the :py:class:`spicerack.actions.Action` class.
Inherits from :py:class:`collections.OrderedDict` and automatically instantiate and returns a new instance of the
:py:class:`spicerack.actions.Actions` class for every missing key like a :py:class:`collections.defaultdict`.
When accessing a missing key, the key itself is passed to the new :py:class:`spicerack.actions.Actions` instance
as ``name``.
When converted to string returns a nicely formatted representation of the instance and all its items.
Todo:
Once the support of Python 3.5 is dropped this can be converted into a simple factory with a single ``new()``
method that returns an instance of ``defaultdict(Actions)``.
"""
def __missing__(self, key: Hashable) -> Actions:
"""Instantiate a new Actions instance for the missing key like a defaultdict.
Parameters as required by Python's data model, see :py:method:`object.__missing__`.
"""
self[key] = Actions(key)
return self[key]
def __str__(self) -> str:
"""Custom string representation of the instance.
Returns:
str: the string representation.
"""
return '\n'.join('- {actions}\n'.format(actions=value) for key, value in self.items())