Source code for athena.atStatus

from __future__ import annotations

import abc
import numbers
from dataclasses import dataclass, field
from typing import Type, Optional, Any, Tuple, Sequence

from athena import atExceptions


_ALL_STATUS = {}
"""Store all Status that have been created to keep track of them and allow finding lowest/highest"""


[docs]class Status(abc.ABC): """Base `Status` class from which status inherit From. A Status represent the result state of an Athena's :class:`~Process`, it allows to categorise and prioritise it's state using the :attr:`~Status.level`. A status also have a :attr:`~Status.color` assigned that may be used in a user interface to display the result to the users. Important: Every subclass of status must be `frozen` and `ordered` dataclass so that comparison operator will be implemented to sort the different statuses. """ # name: str = field(compare=False) """The name of the Status, mostly used to differentiate multiple statuses of the same type. Not used in comparison.""" # color: Tuple[numbers.Number, numbers.Number, numbers.Number] = field(compare=False) """The color that represent the status, to differentiate multiple statuses in a UI for instance. Not used in comparison""" # level: float = float('nan') """ The level for the status, it must be a float greater than or equal to zero, `inf` or `nan` but those should be reserved for special use case. """ def __init__(self, name, color, level): self._name = name self._color = color self._level = level global _ALL_STATUS _ALL_STATUS.setdefault(self.__class__, set()).add(self) def __repr__(self) -> str: """Human readable representation of the Status object. Return: A string representation of the Status including it's class, name and level. The color is represented as an rgb and therefore not expressive enough to be included. """ return '<{}: {} ({})>'.format(self.__class__.__name__, self._name, self._level) def __eq__(self, other): if not isinstance(other, Status): raise TypeError('\'{}\' objects can only be compared to other \'{}\' objects.'.format(self.__class__.__name__)) return self._level == other._level def __gt__(self, other): if not isinstance(other, Status): raise TypeError('\'{}\' objects can only be compared to other \'{}\' objects.'.format(self.__class__.__name__)) return self._level > other._level def __lt__(self, other): if not isinstance(other, Status): raise TypeError('\'{}\' objects can only be compared to other \'{}\' objects.'.format(self.__class__.__name__)) return self._level < other._level def __hash__(self): return hash((self._name, self._color, self._level)) @property def name(self): return self._name @property def color(self): return self._color @property def level(self): return self._level
[docs]class FailStatus(Status): """Represent a Fail Status, can be instantiated to define a new Failure level Notes: :class:`~FailStatus` should use level values greater than 0, the higher the value is, the more critical the Status is. """ ...
[docs]class SuccessStatus(Status): """Represent a Success Status, can be instantiated to define a new Success level Notes: :class:`~SuccessStatus` should use level values lower than 0, the lower the value is, the less critical the Status is. """ ...
[docs]class _BuiltInStatus(Status): """Represent a Built-In Status, can be instantiated to define a new Built-In level Creating new built-in Status must be reserved for framework level behavior, developers must work with other Status types. Built-in Status usually represent special case and have special behavior recognized by the framework itself or third-party UI/Extensions. Notes: :class:`~_BuiltInStatus` instances should use special level, `0.0` is common and totally fine for a "default" kind of built-in Status, on the other hand, built-in statuses that represent an exception may benefit from something like `nan`. At the end, for :class:`~_BuiltInStatus` the level is less important as it's mostly used to sort Status and built-in are handle differently as they are "specials" by nature. """ ...
_DEFAULT: _BuiltInStatus = _BuiltInStatus('Default', (60, 60, 60), 0.0) """Default Status, it is set as base status for all :class:`.Process`""" _SKIPPED: _BuiltInStatus = _BuiltInStatus('Skipped', (85, 85, 85), float('nan')) """Represent the state of a :class:`~Process` for which execution has been skipped.""" SUCCESS: SuccessStatus = SuccessStatus('Success', (0, 128, 0), -float('inf')) """Base success status, represent the classic state of a successful :class:`~Process` execution.""" CORRECT: SuccessStatus = SuccessStatus('Correct', (22, 194, 15), -1.0) """Represent a "good enough" :class:`~Process` execution. Still successful but not optimal.""" WARNING: FailStatus = FailStatus('Warning', (196, 98, 16), 1.0) """Represent a lightly fail status, that are usually not too problematic as is but that may require attention.""" ERROR: FailStatus = FailStatus('Error', (150, 0, 0), float('inf')) """Base fail status, represent the classic state of a failed :class:`~Process` execution.""" _ABORTED: _BuiltInStatus = _BuiltInStatus('Aborted', (100, 100, 100), float('nan')) """Status to represent the state of a :class:`~Process` that has been aborted by user.""" _EXCEPTION: _BuiltInStatus = _BuiltInStatus('Exception', (125, 125, 125), float('nan')) """Status for a Process which encountered an Exception and was interupted."""
[docs]def get_all_statuses() -> Tuple[Status, ...]: """Return all existing Status in a list. Return: All instance of Status subclass defined. Contains the built-in one (defined in this module) as well as user defined Success subclass. """ return tuple(status for status_type_list in _ALL_STATUS.values() for status in status_type_list)
[docs]def get_status_by_name(name: str) -> Optional[Status]: """Find Status instance based on it's name. Parameters: name: The name of the status to find. Return: The status that match the name if any, else None. """ for status in get_all_statuses(): if status.name == name: return status else: return None
[docs]def get_all_fail_status() -> Tuple[FailStatus, ...]: """Get all Fail Status instances. Return: All Fail Statuses instances. """ return tuple(_ALL_STATUS[FailStatus])
[docs]def get_all_success_status() -> Tuple[SuccessStatus, ...]: """Get all Success Status instances. Return: All Success Statuses instances. """ return tuple(_ALL_STATUS[SuccessStatus])
[docs]def lowest_fail_status() -> FailStatus: """Get the lowest Fail Status instance based on Status.level. Return: The Fail Status with the lowest level. """ return sorted(get_all_fail_status(), key=lambda x: x.level)[0]
[docs]def highest_fail_status() -> FailStatus: """Get the highest Fail Status instance based on Status.level. Return: The Fail Status with the highest level. """ return sorted(get_all_fail_status(), key=lambda x: x.level)[-1]
[docs]def lowest_success_status() -> SuccessStatus: """Get the lowest Success Status instance based on Status.level. Return: The Success Status with the lowest level. """ return sorted(get_all_success_status(), key=lambda x: x.level)[0]
[docs]def highest_success_status() -> SuccessStatus: """Get the highest Success Status instance based on Status.level. Return: The Success Status with the highest level. """ return sorted(get_all_success_status(), key=lambda x: x.level)[-1]